module Data.HodaTime.Duration.Internal
(
   Duration(..)
  ,normalize
  ,fromSeconds
)
where

import Data.HodaTime.Instant.Internal (Instant(..))
import Control.Arrow ((>>>), (***), first)
import Data.HodaTime.Constants (secondsPerDay)

-- | Represents a duration of time between instants.  It can be from days to nanoseconds,
--   but anything longer is not representable by a duration because e.g. Months are calendar
--   specific concepts.
newtype Duration = Duration { getInstant :: Instant }
    deriving (Eq, Show)             -- TODO: Remove Show

normalize :: Int -> Int -> (Int, Int)
normalize x size
    | x >= size = pos x
    | x < 0 = neg x
    | otherwise = (0, x)
    where
        split = flip divMod size
        pos = split >>> first fromIntegral
        neg = negArrow . abs
        negAdjust = fromIntegral . negate . succ *** (+ size) . negate
        negArrow x' = let (b,s) = split x' in
          if s == 0 then (negate b,s)     -- In the case that x' splits exactly we don't need to adjust further
          else negAdjust (b,s)

-- | Duration of seconds
fromSeconds :: Int -> Duration
fromSeconds s = Duration $ Instant (fromIntegral d) (fromIntegral s') 0
    where
        (d, s') = normalize s secondsPerDay