'' 
'' COPYRIGHT (C) 1987, CACI, INC. - FEDERAL, LA JOLLA
''
''
'' Model: bank      Investigating service time of customers depending on
''                  the number of tellers and other factors.
''
'' The core routines are the processes CUSTOMER and GENERATOR. Everything
'' else is animation and form interaction overhead.
''-----------------------------------------------------------------------

main
   call INITIALIZE		''-- init model parameters, create entities
   call INITIALIZE.GRAPHICS	''-- set up animation (graphs)
   call GET.PARAMETERS		''-- user dialog for model parameters
   call INITIALIZE.SIMULATION	''-- set simulation parameters from user input
   start simulation		''-- start the actual simulation run
   call SHOW.RESULTS		''-- show results in form
   stop

end  ''main

''-----------------------------------------------------------------

Routine CLOCK.UPDATE given TIME yielding NEWTIME
	''-- This routine is called every time TIME.V changes (attached to
	''-- that event in INITIALIZE.GRAPHICS. The assignment to CLOCKTIME
	''-- (is a display variable) causes the associated clock icon
	''-- to be updated on the screen.
    Define TIME, NEWTIME as double variables

    Let NEWTIME = TIME
    Let CLOCKTIME = TIME

End  ''CLOCK.UPDATE

''-----------------------------------------------------------------

process CUSTOMER
	''-- Models behavior of a customer entering the bank (created by
	''-- the GENERATOR). 
   define ARRIVAL.TIME as a real variable
   let ARRIVAL.TIME = time.v
   request 1 TELLER(1)
   let WAITING.TIME = (time.v - ARRIVAL.TIME) * hours.v * minutes.v
   work exponential.f(MEAN.SERVICE.TIME, 2) minutes
   relinquish 1 TELLER(1)
end  ''CUSTOMER

''-----------------------------------------------------------------

process GENERATOR
	''-- Generates CUSTOMER processes with random interarrival times.
   define TIME.TO.CLOSE as a real variable
   let TIME.TO.CLOSE = time.v + DAY.LENGTH / hours.v
   until time.v >= TIME.TO.CLOSE
   do
      activate a CUSTOMER now
      wait exponential.f(MEAN.INTERARRIVAL.TIME, 1) minutes
   loop
end  ''GENERATOR

''-----------------------------------------------------------------

routine INITIALIZE
     	''-- initialize simulation parameters, create entities etc.
   NO.OF.TELLERS = 4
   MEAN.INTERARRIVAL.TIME = 2.0
   MEAN.SERVICE.TIME = 7.0
   DAY.LENGTH = 6.0
     ''-- create entities 
   create every TELLER(1)
   let u.TELLER(1) = NO.OF.TELLERS
   activate a GENERATOR now
   
end  '' routine INITIALIZE

''-----------------------------------------------------------------

routine INITIALIZE.GRAPHICS
	''-- Set animation speed (TIMESCALE.V) and make CLOCK.UPDATE be called
	''-- every time TIME.V changes.
	''-- Also: Associate the graphs with the display variables.

   Let TIMESCALE.V = 1000  '' clock ticks (1/100 sec) per unit
   Let TIMESYNC.V = 'CLOCK.UPDATE'

   Display CLOCKTIME with "clock.grf"
   Display N.Q.TELLER(1) with "queue.grf"
   Display histogram WAITING.TIME.HISTOGRAM with "wait.grf"

	''-- display title text in top left corner
   create a SHAPE
   call TEXTALIGN.R(0,0)   '' textalign call needed with simgraphics
   display SHAPE with "title.icn" at (12000.0, 31000.0)

end  ''INITIALIZE.GRAPHICS


''-----------------------------------------------------------------

routine INITIALIZE.SIMULATION
	''-- init simulation parameters from user input
   let u.TELLER(1) = NO.OF.TELLERS
end


''-----------------------------------------------------------------

routine GET.PARAMETERS
	''-- Offer the model parameters for change by the user in a form.

  define FORM.PTR as a pointer variable
  define FIELD.ID as a text    variable

  SHOW FORM.PTR with "input.frm"
 
    ''--- set the current values: parameters:
  DDVAL.A(DFIELD.F("NUM.TELLERS", FORM.PTR)) = NO.OF.TELLERS
  DDVAL.A(DFIELD.F("INTARR.TIME", FORM.PTR)) = MEAN.INTERARRIVAL.TIME
  DDVAL.A(DFIELD.F("SERVICE.TIME", FORM.PTR)) = MEAN.SERVICE.TIME
  DDVAL.A(DFIELD.F("BUSINESS.HOURS", FORM.PTR)) = DAY.LENGTH

  let FIELD.ID = ACCEPT.F(FORM.PTR,0)

  if FIELD.ID = "EXIT"
    stop
  endif

    ''-- now set the new parameter values
  NO.OF.TELLERS = DDVAL.A(DFIELD.F("NUM.TELLERS", FORM.PTR))
  MEAN.INTERARRIVAL.TIME = DDVAL.A(DFIELD.F("INTARR.TIME", FORM.PTR))
  MEAN.SERVICE.TIME = DDVAL.A(DFIELD.F("SERVICE.TIME", FORM.PTR))
  DAY.LENGTH = DDVAL.A(DFIELD.F("BUSINESS.HOURS", FORM.PTR))

end

''-----------------------------------------------------------------

routine SHOW.RESULTS
	''-- Show results in a form after simulation is complete. But first
	''-- let the user admire the graphics and then click on the screen 
	''-- to get the results form.

  define FORM.PTR as a pointer variable
  define FIELD.ID as a text    variable
  define UTILIZATION as a real variable

  define NEWX, NEWY as real variables
  define XFORM as an integer variable
       
	''-- display the 'endsim.icn' which asks for a user click 
  erase SHAPE			''-- erase the old title icon
  call TEXTALIGN.R(0,0)		''-- textalign call needed with simgraphics
  display SHAPE with "endsim.icn" at (12000, 31000)
	''-- now wait for mouse click
  call READLOC.R given 12000, 29000, 0 yielding NEWX, NEWY, XFORM
  NEWX = NEWX		''-- shut up warnings
  NEWY = NEWY
  XFORM = XFORM

	''----- now show the results form

  SHOW FORM.PTR with "results.frm"
 
    ''--- set the current values: parameters:
  DDVAL.A(DFIELD.F("NUM.TELLERS", FORM.PTR)) = NO.OF.TELLERS
  DDVAL.A(DFIELD.F("INTARR.TIME", FORM.PTR)) = MEAN.INTERARRIVAL.TIME
  DDVAL.A(DFIELD.F("SERVICE.TIME", FORM.PTR)) = MEAN.SERVICE.TIME
  DDVAL.A(DFIELD.F("BUSINESS.HOURS", FORM.PTR)) = DAY.LENGTH

    ''-- result variables:
  DDVAL.A(DFIELD.F("FINISH.TIME", FORM.PTR)) = TIME.V * HOURS.V
  UTILIZATION = AVG.TELLER.BUSY(1) / NO.OF.TELLERS * 100
  DDVAL.A(DFIELD.F("TELLER.UTIL", FORM.PTR)) = UTILIZATION
  DDVAL.A(DFIELD.F("AVG.Q.LEN", FORM.PTR)) = AVG.QUEUE.LENGTH(1)
  DDVAL.A(DFIELD.F("MAX.Q.LEN", FORM.PTR)) = MAX.QUEUE.LENGTH(1)
  DDVAL.A(DFIELD.F("AVG.CUST.WAIT", FORM.PTR)) = MEAN.WAITING.TIME

  let FIELD.ID = ACCEPT.F(FORM.PTR,0)
  FIELD.ID = FIELD.ID		''-- shut up warnings
end

