-- |
-- Module     : Simulation.Aivika.Statistics.Accumulator
-- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.1
--
-- This small utility module allows accumulating the timing statistics based on 'Signalable' data
-- such as the queue size or the number of lost items in the queue.
--

module Simulation.Aivika.Statistics.Accumulator
       (-- * Timing Statistics Accumulator
        TimingStatsAccumulator,
        newTimingStatsAccumulator,
        timingStatsAccumulated) where

import Simulation.Aivika.Simulation
import Simulation.Aivika.Dynamics
import Simulation.Aivika.Event
import Simulation.Aivika.Ref
import Simulation.Aivika.Statistics
import Simulation.Aivika.Signal

-- | Represents an accumulator for the timing statistics.
newtype TimingStatsAccumulator a =
  TimingStatsAccumulator { forall a. TimingStatsAccumulator a -> Ref (TimingStats a)
timingStatsAccumulatedRef :: Ref (TimingStats a) }

-- | Return the accumulated statistics.
timingStatsAccumulated :: TimingStatsAccumulator a -> Event (TimingStats a)
timingStatsAccumulated :: forall a. TimingStatsAccumulator a -> Event (TimingStats a)
timingStatsAccumulated = Ref (TimingStats a) -> Event (TimingStats a)
forall a. Ref a -> Event a
readRef (Ref (TimingStats a) -> Event (TimingStats a))
-> (TimingStatsAccumulator a -> Ref (TimingStats a))
-> TimingStatsAccumulator a
-> Event (TimingStats a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimingStatsAccumulator a -> Ref (TimingStats a)
forall a. TimingStatsAccumulator a -> Ref (TimingStats a)
timingStatsAccumulatedRef

-- | Start gathering the timing statistics from the current simulation time. 
newTimingStatsAccumulator :: TimingData a => Signalable a -> Event (TimingStatsAccumulator a)
newTimingStatsAccumulator :: forall a.
TimingData a =>
Signalable a -> Event (TimingStatsAccumulator a)
newTimingStatsAccumulator Signalable a
x =
  do Double
t0 <- Dynamics Double -> Event Double
forall a. Dynamics a -> Event a
forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
     a
a0 <- Signalable a -> Event a
forall a. Signalable a -> Event a
readSignalable Signalable a
x
     Ref (TimingStats a)
r  <- Simulation (Ref (TimingStats a)) -> Event (Ref (TimingStats a))
forall a. Simulation a -> Event a
forall (m :: * -> *) a. SimulationLift m => Simulation a -> m a
liftSimulation (Simulation (Ref (TimingStats a)) -> Event (Ref (TimingStats a)))
-> Simulation (Ref (TimingStats a)) -> Event (Ref (TimingStats a))
forall a b. (a -> b) -> a -> b
$ TimingStats a -> Simulation (Ref (TimingStats a))
forall a. a -> Simulation (Ref a)
newRef (Double -> a -> TimingStats a
forall a. TimingData a => Double -> a -> TimingStats a
returnTimingStats Double
t0 a
a0)
     Signal a -> (a -> Event ()) -> Event ()
forall a. Signal a -> (a -> Event ()) -> Event ()
handleSignal_ (Signalable a -> Signal a
forall a. Signalable a -> Signal a
signalableChanged Signalable a
x) ((a -> Event ()) -> Event ()) -> (a -> Event ()) -> Event ()
forall a b. (a -> b) -> a -> b
$ \a
a ->
       do Double
t <- Dynamics Double -> Event Double
forall a. Dynamics a -> Event a
forall (m :: * -> *) a. DynamicsLift m => Dynamics a -> m a
liftDynamics Dynamics Double
time
          Ref (TimingStats a) -> (TimingStats a -> TimingStats a) -> Event ()
forall a. Ref a -> (a -> a) -> Event ()
modifyRef Ref (TimingStats a)
r ((TimingStats a -> TimingStats a) -> Event ())
-> (TimingStats a -> TimingStats a) -> Event ()
forall a b. (a -> b) -> a -> b
$ Double -> a -> TimingStats a -> TimingStats a
forall a.
TimingData a =>
Double -> a -> TimingStats a -> TimingStats a
addTimingStats Double
t a
a
     TimingStatsAccumulator a -> Event (TimingStatsAccumulator a)
forall a. a -> Event a
forall (m :: * -> *) a. Monad m => a -> m a
return TimingStatsAccumulator { timingStatsAccumulatedRef :: Ref (TimingStats a)
timingStatsAccumulatedRef = Ref (TimingStats a)
r }