module Hackage.Security.TUF.Header (
    HasHeader(..)
  , FileVersion(..)
  , FileExpires(..)
  , Header(..)
    
  , expiresInDays
  , expiresNever
  , isExpired
  , versionInitial
  , versionIncrement
  ) where
import Data.Time
import Data.Typeable (Typeable)
import Hackage.Security.JSON
import Hackage.Security.Util.Lens
class HasHeader a where
  
  fileExpires :: Lens' a FileExpires
  
  fileVersion :: Lens' a FileVersion
newtype FileVersion = FileVersion Int54
  deriving (Eq, Ord, Typeable)
instance Show FileVersion where
  show (FileVersion v) = show v
instance Read FileVersion where
  readsPrec p = map (\(v, xs) -> (FileVersion v, xs)) . readsPrec p
newtype FileExpires = FileExpires (Maybe UTCTime)
  deriving (Eq, Ord, Show, Typeable)
data Header = Header {
    headerExpires :: FileExpires
  , headerVersion :: FileVersion
  }
instance HasHeader Header where
  fileExpires f x = (\y -> x { headerExpires = y }) <$> f (headerExpires x)
  fileVersion f x = (\y -> x { headerVersion = y }) <$> f (headerVersion x)
expiresNever :: FileExpires
expiresNever = FileExpires Nothing
expiresInDays :: UTCTime -> Integer -> FileExpires
expiresInDays now n =
    FileExpires . Just $ addUTCTime (fromInteger n * oneDay) now
isExpired :: UTCTime -> FileExpires -> Bool
isExpired _   (FileExpires Nothing)  = False
isExpired now (FileExpires (Just e)) = e < now
versionInitial :: FileVersion
versionInitial = FileVersion 1
versionIncrement :: FileVersion -> FileVersion
versionIncrement (FileVersion i) = FileVersion (i + 1)
instance Monad m => ToJSON m FileVersion where
  toJSON (FileVersion i) = toJSON i
instance Monad m => ToJSON m FileExpires where
  toJSON (FileExpires (Just e)) = toJSON e
  toJSON (FileExpires Nothing)  = return JSNull
instance ReportSchemaErrors m => FromJSON m FileVersion where
  fromJSON enc = FileVersion <$> fromJSON enc
instance ReportSchemaErrors m => FromJSON m FileExpires where
  fromJSON JSNull = return $ FileExpires Nothing
  fromJSON enc    = FileExpires . Just <$> fromJSON enc
instance ReportSchemaErrors m => FromJSON m Header where
  fromJSON enc = do
    headerExpires <- fromJSField enc "expires"
    headerVersion <- fromJSField enc "version"
    return Header{..}
oneDay :: NominalDiffTime
oneDay = 24 * 60 * 60