-----------------------------------------------------------------------------
-- |
-- Module      :  Data.HodaTime.Interval
-- Copyright   :  (C) 2016 Jason Johnson
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Jason Johnson <jason.johnson.081@gmail.com>
-- Stability   :  experimental
-- Portability :  POSIX, Windows
--
-- An 'Interval' is a period of time between two 'Instant's.
----------------------------------------------------------------------------
module Data.HodaTime.Interval
(
  -- * Types
  Interval
  -- * Constructor
  ,interval
  -- * Lenses
  ,start
  ,end
  -- * Functions
  ,contains
  ,duration
)
where

import Data.HodaTime.Instant.Internal (Instant)
import Data.HodaTime.Duration.Internal (Duration)
import Data.HodaTime.Instant (difference)
import Control.DeepSeq (NFData(..))
import Data.Hashable (Hashable(..))

data Interval = Interval Instant Instant
    deriving (Interval -> Interval -> Bool
(Interval -> Interval -> Bool)
-> (Interval -> Interval -> Bool) -> Eq Interval
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Interval -> Interval -> Bool
== :: Interval -> Interval -> Bool
$c/= :: Interval -> Interval -> Bool
/= :: Interval -> Interval -> Bool
Eq, Eq Interval
Eq Interval =>
(Interval -> Interval -> Ordering)
-> (Interval -> Interval -> Bool)
-> (Interval -> Interval -> Bool)
-> (Interval -> Interval -> Bool)
-> (Interval -> Interval -> Bool)
-> (Interval -> Interval -> Interval)
-> (Interval -> Interval -> Interval)
-> Ord Interval
Interval -> Interval -> Bool
Interval -> Interval -> Ordering
Interval -> Interval -> Interval
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
$ccompare :: Interval -> Interval -> Ordering
compare :: Interval -> Interval -> Ordering
$c< :: Interval -> Interval -> Bool
< :: Interval -> Interval -> Bool
$c<= :: Interval -> Interval -> Bool
<= :: Interval -> Interval -> Bool
$c> :: Interval -> Interval -> Bool
> :: Interval -> Interval -> Bool
$c>= :: Interval -> Interval -> Bool
>= :: Interval -> Interval -> Bool
$cmax :: Interval -> Interval -> Interval
max :: Interval -> Interval -> Interval
$cmin :: Interval -> Interval -> Interval
min :: Interval -> Interval -> Interval
Ord)

instance Show Interval where
  showsPrec :: Int -> Interval -> ShowS
showsPrec Int
p (Interval Instant
s Instant
e) = Bool -> ShowS -> ShowS
showParen (Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
    String -> ShowS
showString String
"interval " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Instant -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Instant
s ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' ' ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Instant -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Instant
e

instance NFData Interval where
  rnf :: Interval -> ()
rnf (Interval Instant
s Instant
e) = Instant -> ()
forall a. NFData a => a -> ()
rnf Instant
s () -> () -> ()
forall a b. a -> b -> b
`seq` Instant -> ()
forall a. NFData a => a -> ()
rnf Instant
e

instance Hashable Interval where
  hashWithSalt :: Int -> Interval -> Int
hashWithSalt Int
salt (Interval Instant
s Instant
e) = Int
salt Int -> Instant -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` Instant
s Int -> Instant -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` Instant
e

interval :: Instant -> Instant -> Interval
interval :: Instant -> Instant -> Interval
interval = Instant -> Instant -> Interval
Interval             -- TODO: We probably need some checks here

-- | Lens for the start component of the 'Interval'
start :: Functor f => (Instant -> f Instant) -> Interval -> f Interval
start :: forall (f :: * -> *).
Functor f =>
(Instant -> f Instant) -> Interval -> f Interval
start Instant -> f Instant
f (Interval Instant
s Instant
e) = (Instant -> Instant -> Interval) -> Instant -> Instant -> Interval
forall a b c. (a -> b -> c) -> b -> a -> c
flip Instant -> Instant -> Interval
Interval Instant
e (Instant -> Interval) -> f Instant -> f Interval
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Instant -> f Instant
f Instant
s
{-# INLINE start #-}

-- | Lens for the end component of the 'Interval'
end :: Functor f => (Instant -> f Instant) -> Interval -> f Interval
end :: forall (f :: * -> *).
Functor f =>
(Instant -> f Instant) -> Interval -> f Interval
end Instant -> f Instant
f (Interval Instant
s Instant
e) = Instant -> Instant -> Interval
Interval Instant
s (Instant -> Interval) -> f Instant -> f Interval
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Instant -> f Instant
f Instant
e
{-# INLINE end #-}

-- | Determines if the 'Instant' is between the start and end of the 'Interval'.  The interval includes the start but excludes the end
contains :: Interval -> Instant -> Bool
contains :: Interval -> Instant -> Bool
contains (Interval Instant
s Instant
e) Instant
i = Instant
s Instant -> Instant -> Bool
forall a. Ord a => a -> a -> Bool
<= Instant
i Bool -> Bool -> Bool
&& Instant
e Instant -> Instant -> Bool
forall a. Ord a => a -> a -> Bool
> Instant
i

-- | Get the 'Duration' between the start and the end of the 'Interval'
duration :: Interval -> Duration
duration :: Interval -> Duration
duration (Interval Instant
s Instant
e) = Instant
e Instant -> Instant -> Duration
`difference` Instant
s