-- |
-- Module     : Simulation.Aivika.Trans.GPSS.Block.Test
-- Copyright  : Copyright (c) 2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.2
--
-- This module defines the GPSS block TEST.
--
module Simulation.Aivika.Trans.GPSS.Block.Test
       (awaitingTestBlock,
        awaitingTestBlockM,
        transferringTestBlock,
        transferringTestBlockM) where

import Simulation.Aivika.Trans
import Simulation.Aivika.Trans.GPSS.Block

-- | This is the GPSS construct
--
-- @TEST O A,B@
awaitingTestBlock :: MonadDES m
                     => (a -> Signalable m Bool)
                     -- ^ by the specified transact return
                     -- a test condition and signal that notifies
                     -- about changing the condition
                     -> Block m a a
{-# INLINABLE awaitingTestBlock #-}
awaitingTestBlock :: forall (m :: * -> *) a.
MonadDES m =>
(a -> Signalable m Bool) -> Block m a a
awaitingTestBlock a -> Signalable m Bool
f =
  Block { blockProcess :: a -> Process m a
blockProcess = \a
a ->
           do let s :: Signalable m Bool
s = a -> Signalable m Bool
f a
a
                  loop :: Process m ()
loop =
                    do Bool
f <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Signalable m a -> Event m a
readSignalable Signalable m Bool
s
                       if Bool
f
                         then forall (m :: * -> *) a. Monad m => a -> m a
return ()
                         else do forall (m :: * -> *) a. MonadDES m => Signal m a -> Process m a
processAwait forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Signalable m a -> Signal m ()
signalableChanged_ Signalable m Bool
s
                                 Process m ()
loop
              Process m ()
loop
              forall (m :: * -> *) a. Monad m => a -> m a
return a
a
        }

-- | This is the GPSS construct
--
-- @TEST O A,B@
awaitingTestBlockM :: MonadDES m
                      => (a -> Process m (Signalable m Bool))
                      -- ^ by the specified transact return
                      -- a test condition and signal that notifies
                      -- about changing the condition
                      -> Block m a a
{-# INLINABLE awaitingTestBlockM #-}
awaitingTestBlockM :: forall (m :: * -> *) a.
MonadDES m =>
(a -> Process m (Signalable m Bool)) -> Block m a a
awaitingTestBlockM a -> Process m (Signalable m Bool)
f =
  Block { blockProcess :: a -> Process m a
blockProcess = \a
a ->
           do Signalable m Bool
s <- a -> Process m (Signalable m Bool)
f a
a
              let loop :: Process m ()
loop =
                    do Bool
f <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Signalable m a -> Event m a
readSignalable Signalable m Bool
s
                       if Bool
f
                         then forall (m :: * -> *) a. Monad m => a -> m a
return ()
                         else do forall (m :: * -> *) a. MonadDES m => Signal m a -> Process m a
processAwait forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Signalable m a -> Signal m ()
signalableChanged_ Signalable m Bool
s
                                 Process m ()
loop
              Process m ()
loop
              forall (m :: * -> *) a. Monad m => a -> m a
return a
a
        }

-- | This is the GPSS construct
--
-- @TEST O A,B,C@
transferringTestBlock :: MonadDES m
                         => (a -> Bool)
                         -- ^ the predicate
                         -> Block m a ()
                         -- ^ the block to transfer in when the condition fails
                         -> Block m a a
{-# INLINABLE transferringTestBlock #-}
transferringTestBlock :: forall (m :: * -> *) a.
MonadDES m =>
(a -> Bool) -> Block m a () -> Block m a a
transferringTestBlock a -> Bool
pred Block m a ()
block =
  Block { blockProcess :: a -> Process m a
blockProcess = \a
a ->
           do let f :: Bool
f = a -> Bool
pred a
a
              if Bool
f
                then forall (m :: * -> *) a. Monad m => a -> m a
return a
a
                else forall (m :: * -> *) a. MonadDES m => Process m () -> Process m a
transferProcess (forall (m :: * -> *) a b. Block m a b -> a -> Process m b
blockProcess Block m a ()
block a
a)
        }

-- | This is the GPSS construct
--
-- @TEST O A,B,C@
transferringTestBlockM :: MonadDES m
                          => (a -> Process m Bool)
                          -- ^ the predicate
                          -> Block m a ()
                          -- ^ the block to transfer in when the condition fails
                          -> Block m a a
{-# INLINABLE transferringTestBlockM #-}
transferringTestBlockM :: forall (m :: * -> *) a.
MonadDES m =>
(a -> Process m Bool) -> Block m a () -> Block m a a
transferringTestBlockM a -> Process m Bool
pred Block m a ()
block =
  Block { blockProcess :: a -> Process m a
blockProcess = \a
a ->
           do Bool
f <- a -> Process m Bool
pred a
a
              if Bool
f
                then forall (m :: * -> *) a. Monad m => a -> m a
return a
a
                else forall (m :: * -> *) a. MonadDES m => Process m () -> Process m a
transferProcess (forall (m :: * -> *) a b. Block m a b -> a -> Process m b
blockProcess Block m a ()
block a
a)
        }