module Simulation.Aivika.Trans.Gate
       (Gate,
        newGate,
        newGateOpened,
        newGateClosed,
        openGate,
        closeGate,
        gateOpened,
        gateClosed,
        awaitGateOpened,
        awaitGateClosed,
        gateChanged_) where
import Control.Monad
import Simulation.Aivika.Trans.DES
import Simulation.Aivika.Trans.Simulation
import Simulation.Aivika.Trans.Event
import Simulation.Aivika.Trans.Process
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.Ref
data Gate m = Gate { gateRef :: Ref m Bool }
newGate :: MonadDES m => Bool -> Simulation m (Gate m)
newGate opened =
  do r <- newRef opened
     return Gate { gateRef = r }
newGateOpened :: MonadDES m => Simulation m (Gate m)
newGateOpened = newGate True
newGateClosed :: MonadDES m => Simulation m (Gate m)
newGateClosed = newGate False
openGate :: MonadDES m => Gate m -> Event m ()
openGate gate =
  writeRef (gateRef gate) True
closeGate :: MonadDES m => Gate m -> Event m ()
closeGate gate =
  writeRef (gateRef gate) False
gateOpened :: MonadDES m => Gate m -> Event m Bool
gateOpened gate =
  readRef (gateRef gate)
gateClosed :: MonadDES m => Gate m -> Event m Bool
gateClosed gate =
  fmap not $ readRef (gateRef gate)
awaitGateOpened :: MonadDES m => Gate m -> Process m ()
awaitGateOpened gate =
  do f <- liftEvent $ readRef (gateRef gate)
     unless f $
       do processAwait $ refChanged_ (gateRef gate)
          awaitGateOpened gate
awaitGateClosed :: MonadDES m => Gate m -> Process m ()
awaitGateClosed gate =
  do f <- liftEvent $ readRef (gateRef gate)
     when f $
       do processAwait $ refChanged_ (gateRef gate)
          awaitGateClosed gate
gateChanged_ :: MonadDES m => Gate m -> Signal m ()
gateChanged_ gate =
  refChanged_ (gateRef gate)