{-# LANGUAGE Safe       #-}
{-# LANGUAGE StrictData #-}
module Network.Tox.Time where

import           Control.Applicative       ((<$>), (<*>))
import qualified System.Clock              as Clock
import           Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)

{-------------------------------------------------------------------------------
 -
 - :: Implementation.
 -
 ------------------------------------------------------------------------------}

newtype Timestamp = Timestamp Clock.TimeSpec
  deriving (Timestamp -> Timestamp -> Bool
(Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool) -> Eq Timestamp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Timestamp -> Timestamp -> Bool
$c/= :: Timestamp -> Timestamp -> Bool
== :: Timestamp -> Timestamp -> Bool
$c== :: Timestamp -> Timestamp -> Bool
Eq, Eq Timestamp
Eq Timestamp
-> (Timestamp -> Timestamp -> Ordering)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Timestamp)
-> (Timestamp -> Timestamp -> Timestamp)
-> Ord Timestamp
Timestamp -> Timestamp -> Bool
Timestamp -> Timestamp -> Ordering
Timestamp -> Timestamp -> Timestamp
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Timestamp -> Timestamp -> Timestamp
$cmin :: Timestamp -> Timestamp -> Timestamp
max :: Timestamp -> Timestamp -> Timestamp
$cmax :: Timestamp -> Timestamp -> Timestamp
>= :: Timestamp -> Timestamp -> Bool
$c>= :: Timestamp -> Timestamp -> Bool
> :: Timestamp -> Timestamp -> Bool
$c> :: Timestamp -> Timestamp -> Bool
<= :: Timestamp -> Timestamp -> Bool
$c<= :: Timestamp -> Timestamp -> Bool
< :: Timestamp -> Timestamp -> Bool
$c< :: Timestamp -> Timestamp -> Bool
compare :: Timestamp -> Timestamp -> Ordering
$ccompare :: Timestamp -> Timestamp -> Ordering
$cp1Ord :: Eq Timestamp
Ord, Int -> Timestamp -> ShowS
[Timestamp] -> ShowS
Timestamp -> String
(Int -> Timestamp -> ShowS)
-> (Timestamp -> String)
-> ([Timestamp] -> ShowS)
-> Show Timestamp
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Timestamp] -> ShowS
$cshowList :: [Timestamp] -> ShowS
show :: Timestamp -> String
$cshow :: Timestamp -> String
showsPrec :: Int -> Timestamp -> ShowS
$cshowsPrec :: Int -> Timestamp -> ShowS
Show, ReadPrec [Timestamp]
ReadPrec Timestamp
Int -> ReadS Timestamp
ReadS [Timestamp]
(Int -> ReadS Timestamp)
-> ReadS [Timestamp]
-> ReadPrec Timestamp
-> ReadPrec [Timestamp]
-> Read Timestamp
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Timestamp]
$creadListPrec :: ReadPrec [Timestamp]
readPrec :: ReadPrec Timestamp
$creadPrec :: ReadPrec Timestamp
readList :: ReadS [Timestamp]
$creadList :: ReadS [Timestamp]
readsPrec :: Int -> ReadS Timestamp
$creadsPrec :: Int -> ReadS Timestamp
Read)

newtype TimeDiff = TimeDiff Clock.TimeSpec
  deriving (TimeDiff -> TimeDiff -> Bool
(TimeDiff -> TimeDiff -> Bool)
-> (TimeDiff -> TimeDiff -> Bool) -> Eq TimeDiff
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TimeDiff -> TimeDiff -> Bool
$c/= :: TimeDiff -> TimeDiff -> Bool
== :: TimeDiff -> TimeDiff -> Bool
$c== :: TimeDiff -> TimeDiff -> Bool
Eq, Eq TimeDiff
Eq TimeDiff
-> (TimeDiff -> TimeDiff -> Ordering)
-> (TimeDiff -> TimeDiff -> Bool)
-> (TimeDiff -> TimeDiff -> Bool)
-> (TimeDiff -> TimeDiff -> Bool)
-> (TimeDiff -> TimeDiff -> Bool)
-> (TimeDiff -> TimeDiff -> TimeDiff)
-> (TimeDiff -> TimeDiff -> TimeDiff)
-> Ord TimeDiff
TimeDiff -> TimeDiff -> Bool
TimeDiff -> TimeDiff -> Ordering
TimeDiff -> TimeDiff -> TimeDiff
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: TimeDiff -> TimeDiff -> TimeDiff
$cmin :: TimeDiff -> TimeDiff -> TimeDiff
max :: TimeDiff -> TimeDiff -> TimeDiff
$cmax :: TimeDiff -> TimeDiff -> TimeDiff
>= :: TimeDiff -> TimeDiff -> Bool
$c>= :: TimeDiff -> TimeDiff -> Bool
> :: TimeDiff -> TimeDiff -> Bool
$c> :: TimeDiff -> TimeDiff -> Bool
<= :: TimeDiff -> TimeDiff -> Bool
$c<= :: TimeDiff -> TimeDiff -> Bool
< :: TimeDiff -> TimeDiff -> Bool
$c< :: TimeDiff -> TimeDiff -> Bool
compare :: TimeDiff -> TimeDiff -> Ordering
$ccompare :: TimeDiff -> TimeDiff -> Ordering
$cp1Ord :: Eq TimeDiff
Ord, Int -> TimeDiff -> ShowS
[TimeDiff] -> ShowS
TimeDiff -> String
(Int -> TimeDiff -> ShowS)
-> (TimeDiff -> String) -> ([TimeDiff] -> ShowS) -> Show TimeDiff
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TimeDiff] -> ShowS
$cshowList :: [TimeDiff] -> ShowS
show :: TimeDiff -> String
$cshow :: TimeDiff -> String
showsPrec :: Int -> TimeDiff -> ShowS
$cshowsPrec :: Int -> TimeDiff -> ShowS
Show, ReadPrec [TimeDiff]
ReadPrec TimeDiff
Int -> ReadS TimeDiff
ReadS [TimeDiff]
(Int -> ReadS TimeDiff)
-> ReadS [TimeDiff]
-> ReadPrec TimeDiff
-> ReadPrec [TimeDiff]
-> Read TimeDiff
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [TimeDiff]
$creadListPrec :: ReadPrec [TimeDiff]
readPrec :: ReadPrec TimeDiff
$creadPrec :: ReadPrec TimeDiff
readList :: ReadS [TimeDiff]
$creadList :: ReadS [TimeDiff]
readsPrec :: Int -> ReadS TimeDiff
$creadsPrec :: Int -> ReadS TimeDiff
Read)

instance Num TimeDiff where
  TimeDiff TimeSpec
t + :: TimeDiff -> TimeDiff -> TimeDiff
+ TimeDiff TimeSpec
t' = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ TimeSpec
t TimeSpec -> TimeSpec -> TimeSpec
forall a. Num a => a -> a -> a
Prelude.+ TimeSpec
t'
  TimeDiff TimeSpec
t - :: TimeDiff -> TimeDiff -> TimeDiff
- TimeDiff TimeSpec
t' = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ TimeSpec
t TimeSpec -> TimeSpec -> TimeSpec
forall a. Num a => a -> a -> a
Prelude.- TimeSpec
t'
  TimeDiff TimeSpec
t * :: TimeDiff -> TimeDiff -> TimeDiff
* TimeDiff TimeSpec
t' = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ TimeSpec
t TimeSpec -> TimeSpec -> TimeSpec
forall a. Num a => a -> a -> a
* TimeSpec
t'
  negate :: TimeDiff -> TimeDiff
negate (TimeDiff TimeSpec
t) = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ TimeSpec -> TimeSpec
forall a. Num a => a -> a
negate TimeSpec
t
  abs :: TimeDiff -> TimeDiff
abs (TimeDiff TimeSpec
t) = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ TimeSpec -> TimeSpec
forall a. Num a => a -> a
abs TimeSpec
t
  signum :: TimeDiff -> TimeDiff
signum (TimeDiff TimeSpec
t) = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ TimeSpec -> TimeSpec
forall a. Num a => a -> a
signum TimeSpec
t
  fromInteger :: Integer -> TimeDiff
fromInteger = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff)
-> (Integer -> TimeSpec) -> Integer -> TimeDiff
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> TimeSpec
forall a. Num a => Integer -> a
fromInteger

seconds :: Integer -> TimeDiff
seconds :: Integer -> TimeDiff
seconds Integer
s = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ Int64 -> Int64 -> TimeSpec
Clock.TimeSpec (Integer -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
s) Int64
0

milliseconds :: Integer -> TimeDiff
milliseconds :: Integer -> TimeDiff
milliseconds = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff)
-> (Integer -> TimeSpec) -> Integer -> TimeDiff
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Int64 -> TimeSpec
Clock.TimeSpec Int64
0 (Int64 -> TimeSpec) -> (Integer -> Int64) -> Integer -> TimeSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
*Int64
10Int64 -> Integer -> Int64
forall a b. (Num a, Integral b) => a -> b -> a
^(Integer
6::Integer)) (Int64 -> Int64) -> (Integer -> Int64) -> Integer -> Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral

getTime :: IO Timestamp
getTime :: IO Timestamp
getTime = TimeSpec -> Timestamp
Timestamp (TimeSpec -> Timestamp) -> IO TimeSpec -> IO Timestamp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Clock -> IO TimeSpec
Clock.getTime Clock
Clock.Monotonic

(-) :: Timestamp -> Timestamp -> TimeDiff
Timestamp TimeSpec
t - :: Timestamp -> Timestamp -> TimeDiff
- Timestamp TimeSpec
t' = TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> TimeSpec -> TimeDiff
forall a b. (a -> b) -> a -> b
$ TimeSpec
t TimeSpec -> TimeSpec -> TimeSpec
forall a. Num a => a -> a -> a
Prelude.- TimeSpec
t'

(+) :: Timestamp -> TimeDiff -> Timestamp
Timestamp TimeSpec
t + :: Timestamp -> TimeDiff -> Timestamp
+ TimeDiff TimeSpec
t' = TimeSpec -> Timestamp
Timestamp (TimeSpec -> Timestamp) -> TimeSpec -> Timestamp
forall a b. (a -> b) -> a -> b
$ TimeSpec
t TimeSpec -> TimeSpec -> TimeSpec
forall a. Num a => a -> a -> a
Prelude.+ TimeSpec
t'

{-------------------------------------------------------------------------------
 -
 - :: Tests.
 -
 ------------------------------------------------------------------------------}

instance Arbitrary Timestamp
  where arbitrary :: Gen Timestamp
arbitrary = (TimeSpec -> Timestamp
Timestamp (TimeSpec -> Timestamp) -> Gen TimeSpec -> Gen Timestamp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Gen TimeSpec -> Gen Timestamp) -> Gen TimeSpec -> Gen Timestamp
forall a b. (a -> b) -> a -> b
$ Int64 -> Int64 -> TimeSpec
Clock.TimeSpec (Int64 -> Int64 -> TimeSpec)
-> Gen Int64 -> Gen (Int64 -> TimeSpec)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Int64
forall a. Arbitrary a => Gen a
arbitrary Gen (Int64 -> TimeSpec) -> Gen Int64 -> Gen TimeSpec
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Int64
forall a. Arbitrary a => Gen a
arbitrary

instance Arbitrary TimeDiff
  where arbitrary :: Gen TimeDiff
arbitrary = (TimeSpec -> TimeDiff
TimeDiff (TimeSpec -> TimeDiff) -> Gen TimeSpec -> Gen TimeDiff
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Gen TimeSpec -> Gen TimeDiff) -> Gen TimeSpec -> Gen TimeDiff
forall a b. (a -> b) -> a -> b
$ Int64 -> Int64 -> TimeSpec
Clock.TimeSpec (Int64 -> Int64 -> TimeSpec)
-> Gen Int64 -> Gen (Int64 -> TimeSpec)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Int64
forall a. Arbitrary a => Gen a
arbitrary Gen (Int64 -> TimeSpec) -> Gen Int64 -> Gen TimeSpec
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Int64
forall a. Arbitrary a => Gen a
arbitrary