module Session.Timing.Math
  ( nextExpires
  , isExpired
  ) where

import Internal.Prelude

import Session.Timing.Time
import Session.Timing.Timeout
import Time

-- | Calculate the next point in time where the given session
--   will expire assuming that it sees no activity until then
--
--  Returns 'Nothing' if and only if the settings do not specify any timeout
--  limits.
nextExpires
  :: Timeout NominalDiffTime
  -> Time UTCTime
  -- ^ A session's timing information
  -> Maybe UTCTime
nextExpires :: Timeout NominalDiffTime -> Time UTCTime -> Maybe UTCTime
nextExpires Timeout NominalDiffTime
timeout Time UTCTime
time =
  ((NonEmpty UTCTime -> UTCTime)
-> Maybe (NonEmpty UTCTime) -> Maybe UTCTime
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap NonEmpty UTCTime -> UTCTime
forall a. Ord a => NonEmpty a -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum (Maybe (NonEmpty UTCTime) -> Maybe UTCTime)
-> ([Maybe UTCTime] -> Maybe (NonEmpty UTCTime))
-> [Maybe UTCTime]
-> Maybe UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [UTCTime] -> Maybe (NonEmpty UTCTime)
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty ([UTCTime] -> Maybe (NonEmpty UTCTime))
-> ([Maybe UTCTime] -> [UTCTime])
-> [Maybe UTCTime]
-> Maybe (NonEmpty UTCTime)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe UTCTime] -> [UTCTime]
forall a. [Maybe a] -> [a]
catMaybes)
    [ (NominalDiffTime -> UTCTime -> UTCTime)
-> UTCTime -> NominalDiffTime -> UTCTime
forall a b c. (a -> b -> c) -> b -> a -> c
flip NominalDiffTime -> UTCTime -> UTCTime
addUTCTime Time UTCTime
time.accessed (NominalDiffTime -> UTCTime)
-> Maybe NominalDiffTime -> Maybe UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Timeout NominalDiffTime
timeout.idle
    , (NominalDiffTime -> UTCTime -> UTCTime)
-> UTCTime -> NominalDiffTime -> UTCTime
forall a b c. (a -> b -> c) -> b -> a -> c
flip NominalDiffTime -> UTCTime -> UTCTime
addUTCTime Time UTCTime
time.created (NominalDiffTime -> UTCTime)
-> Maybe NominalDiffTime -> Maybe UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Timeout NominalDiffTime
timeout.absolute
    ]

-- | Check if a session has expired
isExpired
  :: Timeout NominalDiffTime
  -- ^ Settings
  -> UTCTime
  -- ^ Now
  -> Time UTCTime
  -- ^ A session's timing information
  -> Bool
isExpired :: Timeout NominalDiffTime -> UTCTime -> Time UTCTime -> Bool
isExpired Timeout NominalDiffTime
timeout UTCTime
now Time UTCTime
time =
  Bool -> (UTCTime -> Bool) -> Maybe UTCTime -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (UTCTime -> UTCTime -> Bool
forall a. Ord a => a -> a -> Bool
<= UTCTime
now) (Maybe UTCTime -> Bool) -> Maybe UTCTime -> Bool
forall a b. (a -> b) -> a -> b
$ Timeout NominalDiffTime -> Time UTCTime -> Maybe UTCTime
nextExpires Timeout NominalDiffTime
timeout Time UTCTime
time