{-# LANGUAGE DeriveGeneric, DeriveLift, NumDecimals #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  NgxExport.Tools.TimeInterval
-- Copyright   :  (c) Alexey Radkov 2018-2022
-- License     :  BSD-style
--
-- Maintainer  :  alexey.radkov@gmail.com
-- Stability   :  stable
-- Portability :  portable
--
-----------------------------------------------------------------------------


module NgxExport.Tools.TimeInterval (
    -- * A simple implementation of time intervals
    -- $description

    -- * Exported data and functions
                                     TimeInterval (..)
                                    ,toSec
                                    ,threadDelaySec
                                    ) where

import           Language.Haskell.TH.Syntax
import           Data.Aeson.Types
import           Data.Function (on)
import           Data.Ord (comparing)
import           Control.Concurrent
import           GHC.Generics

-- $description
--
-- A simple implementation of time intervals supposed for describing low
-- resolution timeouts.

-- | Time intervals.
--
-- Note that /Unset/ is a zero time interval which is equal to 0 seconds,
-- however it is expected to be used differently. In particular, to explicitly
-- express an intention to unset the timeout.
data TimeInterval = Hr Int          -- ^ Hours
                  | Min Int         -- ^ Minutes
                  | Sec Int         -- ^ Seconds
                  | HrMin Int Int   -- ^ Hours and minutes
                  | MinSec Int Int  -- ^ Minutes and seconds
                  | Unset           -- ^ Zero time interval
                  deriving ((forall x. TimeInterval -> Rep TimeInterval x)
-> (forall x. Rep TimeInterval x -> TimeInterval)
-> Generic TimeInterval
forall x. Rep TimeInterval x -> TimeInterval
forall x. TimeInterval -> Rep TimeInterval x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. TimeInterval -> Rep TimeInterval x
from :: forall x. TimeInterval -> Rep TimeInterval x
$cto :: forall x. Rep TimeInterval x -> TimeInterval
to :: forall x. Rep TimeInterval x -> TimeInterval
Generic, (forall (m :: * -> *). Quote m => TimeInterval -> m Exp)
-> (forall (m :: * -> *).
    Quote m =>
    TimeInterval -> Code m TimeInterval)
-> Lift TimeInterval
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => TimeInterval -> m Exp
forall (m :: * -> *).
Quote m =>
TimeInterval -> Code m TimeInterval
$clift :: forall (m :: * -> *). Quote m => TimeInterval -> m Exp
lift :: forall (m :: * -> *). Quote m => TimeInterval -> m Exp
$cliftTyped :: forall (m :: * -> *).
Quote m =>
TimeInterval -> Code m TimeInterval
liftTyped :: forall (m :: * -> *).
Quote m =>
TimeInterval -> Code m TimeInterval
Lift, ReadPrec [TimeInterval]
ReadPrec TimeInterval
Int -> ReadS TimeInterval
ReadS [TimeInterval]
(Int -> ReadS TimeInterval)
-> ReadS [TimeInterval]
-> ReadPrec TimeInterval
-> ReadPrec [TimeInterval]
-> Read TimeInterval
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS TimeInterval
readsPrec :: Int -> ReadS TimeInterval
$creadList :: ReadS [TimeInterval]
readList :: ReadS [TimeInterval]
$creadPrec :: ReadPrec TimeInterval
readPrec :: ReadPrec TimeInterval
$creadListPrec :: ReadPrec [TimeInterval]
readListPrec :: ReadPrec [TimeInterval]
Read, Int -> TimeInterval -> ShowS
[TimeInterval] -> ShowS
TimeInterval -> String
(Int -> TimeInterval -> ShowS)
-> (TimeInterval -> String)
-> ([TimeInterval] -> ShowS)
-> Show TimeInterval
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TimeInterval -> ShowS
showsPrec :: Int -> TimeInterval -> ShowS
$cshow :: TimeInterval -> String
show :: TimeInterval -> String
$cshowList :: [TimeInterval] -> ShowS
showList :: [TimeInterval] -> ShowS
Show)

instance FromJSON TimeInterval

instance Eq TimeInterval where
    == :: TimeInterval -> TimeInterval -> Bool
(==) = Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
(==) (Int -> Int -> Bool)
-> (TimeInterval -> Int) -> TimeInterval -> TimeInterval -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` TimeInterval -> Int
toSec

instance Ord TimeInterval where
    compare :: TimeInterval -> TimeInterval -> Ordering
compare = (TimeInterval -> Int) -> TimeInterval -> TimeInterval -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing TimeInterval -> Int
toSec

-- | Converts a time interval into seconds.
toSec :: TimeInterval -> Int
toSec :: TimeInterval -> Int
toSec (Hr Int
h)       = Int
3600 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
h
toSec (Min Int
m)      = Int
60 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
m
toSec (Sec Int
s)      = Int
s
toSec (HrMin Int
h Int
m)  = Int
3600 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
h Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
60 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
m
toSec (MinSec Int
m Int
s) = Int
60 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
m Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
s
toSec TimeInterval
Unset        = Int
0

-- | Delays the current thread by the specified number of seconds.
threadDelaySec :: Int -> IO ()
threadDelaySec :: Int -> IO ()
threadDelaySec = Int -> IO ()
threadDelay (Int -> IO ()) -> (Int -> Int) -> Int -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1e6)