#INCLUDE "semaphore.inc"
#INCLUDE "crew.inc"

#USE "course.lib"                        -- FUNC random

#INCLUDE "display.inc"
#INCLUDE "blackboard.inc"
#INCLUDE "control_info.inc"

PROC philosopher (VAL BYTE id, VAL INT initial.seed,
                  CREW.CONTROL.INFO control.info,
                  CREW.BLACKBOARD blackboard,
                  CHAN OF DISPLAY out, SEMAPHORE out.s)

  VAL BYTE my.scribble IS '0' + id:

  --{{{  DATA TYPE PHIL.INFO
  DATA TYPE PHIL.INFO
    RECORD
      INT seconds:
      INT min.think, max.think, span.think:
      INT min.read, max.read, span.read:
      INT min.write, max.write, span.write:
      INT read.percentage:
  :
  --}}}

  PHIL.INFO phil.info:

  --{{{  PROC check.control (CREW.CONTROL.INFO control.info, PHIL.INFO phil.info)
  PROC check.control (CREW.CONTROL.INFO control.info, PHIL.INFO phil.info)
    INT new.seconds:
    SEQ
      claim.read.crew (control.info[crew])
      new.seconds := control.info[seconds]
      phil.info[read.percentage] := control.info[read.percentage]
      release.read.crew (control.info[crew])
      IF
        phil.info[seconds] <> new.seconds
          SEQ
            phil.info[seconds] := new.seconds
            phil.info[min.think] := 2*new.seconds
            phil.info[max.think] := 10*new.seconds
            phil.info[span.think] := phil.info[max.think] - phil.info[min.think]
            phil.info[min.read]  := 5*new.seconds
            phil.info[max.read]  := 10*new.seconds
            phil.info[span.read] := phil.info[max.read] - phil.info[min.read]
            phil.info[min.write] := 5*new.seconds
            phil.info[max.write] := 10*new.seconds
            phil.info[span.write] := phil.info[max.write] - phil.info[min.write]
        TRUE
          SKIP
  :
  --}}}

  INT seed:

  BOOL reading:

  SEQ
    --{{{  initialise info
    SEQ
      phil.info[seconds] := -1                  -- force the update below
      check.control (control.info, phil.info)
    --}}}
    --{{{  initialise seed
    INT dummy:
    SEQ
      seed := initial.seed
      dummy, seed := random (phil.info[span.think], seed)
    --}}}
    WHILE TRUE
      SEQ
        --{{{  think-a-while
        TIMER tim:
        INT t, i:
        SEQ
          claim.semaphore (out.s)
          out ! thinking; id
          release.semaphore (out.s)
          tim ? t
          check.control (control.info, phil.info)
          i, seed := random (phil.info[span.think], seed)
          tim ? AFTER t PLUS (phil.info[min.think] + i)
        --}}}
        --{{{  reading or writing?
        INT i:
        SEQ
          i, seed := random (100, seed)
          reading := (i < phil.info[read.percentage])
        --}}}
        IF
          reading
            --{{{  read-a-while
            TIMER tim:
            INT t, i:
            SEQ
              --{{{  say want to read
              SEQ
                claim.semaphore (out.s)
                out ! wanna.read; id
                release.semaphore (out.s)
              --}}}
              claim.read.crew (blackboard[crew])
              --{{{  say we are reading
              SEQ
                claim.semaphore (out.s)
                out ! reading; id
                release.semaphore (out.s)
              --}}}
              tim ? t
              check.control (control.info, phil.info)
              i, seed := random (phil.info[span.read], seed)
              tim ? AFTER t PLUS (phil.info[min.read] + i)
              --{{{  say what we have read
              SEQ
                claim.semaphore (out.s)
                out ! done.read; id; blackboard[value]
                release.semaphore (out.s)
              --}}}
              release.read.crew (blackboard[crew])
            --}}}
          TRUE
            --{{{  write-a-while
            TIMER tim:
            INT t, i:
            SEQ
              --{{{  say want to write
              SEQ
                claim.semaphore (out.s)
                out ! wanna.write; id; my.scribble
                release.semaphore (out.s)
              --}}}
              claim.write.crew (blackboard[crew])
              --{{{  say we are writing
              SEQ
                claim.semaphore (out.s)
                out ! writing; id; my.scribble
                release.semaphore (out.s)
              --}}}
              tim ? t
              check.control (control.info, phil.info)
              i, seed := random (phil.info[span.write], seed)
              tim ? AFTER t PLUS (phil.info[min.write] + i)
              blackboard[value] := my.scribble
              --{{{  say what we have written
              SEQ
                claim.semaphore (out.s)
                out ! done.write; id; blackboard[value]
                release.semaphore (out.s)
              --}}}
              release.write.crew (blackboard[crew])
            --}}}

:
