-- |
-- Module:     Control.Wire.Prefab.Calculus
-- Copyright:  (c) 2011 Ertugrul Soeylemez
-- License:    BSD3
-- Maintainer: Ertugrul Soeylemez <es@ertes.de>
--
-- Wires for calculus over time.

module Control.Wire.Prefab.Calculus
    ( -- * Integration
      integral,

      -- * Differentiation
      derivative
    )
    where

import Control.Wire.Trans.Clock
import Control.Wire.Types
import Data.VectorSpace


-- | Integrate over time.
--
-- * Depends: Current instant.

integral ::
    forall e t v (>~).
    (VectorSpace v, WirePure (>~), WWithDT t (>~), Scalar v ~ t)
    => v -> Wire e (>~) v v
integral = withDT . integral'
    where
    integral' :: v -> Wire e (>~) (v, t) v
    integral' x0 =
        mkPure $ \(dx, dt) ->
            let x1 = x0 ^+^ (dx ^* dt)
            in x0 `seq` (Right x0, integral' x1)


-- | Calculates the derivative of the input signal over time.
--
-- * Depends: Current instant.

derivative ::
    forall e t v (>~).
    (Fractional t, VectorSpace v, WirePure (>~), WWithDT t (>~), Scalar v ~ t)
    => Wire e (>~) v v
derivative = mkPure $ \x0 -> (Right zeroV, withDT (deriv' x0))
    where
    deriv' :: v -> Wire e (>~) (v, t) v
    deriv' x0 =
        mkPure $ \(x1, dt) ->
            let dx = (x1 ^-^ x0) ^/ dt
            in x0 `seq` (Right dx, deriv' x1)