{-|
Module      : Duration
Description : The chosen implementation of duration for reactive tile
Copyright   : (c) David Janin, 2016
License     : see the LICENSE file in the distribution
Maintainer  : janin@labri.fr
Stability   : experimental

There is another choice (see module bundles Duration)

-}

{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}

{-# LANGUAGE MultiParamTypeClasses,
             GeneralizedNewtypeDeriving,
             FlexibleInstances #-}

module Reactive.Duration (Duration, updateOnDelay, updateOnVariable
                         , durationFromID, durationFromConst
                         , isZeroDuration, maybeConstDur,toConstDur,constDur) where

import Duration.MinMaxAffine
import Duration.Lattice


newtype Duration d i = Duration {fromDuration :: (MinMaxAffine d i)} deriving (Show, Ord, Eq, Fractional, Num, POrd,Lattice)


-- | True if duration equals zero, false otherwise
isZeroDuration :: (Num d, POrd d) => d -> Bool
isZeroDuration d = case (partialCompare 0 d) of
                     Just EQ -> True
                     _ -> False

-- | Replaces every unknown X by X+d where d is a constant duration.
updateOnDelay :: (Num d, Ord d, Ord i) =>
                             d -> Duration d i -> Duration d i
updateOnDelay d = Duration . updateMinMaxOnDelay d . fromDuration

-- | Replaces every (index) specified unknown X by 0.
updateOnVariable :: (Num d, Ord d, Ord i) =>
                             [i] -> Duration d i -> Duration d i
updateOnVariable l = Duration . updateMinMaxOnVariable l . fromDuration

-- | Creates an unknown duration from a variable index.
durationFromID :: (Num d) => i -> Duration d i                   
durationFromID i =  Duration $ varDur i 
                    
-- | Creates an constant duration from a constant value.
durationFromConst :: (Num d) => d -> Duration d i                   
durationFromConst d  = Duration $ constDur d

-- | Tries to convert a duration into a constant value. Return Nothing when the duration is not constant.
maybeConstDur :: (Num d, Ord d, Ord i) => Duration d i   -> Maybe d
maybeConstDur  =  getConstDurMaybe . fromDuration
                       
-- | Converts a duration into a constant value. Makes an error when the duration is not constant.
toConstDur :: (Num d, Ord d, Ord i) => Duration d i   ->  d
toConstDur d = case getConstDurMaybe $ fromDuration d of
                 Just d -> d
                 Nothing -> 0