#INCLUDE "moa.module"
#INCLUDE "course.module"

VAL FIELD.WIDTH IS 12:
PROTOCOL BACKTALK
  CASE
    query.ok
    sem
    poison
    cont
    err
:
PROC in.mob.string(RESULT MOBILE []BYTE mobstr, CHAN BYTE in,out)
  [100] BYTE str:
  INT len:
  SEQ
    in.string(str,len,100,in,out)
    mobstr:=MOBILE [len]BYTE
    #PRAGMA DEFINED mobstr
    SEQ i=0 FOR len
      mobstr[i]:=str[i]
    out ! '*n'
:
PROC do.delay (VAL INT us)
  TIMER tim:
  INT t:
  SEQ
    tim ? t                 -- read current time
    t := t PLUS us          -- add delay
    tim ? AFTER t           -- wait until time "t"
:
PROC mergechar([2]CHAN OF BYTE in?,CHAN OF BYTE out!)
  BYTE b:
  WHILE TRUE
    ALT i = 0 FOR 2
      in[i] ? b
        out ! b
:

PROC input(CHAN OF BYTE in?,out!,CHAN OF MYSQL.CONTROL sql.control,CHAN OF BACKTALK back)
  [50]BYTE str:
  MOBILE []BYTE strmob:
  INT strlen:
  WHILE TRUE
    SEQ
      back ? CASE
        sem
          SKIP
        err
          SKIP
        query.ok
          SKIP
        cont
          SKIP
      do.delay(100)
      out.string("mysql-occam>",0,out)
      out ! FLUSH
      in.string(str,strlen,100,in,out)
      out ! '*n'
      #PRAGMA DEFINED strmob
      strmob := MOBILE [strlen]BYTE
      SEQ i = 0 FOR strlen
        strmob[i] := str[i]
      SEQ
        sql.control ! query; strmob
        back ? CASE
          cont
            SEQ
              sql.control ! field.names
              sql.control ! remaining.rows
          err
            SKIP
:
PROC output(CHAN OF MYSQL.RESULT in, CHAN OF BYTE out!,CHAN OF BACKTALK back)
  INT s:
  INT num.fields:
  WHILE TRUE
    in ? CASE
      initialisation.error
        SEQ
          out.string("Initialisation error*n",0,out)
          out ! FLUSH
      no.data.error
        SEQ
          out.string("Error: No data*n",0,out)
          out ! FLUSH
          back ! err
      connected
        SEQ
          out.string("Connected to server*n",0,out)
          out ! FLUSH
          back ! sem
      INT n:
      data.ready; n
        SEQ
          out.string("Data ready!, number of rows : ",0,out)
          out.int(n,0,out) 
          out ! '*n'
          out ! FLUSH
          SEQ i=0 FOR 30
            out ! '-'
          out ! '*n'
          back ! cont


      MOBILE []MOBILE []BYTE f.names:
      INT sz:
      data.field.names; f.names
        SEQ
          num.fields:=SIZE f.names
          sz:= SIZE f.names
          SEQ i=0 FOR sz
            SEQ
              out.string(f.names[i],FIELD.WIDTH,out)
          out.string("*n",0,out)
      INT errnum:
      MOBILE []BYTE errdescr:
      mysql.error; errnum; errdescr
        SEQ
          out.string("Client error : ",0,out)
          out.int(errnum,0,out) 
          out.string(" description : ",0,out)
          out.string(errdescr,0,out)
          out ! '*n'
          out ! FLUSH
          back ! err
          back ! sem
      MOBILE []MOBILE []BYTE row:
      data.row ; row
        SEQ
          s := SIZE row
          SEQ i = 0 FOR SIZE row
            SEQ
              out.string(row[i],FIELD.WIDTH,out)
          out ! '*n'
          out ! FLUSH
      end.of.data
        SEQ
          SEQ i=0 FOR 30
            out ! '-'
          out ! '*n'
          out.string("end of resultset*n",0,out)
          out ! FLUSH
          back ! sem
:
PROC main(CHAN OF BYTE kyb,scr,err)
  [2]CHAN OF BYTE merge:
  CHAN MYSQL.CONTROL sql.control:
  CHAN MYSQL.RESULT sql.result:
  CHAN OF BACKTALK back:
  MOBILE []BYTE host,user,pass,database:
  SEQ
    out.string("MySQL demo client for MoA*n",0,scr)
    out.string("host :",0,scr)
    scr ! FLUSH
    in.mob.string(host,kyb,scr)
    out.string("user :",0,scr)
    scr ! FLUSH
    in.mob.string(user,kyb,scr)
    out.string("password :",0,scr)
    scr ! FLUSH
    in.mob.string(pass,kyb,scr)
    out.string("database :",0,scr)
    scr ! FLUSH
    in.mob.string(database,kyb,scr)
    #PRAGMA DEFINED host
    #PRAGMA DEFINED user
    #PRAGMA DEFINED pass
    err ! ' '-- FLUSH error chan so kroc will not give warning for unused chan.
    PAR
      mergechar(merge,scr)
      input(kyb,merge[0],sql.control,back)
      output(sql.result,merge[1],back)
      MySQL(sql.control,sql.result,host,user,pass,database,0,"")
:
