content: 
  -- Example: A Truck Hauling Situation
  --
  -- It is described in different sources [1, 2]. So, this is chapter 9 of [2] and section 7.16 of [1].
  -- 
  -- The system to be modeled in this example consists of one bulldozer, four trucks,
  -- and two man-machine loaders. The bulldozer stockpiles material for the loaders.
  -- Two piles of material must be stocked prior to the initiation of any load operation.
  -- The time for the bulldozer to stockpile material is Erlang distributed and consists
  -- of the sum of two exponential variables each with a men of 4. (This corresponds to
  -- an Erlang variable with a mean of 8 and a variance of 32.) In addition to this
  -- material, a loader and an unloaded truck must be available before the loading
  -- operations can begin. Loading time is exponentially distributed with a mean time of
  -- 14 minutes for server 1 and 12 minutes for server 2.
  -- 
  -- After a truck is loaded, it is hauled, then dumped and must be returned before
  -- the truck is available for further loading. Hauling time is normally distributed.
  -- When loaded, the average hauling time is 22 minutes. When unloaded, the average
  -- time is 18 minutes. In both cases, the standard deviation is 3 minutes. Dumping
  -- time is uniformly distributed between 2 and 8 minutes. Following a loading
  -- operation, the loaded must rest for a 5 minute period before he is available
  -- to begin loading again. The system is to be analyzed for 8 hours and all operations
  -- in progress at the end of 8 hours should be completed before terminating
  -- the operations for a run.
  -- 
  -- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.
  -- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006
  
  import Control.Monad
  import Control.Monad.Trans
  import Control.Arrow
  
  import Data.Monoid
  import Data.List
  import Data.Array
  
  import Simulation.Aivika
  import qualified Simulation.Aivika.Queue.Infinite as IQ
  
  -- | The simulation specs.
  specs = Specs { spcStartTime = 0.0,
                  spcStopTime = 1000.0,
                  spcDT = 0.1,
                  spcMethod = RungeKutta4,
                  spcGeneratorType = SimpleGenerator }
  
  data Truck = Truck
  
  data Pile = Pile
  
  data Loader = Loader1
              | Loader2
                deriving (Eq, Ord, Show, Ix)
  
  awaitQueuesNonEmpty q1 q2 q3 =
    do n1 <- liftEvent $ IQ.queueCount q1
       n2 <- liftEvent $ IQ.queueCount q2
       n3 <- liftEvent $ IQ.queueCount q3
       when (n1 == 0 || n2 == 0 || n3 == 0) $
         do let signal = IQ.queueCountChanged_ q1 <>
                         IQ.queueCountChanged_ q2 <>
                         IQ.queueCountChanged_ q3
            processAwait signal
            awaitQueuesNonEmpty q1 q2 q3
  
  -- | The simulation model.
  model :: Simulation Results
  model = do
    truckQueue <- runEventInStartTime IQ.newFCFSQueue
    loadQueue <- runEventInStartTime IQ.newFCFSQueue
    loaderQueue <- runEventInStartTime IQ.newFCFSQueue
    loaderOp1 <- runEventInStartTime $
                 newRandomExponentialOperation 14
    loaderOp2 <- runEventInStartTime $
                 newRandomExponentialOperation 12
    let loaderOps = array (Loader1, Loader2)
                    [(Loader1, loaderOp1),
                     (Loader2, loaderOp2)]
    let start :: Process ()
        start =
          do randomErlangProcess_ 4 2
             randomErlangProcess_ 4 2
             liftEvent $
               IQ.enqueue loadQueue Pile
             t <- liftDynamics time
             when (t <= 480) start
        begin :: Process ()
        begin =
          do awaitQueuesNonEmpty truckQueue loadQueue loaderQueue
             truck  <- IQ.dequeue truckQueue
             pile   <- IQ.dequeue loadQueue
             loader <- IQ.dequeue loaderQueue
             -- the load operation
             operationProcess (loaderOps ! loader) () 
             -- truck hauling
             liftEvent $
               do runProcess $
                    do holdProcess 5
                       liftEvent $
                         IQ.enqueue loaderQueue loader
                  runProcess $
                    do randomNormalProcess_ 22 3
                       randomUniformProcess_ 2 8
                       randomNormalProcess_ 18 3
                       liftEvent $
                         IQ.enqueue truckQueue truck
             begin
    runEventInStartTime $
      do forM_ [1..4] $ \i ->
           IQ.enqueue truckQueue Truck
         IQ.enqueue loaderQueue Loader1
         IQ.enqueue loaderQueue Loader2
    runProcessInStartTime begin
    runProcessInStartTime begin
    runProcessInStartTime start
    return $
      results
      [ resultSource
       "loadQueue" "Queue Load"
       loadQueue,
       --
       resultSource
       "truckQueue" "Queue Trucks"
       truckQueue,
       --
       resultSource
       "loaderQueue" "Queue Loader"
       loaderQueue,
       --
       resultSource
       "loaderOps" "Loader Operations"
       loaderOps]
  
  main =
    printSimulationResultsInStopTime
    printResultSourceInEnglish
    (fmap resultSummary model) specs
  