#pragma mode(separator(.,;) integer(h32))

p,ns,ct,tape,tp,q;
inst,mode,cs,b;

black:=RGB(0,0,0);
red:=RGB(255,0,0);
white:=RGB(255,255,255);

modes:={"Key press","Slow","Medium","Fast","Very fast"};

WaitForRelease()
BEGIN
 REPEAT
 UNTIL STRING(MOUSE)="{{},{}}";

 REPEAT 
 UNTIL GETKEY=-1;
END;

Init(filename)
BEGIN
 DIMGROB_P(G2,320,240);

 p:=Notes(filename);
 cs:="Q1";
 ns:="";
 ct:="";
 tp:=1;
 b:="B";
 q:="";
 inst:="";

 WaitForRelease();
END;

Fetch()
BEGIN
 LOCAL ss,sq,f,rhs,keepRunning;

 ct:=MID(tape,tp,1);
 ss:=cs+" "+ct+" ";
 sq:=INSTRING(p,ss);

 IF sq THEN
  // Found start of quad
  q:=MID(p,sq,14);
  f:=INSTRING(q,CHAR(10));
  IF f THEN
   // Truncate quad to EOL
   q:=LEFT(q,f-1);
  END;
  rhs:=MID(q,SIZE(ss)+1);
  inst:=LEFT(rhs,1);
  ns:=MID(rhs,3);
  keepRunning:=1;
 ELSE
  keepRunning:=0;
 END;

 RETURN(keepRunning);
END;

MoveRight()
BEGIN
 tp:=tp+1;

 // Extend tape if pointer is past end
 IF tp>SIZE(tape) THEN
  tape:=tape+b;
 END;
END;

MoveLeft()
BEGIN
 IF tp==1 THEN
  // Extend tape to left
  tape:=b+tape;
 ELSE
  tp:=tp-1; 
 END;
END;

WriteToTape()
BEGIN
 tape(tp):=inst;
END;

Execute()
BEGIN
 CASE
  IF inst=="R" THEN MoveRight() END;
  IF inst=="L" THEN MoveLeft() END;
  DEFAULT WriteToTape();
 END;

 cs:=ns;
END;

Output(m)
BEGIN
 LOCAL ls:="";
 LOCAL ms:="";
 LOCAL rs:="";
 LOCAL t:="";

 CASE
 IF tp==1 THEN
  ms:=LEFT(tape,1);
  rs:=MID(tape,2);
  END;
 IF tp==SIZE(tape) THEN
  ls:=LEFT(tape,SIZE(tape)-1);
  ms:=MID(tape,SIZE(tape));
  END;
 DEFAULT
  ls:=LEFT(tape,tp-1);
  ms:=MID(tape,tp,1);
  rs:=MID(tape,tp+1);
 END;

 t:=ls+"["+ms+"]"+rs;

 RECT(G2,white);
 TEXTOUT_P(q,G2,0,0,2,black);
 TEXTOUT_P(t,G2,0,20,2,black);
 TEXTOUT_P(m,G2,0,40,2,black);
 BLIT_P(G0,G2);
END;

HandleMode()
BEGIN
CASE
 IF mode==1 THEN WAIT(-1); END;
 IF mode==2 THEN WAIT(1); END;
 IF mode==3 THEN WAIT(0.5); END;
 IF mode==4 THEN WAIT(0.25); END;
 DEFAULT
  // As fast as possible
 END;
 WaitForRelease();
END;

EXPORT Turing()
BEGIN
 LOCAL filename,v;
 tape:="1";
 cs:="Q1";
 b:="B";

 v:=INPUT({{filename,Notes()},{mode,modes},{tape,[2]},{cs,[2]},{b,[2]}},"Turing Machine Simulator",{"Program","Run mode","Initial tape","Initial state","Blank character"});

 IF v THEN
  Init(filename);
  Output("");
  HandleMode();
  WHILE Fetch() DO
   Output("");
   Execute();
   HandleMode();
  END;
  Output("Finished");
  WaitForRelease();
  FREEZE;
 END;
 RETURN(tape);
END;
