-- |
-- Module:     Control.Wire.Prefab.Sample
-- Copyright:  (c) 2012 Ertugrul Soeylemez
-- License:    BSD3
-- Maintainer: Ertugrul Soeylemez <es@ertes.de>
--
-- Signal sampling wires.

module Control.Wire.Prefab.Sample
    ( -- * Sampling
      --history,
      keep,
      sample,
      window,
      windowList
    )
    where

import qualified Data.Foldable as F
import qualified Data.Sequence as Seq
import Control.Wire.Wire
import Data.Sequence (Seq, (|>))


-- | Produce the most recent inputs in the given time window.  The left
-- input signal is the sample, the right input signal is the time
-- window.
--
-- * Complexity: O(n), where n the number of samples in the time window.
--
-- * Depends: current instant.

--history :: (Reactive cat) => Wire e cat (a, Time) (Seq (a, Time))
--history = undefined


-- | Keep the input signal of the first instant forever.
--
-- Depends: first instant.

keep :: Wire e m a a
keep = mkPure (\_ x -> (Right x, constant x))


-- | Sample the left signal at discrete intervals given by the right
-- signal.
--
-- * Depends: instant of the last sample.

sample :: Wire e m (a, Time) a
sample = mkPure $ \dt (x, _) -> (Right x, sample' dt x)
    where
    sample' t0' x' =
        mkPure $ \dt (x, t1) ->
            let t0 = t0' + dt in
            if t0 >= t1
              then (Right x, sample' (t0 - t1) x)
              else (Right x', sample' t0 x')


-- | Produce up to the given number of most recent inputs.
--
-- * Complexity: O(n), where n is the given argument.
--
-- * Depends: current instant.

window :: Int -> Wire e m a (Seq a)
window = collect' Seq.empty
    where
    collect' s' 0 = window' s'
    collect' s' n =
        mkPure $ \_ x ->
            let s = s' |> x in
            s `seq` (Right s, collect' s (n - 1))

    window' s' =
        mkPure $ \_ x ->
            let s = Seq.drop 1 (s' |> x) in
            s `seq` (Right s, window' s)


-- | Same as @fmap toList . window@.

windowList :: (Monad m) => Int -> Wire e m a [a]
windowList = fmap F.toList . window