module Synthesizer.PiecewiseConstant.Private where

import qualified Synthesizer.Generic.Signal as SigG

import qualified Data.EventList.Relative.BodyTime  as EventListBT
import qualified Data.EventList.Relative.TimeBody  as EventList

import qualified Numeric.NonNegative.Wrapper as NonNegW

import Control.Monad.Trans.State (evalState, get, put, )

import qualified Data.List as List
import Data.Traversable (traverse, )
import Data.Foldable (traverse_, )



type StrictTime = NonNegW.Integer
type ShortStrictTime = NonNegW.Int


{-# INLINE toSignal #-}
toSignal ::
   (SigG.Transform sig y) =>
   (StrictTime -> y -> sig y) ->
   EventListBT.T StrictTime y -> sig y
toSignal replicateLong =
   EventListBT.foldrPair
      (\y t -> SigG.append (replicateLong t y))
      SigG.empty

{-# INLINE toSignalInit #-}
toSignalInit ::
   (SigG.Transform sig y) =>
   (StrictTime -> y -> sig y) ->
   y -> EventList.T StrictTime y -> sig y
toSignalInit replicateLong initial =
   (\ ~(t,rest) -> SigG.append (replicateLong t initial) rest)
   .
   EventList.foldr
      (,)
      (\y ~(t,rest) -> SigG.append (replicateLong t y) rest)
      (0, SigG.empty)
{-
   toSignal .
--   EventListBM.switchBodyR const .
--   EventListBM.snocTime NonNeg.zero .
--   EventListMB.consBody initial .
   -- switchBodyR causes a space leak
   EventListTM.switchBodyR EventListBT.empty
      (\xs _ -> EventListMT.consBody initial xs)
-}

{-# INLINE toSignalInitWith #-}
toSignalInitWith ::
   (SigG.Transform sig c) =>
   (StrictTime -> c -> sig c) ->
   (y -> c) -> c -> EventList.T StrictTime [y] -> sig c
toSignalInitWith replicateLong f initial =
   toSignalInit replicateLong initial .
   flip evalState initial .
   traverse (\evs -> traverse_ (put . f) evs >> get)


{- |
Returns a list of non-zero times.
-}
{-# INLINE chopLongTime #-}
chopLongTime :: StrictTime -> [ShortStrictTime]
chopLongTime n =
   let d = fromIntegral (maxBound :: Int)
       (q,r) = divMod (NonNegW.toNumber n) d
   in  map (NonNegW.fromNumberMsg "chopLongTime" . fromInteger) $
       List.genericReplicate q d ++
       if r/=0 then [r] else []