{-|
Copyright   : Written by David Himmelstrup
License     : Unlicense
Maintainer  : lemmih@gmail.com
Stability   : experimental
Portability : POSIX
-}
module Reanimate.Transition
  ( Transition
  , signalT
  , mapT
  , overlapT
  , chainT
  , effectT
  , fadeT
  ) where

import           Reanimate.Animation (Animation, dropA, duration, lastA, parA, pause, seqA, signalA,
                                      takeA)
import           Reanimate.Ease      (Signal)
import           Reanimate.Effect    (Effect, applyE, fadeInE, fadeOutE)

-- | A transition transforms one animation into another.
type Transition = Animation -> Animation -> Animation

-- | Apply a signal to the timing of a transition.
signalT :: Signal -> Transition -> Transition
signalT = mapT . signalA

-- | Map the result of a transition.
mapT :: (Animation -> Animation) -> Transition -> Transition
mapT fn t a b = fn (t a b)

-- | Apply transition only to @N@ seconds of the first
--   animation and to the last @N@ seconds of the second animation.
--
--   Example:
--
-- @
-- 'overlapT' 0.5 'fadeT' 'Reanimate.Builtin.Documentation.drawBox' 'Reanimate.Builtin.Documentation.drawCircle'
-- @
--
--   <<docs/gifs/doc_overlapT.gif>>
overlapT :: Double -> Transition -> Transition
overlapT overlap t a b =
    aBefore `seqA` t aOverlap bOverlap `seqA` bAfter
  where
    aBefore  = takeA (duration a - overlap) a
    aOverlap = lastA overlap a
    bOverlap = takeA overlap b
    bAfter   = dropA overlap b


-- | Create a transition between two animations by applying an effect to each respective animation.
effectT :: Effect -- ^ Effect to be applied to the first animation.
        -> Effect -- ^ Effect to be applied to the second animation.
        -> Transition
effectT eA eB a b = applyE eA a `parA` applyE eB b

-- | Combine a list of animations using a given transition.
--
--   Example:
--
-- @
-- 'chainT' ('overlapT' 0.5 'fadeT') ['Reanimate.Builtin.Documentation.drawBox', 'Reanimate.Builtin.Documentation.drawCircle', 'Reanimate.Builtin.Documentation.drawProgress']
-- @
--
--   <<docs/gifs/doc_chainT.gif>>
chainT :: Transition -> [Animation] -> Animation
chainT _ []     = pause 0
chainT t (x:xs) = foldl t x xs

-- | Fade out left-hand-side animation while fading in right-hand-side animation.
--
--   Example:
--
-- @
-- 'Reanimate.Builtin.Documentation.drawBox' `'fadeT'` 'Reanimate.Builtin.Documentation.drawCircle'
-- @
--
--   <<docs/gifs/doc_fadeT.gif>>
fadeT :: Transition
fadeT = effectT fadeOutE fadeInE