/* COPYRIGHT NOTICE
*
*  This software is created by prof. Milan Popovic, Belgrade Business School, Belgrade, Serbia, email milanpopovic@ptt.rs.*
*  Copyright ©20009 by Milan Popovic. All Rights Reserved. Permission to use, copy, modify, and distribute this software 
*  and its documentation for educational, research, and not-for-profit purposes, without fee and without a signed licensing
*  agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs 
*  appear in all copies, modifications, and distributions. Contact Milan Popovic, email milanpopovic@ptt.rs, for commercial
*  licensing opportunities. 
*  
*  DISCLAIMER
*  
*  IN NO EVENT SHALL THE AUTOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, 
*  INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHOR HAS BEEN ADVISED
*  OF THE POSSIBILITY OF SUCH DAMAGE.
*  
*  THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
*  AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED
*  "AS IS". THE AUTHOR HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
**************************************************************************************************************************/
/*******************************************************************************
*
*                      Karel's library
*
********************************************************************************/

/********************************************************************************
*
*                       Resize window
*
*********************************************************************************/
var pageW = Math.floor(screen.width*0.95);
var worldSize = Math.floor(screen.height*0.7);
var consoleSize = Math.floor(pageW*0.15);
var progSize = pageW-worldSize-consoleSize;

function fitToSize(){
  document.getElementById('programTitle').style.width = progSize+'px';
  document.getElementById('programTitle').style.height = 20+'px';
  document.getElementById('program').style.width = progSize+'px';
  document.getElementById('program').style.height = worldSize+'px';
  document.getElementById('consoleTitle').style.width = consoleSize+'px';
  document.getElementById('consoleTitle').style.height = 20+'px';
  document.getElementById('console').style.width = consoleSize+'px';
  document.getElementById('console').style.height = Math.floor(consoleSize*0.8)+'px';
  document.getElementById('worldTitle').style.width = worldSize+'px';
  document.getElementById('worldTitle').style.height = 20+'px';
}


/*******************************************************************************************************
*                                                                                                      *
*                                 Global variables                                                     *
*                                                                                                      *
********************************************************************************************************/
const MAX_PROG_STEPS = 10000;
const MAX_STREETS = 100; MAX_AVENUES = 100; 
var design ="none";
var kareleast='images/karel-east.gif', karelwest='images/karel-west.gif', karelsouth='images/karel-south.gif', karelnorth='images/karel-north.gif';
var karel=0; var karelFacing=0; var karelSize=0; var karelX=0; var karelY=0; 
var lastCrash=0; var karelImg=kareleast; var speed=0.5; tMove = 0; tExec=0;//Annimation parameters

var font="vedrana"; var fontSize = "20px"; var fontStyle = "FONT.ITALIC_BOLD"; var fontColor="red";

var end = 0; var pc = 0; var stop = false;

var mode = "manual"; var source='';
var curProgram = "source";

var karelAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

var letters = new Array(10000);
for(i=0; i < 10000; i++) letters[i] = "";

var beepers = new Array(10000);
for(i=0; i < 10000; i++) beepers[i] = 0;


var command = new Array(end)
for (i=0; i < MAX_PROG_STEPS ; i++)
	command[i]=0;

/*******************************************************************************************************
*                                                                                                      *
*                                 Initialization                                                       *
*                                                                                                      *
********************************************************************************************************/

function initWorld(){      
  document.getElementById('KarelWorld').style.left = (progSize+20)+'px';
  cellSize = Math.floor(worldSize/Math.max(avenues,streets));
  karelX = 0;
  karelY = 0;
  for(i=0; i < 2500; i++) beepers[i] = 0;
  karelFacing = 'east';
  karelSize = cellSize;
  karelImg=kareleast; 
  lastCrash ="Never";
  drawWorld(); 
  world.drawKarel("karel",karelImg,0,(streets-1)*cellSize,karelSize,karelSize,'');    
  world.paint();
  karel = document.getElementById('karel'); // Karel <div> element
  if(curProgram == "source") source = document.getElementById('program').value;
  worldMap="Dimension:("+streets+','+avenues+')\nBeeperBag: INFINITE\nKarel: (1, 1) East\nSpeed: 0.5\n';
  showStatus();
  turnRight();turnLeft();
}

function drawWorld(){  
      world = new jsGraphics("KarelWorld");
      world.setColor("gainsboro");
      world.setStroke(1);
      for(i=0; i<=avenues; i++)	// Plotting the grid (Karel's world) 
      	world.drawLine(i*cellSize, 0, i*cellSize, cellSize*streets);
      for(i=0; i<=streets; i++)   	      
      	world.drawLine(0,i*cellSize, cellSize*avenues,i*cellSize);
      world.paint();

}

function putKarel(x,y){
  yK = (streets-1)*cellSize-y*cellSize;
  xK = x*cellSize;
  switch(karelFacing){
  	case 'east': karelImg = kareleast;break;
  	case 'west': karelImg = karelwest;break;
  	case 'south': karelImg = karelsouth;break;
  	case 'north': karelImg = karelnorth;break;
      dafault: "blank.gif";
  }
  karel.style.top  = yK+'px'; 
  karel.style.left = xK+'px';   
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Basic Karel operations                                               *
*                                                                                                      *
********************************************************************************************************/

function moveKarel(){ // Animate Karel's one step move 
 if(tMove == 0){ 
      // Calculate current position (fromX,fromY)
  	leftMargin = (screen.availWidth-avenues*cellSize)/2;
  	fromY = (streets-1)*cellSize - karelY*cellSize;
  	fromX = karelX*cellSize;  
      // Make a move or detect a collision
  	switch(karelFacing){
  		case 'east': if(karelX == (avenues-1)){Crash();break;} 
            	karelX++; break;
  		case 'west': if(karelX == 0){Crash();break;}
               	karelX--; break;
  		case 'south': if(karelY == 0){Crash();break;}
               	karelY--; break;
  		case 'north': if(karelY == (streets-1)){Crash();break;}
               	karelY++; break;
      	dafault: break;
  	}
      // Calculate next position (toX,toY)
  	toY = (streets-1)*cellSize - karelY*cellSize;
  	toX = karelX*cellSize;   
  	dx = (toX-fromX)/20;
  	dy = (toY-fromY)/20;
  }
  // Animate the move in increments dx and dy
  fromX += dx; // Change current position
  fromY += dy; 
  //alert(fromX+' '+fromY);
  karel.style.top  = Math.floor(fromY)+'px'; 
  karel.style.left = Math.floor(fromX)+'px'; 

  if((toX-fromX)*(toX-fromX)+ (toY-fromY)*(toY-fromY) < 10) {tMove=0;return;}
  tMove = setTimeout("moveKarel()",20); // Timeout
}

function move(){
  if (mode == "auto") {
				command[pc++] = "move"; if(pc > 9998) { alert("Halting problem - program will never end "); stop();return;}
				switch(karelFacing){
  					case 'east': karelX++; break;
  					case 'west': karelX--; break;
  					case 'south':karelY--; break;
  					case 'north':karelY++; break;
      				dafault: break;
  				}
				return;
  }
  if(!frontIsClear()){
      Crash();
      return;
  }
  moveKarel(); showStatus();
}

function turnLeft(){ 
  if (mode == "auto") {command[pc++] = "turnLeft"; if(pc > 9998) { alert("Halting problem - program will never end! "); stop();return;}
				switch(karelFacing){
  					case 'east': karelFacing = 'north'; break;
  					case 'west': karelFacing = 'south'; break;
  					case 'south': karelFacing = 'east'; break;
  					case 'north': karelFacing = 'west'; break;
					dafault: break;
  					}
				return;
  }
  switch(karelFacing){
  	case 'east': karelFacing = 'north'; karelImg = karelnorth; karel.innerHTML=karel.innerHTML.replace("east","north");break;
  	case 'west': karelFacing = 'south'; karelImg = karelsouth;karel.innerHTML=karel.innerHTML.replace("west","south");break;
  	case 'south': karelFacing = 'east'; karelImg = kareleast;karel.innerHTML=karel.innerHTML.replace("south","east");break;
  	case 'north': karelFacing = 'west'; karelImg = karelwest;karel.innerHTML=karel.innerHTML.replace("north","west");break;
	dafault: break;
  }
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Advanced Karel operations                                            *
*                                                                                                      *
********************************************************************************************************/

function turnRight(){
  turnLeft();
  turnLeft();
  turnLeft();
}

function turnAround(){
  turnLeft();
  turnLeft();
}
/*******************************************************************************************************
*                                                                                                      *
*                                 Beeper functions                                                     *
*                                                                                                      *
********************************************************************************************************/
function putBeeper(){
  if (mode == "auto" && curProgram != "map") {
      command[pc++] = "putBeeper";   beepers[karelY*avenues+karelX]++;  
      document.getElementById('beepers').value = beepers[karelY*avenues+karelX];
      return;
  }
  size = Math.floor(cellSize/5);
  if(size < 2) size=2;
  disp = Math.floor(cellSize/5);
  beeperName="T"+karelX+"_"+karelY;
  if (!beepersPresent())
  {
    world.drawBeeper(karelX,karelY,size,size)
    world.paint();
  }  
  addBeeper();
  }

function pickBeeper(){  
  if (mode == "auto") {command[pc++] = "pickBeeper";  beepers[karelY*avenues+karelX]--; document.getElementById('beepers').value = beepers[karelY*avenues+karelX];
return;}
  if(!beepersPresent()) return;
  removeBeeper();
  if(!beepersPresent()){
     deleteBeeper();
  }
}
function putBeeperM(){
 beepers[karelY*avenues+karelX]++;
 document.getElementById('beepers').value = beepers[karelY*avenues+karelX];
 putBeeper();
}

function putrunBeeper(){
  putBeeper();
  beepers[karelY*avenues+karelX]++;
  document.getElementById('beepers').value = beepers[karelY*avenues+karelX];
}

function pickBeeperM(){
 if(beepers[karelY*avenues+karelX] == 0) return;
 beepers[karelY*avenues+karelX]--; 
 document.getElementById('beepers').value = beepers[karelY*avenues+karelX];
 pickBeeper();
}
function deleteBeeper(){
  beeperId = 'B'+karelX+'_'+karelY;
  reg = '<div id="'+beeperId+'" .*?>(.*?)</div>';
  var regExp=new RegExp(reg,"i");  
  document.getElementById('KarelWorld').innerHTML = document.getElementById('KarelWorld').innerHTML.replace(regExp,'');
  redrawKarel();
}

function addBeeper(){
  if(!beepersPresent()){
    token = "beepers:("+(karelX+1)+","+(karelY+1)+")1\n";
    worldMap+=token;
    return;
  }
  token = "beepers:("+(karelX+1)+","+(karelY+1)+")";
  lines = worldMap.split('\n');
  for(l = 0; l < lines.length; l++){
       var count = 0;
	 if (lines[l].indexOf(token) ==-1) continue;
       {
          cc = lines[l];
          c = lines[l].replace(token,'');
          count=parseInt(c)+1;
          worldMap = worldMap.replace(cc,token+count);
          return;
       }
  }  
}

function removeBeeper(){
  if(!beepersPresent()){
       return;
  }
  token = "beepers:("+(karelX+1)+","+(karelY+1)+")";
  lines = worldMap.split('\n');
  for(l = 0; l < lines.length; l++){
       var count = 0;
	 if (lines[l].indexOf(token) ==-1) continue;
       {
          cc = lines[l];
          c = lines[l].replace(token,'');
          count=parseInt(c);
          if(count == 1)
              worldMap = worldMap.replace(cc+'\n','');
          else {count--;worldMap = worldMap.replace(cc,token+count+'\n');}
          return;
       }
  }  

}

/*******************************************************************************************************
*                                                                                                      *
*                                 Paint and print functions                                            *
*                                                                                                      *
********************************************************************************************************/

function printCorner(char){
if (mode == "auto") {command[pc++] = "print "+char; return;}
  fontSize=Math.floor(cellSize/2);
  world.setFont(font,fontSize+"px",fontStyle);  
  world.setColor(document.getElementById('colors').value);
  x = Math.floor(karelX*cellSize+cellSize/2-fontSize/2);
  y = Math.floor((streets - karelY -1)*cellSize+cellSize/2-fontSize/2);
  world.drawString(char,x,y);
  world.paint();
}

function paintCorner(c){
if (mode == "auto") {command[pc++] = "paint "+c; return;}
    paintColor = c;
    paint();
}

function paint(){
  world.setColor(paintColor);
  world.fillRect(karelX*cellSize+1,(streets-karelY-1)*cellSize+1,cellSize-1,cellSize-1);  
  redrawKarel();
  redrawBeeper();
}

function paintM(){
  world.setColor(document.getElementById('colors').value);
  world.fillRect(karelX*cellSize+1,(streets-karelY-1)*cellSize+1,cellSize-1,cellSize-1); 
    redrawBeeper();
    redrawKarel();
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Program control                                                      *
*                                                                                                      *
********************************************************************************************************/

function clearProgram(){
  document.getElementById('program').value='';
}

function Crash(){
  var curDateTime = new Date()
  lastCrash = curDateTime.toLocaleString();
  lastCrash = lastCrash.replace('GMT+0100 (Central Europe Standard Time)','');
  consoleWrite("Crash:"+lastCrash);
  turnLeft();
}

function showStatus(){
 document.getElementById('posX').value = karelX;
 document.getElementById('posY').value = karelY;
 document.getElementById('speed').value = speed; 
 document.getElementById('rows').value = streets;
 document.getElementById('cols').value = avenues;
 document.getElementById('beepers').value = beepers[karelY*avenues+karelX];
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Environmental changes                                                *
*                                                                                                      *
********************************************************************************************************/

function newWorld(){
  new_streets = parseInt(document.getElementById('rows').value);
  new_avenues = parseInt(document.getElementById('cols').value);
  if(new_avenues > 0 && new_avenues <= MAX_AVENUES){
					avenues = new_avenues; document.getElementById('posX').value = avenues;
				    }
  else { 
        consoleWrite('0<=avenues<='+MAX_AVENUES);document.getElementById('posX').value = avenues;
  }
  if(new_streets > 0 && new_streets <= MAX_STREETS){                              
                              streets=new_streets; document.getElementById('posY').value = streets;
                            }
  else {
        consoleWrite('0<=streets<='+MAX_STREETS);
        document.getElementById('posY').value = streets;
  }
  

  world.clear();
  initWorld();
}

function changeBeepers(){

  beepers[karelY*avenues+karelX]= parseInt(document.getElementById('beepers').value);
  size = Math.floor(cellSize/5);
  if(size < 2) size=2;
  disp = Math.floor(cellSize/5);
  beeperName="T"+karelX+"_"+karelY;
  if (!beepersPresent()){
    world.drawBeeper(karelX,karelY,size,size)
    world.paint();
  }  
  for(i=0;i < beepers[karelY*avenues+karelX]; i++)
     addBeeper();
}

function newKarel(name){
  
  kareleast = 'images/'+name+'-east.gif';
  karelwest = 'images/'+name+'-west.gif';
  karelsouth = 'images/'+name+'-south.gif';
  karelnorth = 'images/'+name+'-north.gif';
  switch(karelFacing){
  	case 'east': karelImg = kareleast;break;
  	case 'west': karelImg = karelwest;break;
  	case 'south': karelImg = karelsouth;break;
  	case 'north': karelImg = karelnorth;break;
	dafault: break;
  }
  redrawKarel();
}

function newSpeed(){

  new_speed = parseFloat(document.getElementById('speed').value);
  if (new_speed >= 0 && new_speed <= 1) { 
      speed = new_speed;document.getElementById('speed').value= speed;
  }
  else { consoleWrite("0<=speed<=1"); document.getElementById('speed').value= speed;}
}

function newPos(){
  karelX = parseInt(document.getElementById('posX').value);
  karelY = parseInt(document.getElementById('posY').value);
  if(karelX > (avenues-1)){consoleWrite('Max. avenues:'+(avenues-1));
					karelX=0; document.getElementById('posX').value = karelX;
					putKarel(karelX,karelY);return;
				   }
  if(karelY > (streets-1)){consoleWrite('Max. streets:'+(streets-1));
                              karelY=0; document.getElementById('posY').value = karelY;
                              putKarel(karelX,karelY);return;
                           }
  putKarel(karelX,karelY);
}

function redrawKarel(){
  document.getElementById('KarelWorld').innerHTML = document.getElementById('KarelWorld').innerHTML.replace(/<div id="karel\b[^>]*>(.*?)<\/div>/,'');
  world.drawKarel("karel",karelImg,karelX*cellSize,(streets-karelY-1)*cellSize,karelSize,karelSize,'');
  world.paint(); 
  karel = document.getElementById('karel'); // Karel <div> element
}

function redrawBeeper(){
  if(!beepersPresent()) return;
  world.setColor("red");
  size = Math.floor(cellSize/5);
  if(size < 2) size = 2;
  beeperId = 'B'+karelX+'_'+karelY;
  reg = '<div id="'+beeperId+'" .*?>(.*?)</div>';
  var regExp=new RegExp(reg,"i");  
  document.getElementById('KarelWorld').innerHTML = document.getElementById('KarelWorld').innerHTML.replace(regExp,'');
  world.drawBeeper(karelX,karelY,size,size);
  world.paint();
}
function newBeepers(){
  for(i=0; i < parseInt(document.getElementById('beepers').value);i++) putBeeper();
}
/*******************************************************************************************************
*                                                                                                      *
*                                 Program execution                                                    *
*                                                                                                      *
********************************************************************************************************/
function compile(){
if (curProgram == 'source'){
    prog = document.getElementById('program').value; 
    source = prog;
    pc=0;
    mode="auto";
    startX = karelX;
    startY = karelY;
    startFacing = karelFacing;
    eval(prog);
    karelX=startX;
    karelY=startY;
    karelFacing = startFacing;
    end = pc;
    showObjectCode();
  }
}
function runProgram(){
  stop = false;
  if(curProgram == 'map'){
    loadWorld();
    return;
  }
  prog = document.getElementById('program').value; 
  if (curProgram == 'source'){
    pc=0;
    mode="auto";
    startX = karelX;
    startY = karelY;
    startFacing = karelFacing;
    eval(prog);
    karelX=startX;
    karelY=startY;
    karelFacing = startFacing;
    end = pc;
  }
  else {command = prog.split('\n'); end = command.length};
  mode="manual";
  pc=0;
  consoleWrite("No. of steps = "+end);
  autoExec();
}

function autoExec(){
  if(stop) {stop = false; return;}
  if( pc == end ) return;
  instr = command[pc++].split(' ');
  switch (instr[0]){
  	case "move":move(); break;
  	case "turnLeft": turnLeft();break;
  	case "putBeeper": putBeeper();break;
  	case "pickBeeper": pickBeeper();break;
  	case "paint": paintCorner(instr[1]);break;
  	case "print": printCorner(instr[1]);break;
  	default: break;
  }
    t=100;
    if(instr[0]=="move") t = 250;
    tExec = setTimeout("autoExec()",t+100/speed);
}

function optimizeCode(){
  code = document.getElementById('program').value; 
  code = code.replace(/turnLeft\nturnLeft\nturnLeft\nturnLeft\n/g,'');
  document.getElementById('program').value = code;
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Utilities                                                            *
*                                                                                                      *
********************************************************************************************************/
function changeMode(mode){
   switch(curProgram){
     case 'source': source = document.getElementById('program').value; break;
     case 'object': break;
     case 'map': worldMap = document.getElementById('program').value; break;
     default: break;
   }
   switch(mode){
     case "Source code": showSourceCode();break;
     case "Object code": showObjectCode(); break;
     case "World code":showMapCode();break;
     default: break;
   }
}

function showObjectCode(){
  var prog='';
  for( i=0;i<end;i++) 
    prog = prog + command[i]+'\n';
  if(prog == "") {alert("Nothing compiled, check program and world!"); return;}
  document.getElementById('program').value=prog;
  curProgram = 'object';
}

function showSourceCode(){
  document.getElementById('program').value=source;
  curProgram = 'source';
}

function showMapCode(){
  document.getElementById('program').value=worldMap;
  curProgram = 'map';
}

function consoleWrite(message){
  document.getElementById('console').value+=message+'\n';
}

function stopRobot(){
  stop = true;
  tMove=0;
}

function karelToHome(){
  karelX=0;
  karelY=0;
  switch(karelFacing){
  	case 'east': break
  	case 'west': karelFacing = 'east'; karelImg = karelsouth;karel.innerHTML=karel.innerHTML.replace("west","east");break;
  	case 'south': karelFacing = 'east'; karelImg = kareleast;karel.innerHTML=karel.innerHTML.replace("south","east");break;
  	case 'north': karelFacing = 'east'; karelImg = karelwest;karel.innerHTML=karel.innerHTML.replace("north","east");break;
	dafault: break;
  }
  putKarel(0,0);
  showStatus();
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Condition                                                            *
*                                                                                                      *
********************************************************************************************************/

function frontIsClear(){
  side  = karelFacing;
  x=karelX; y =karelY;
  if( side == "east" && x+1==avenues) return false; // Check against outer walls
  if( side == "south" && y-1 < 0) return false;
  if( side == "west" && x-1 < 0) return false;
  if( side == "north" && y+1==streets) return false;
  if(karelFacing == "north") {side = "south"; y = y+1;} // Ckeck agains inside walls
  if(karelFacing == "east") {side="west"; x=x+1;}
  wall = "wall:("+(x+1)+","+(y+1)+")"+side;
  if (worldMap.indexOf(wall) !=-1) return false;
  else return true;
}
function frontIsBlocked(){
 return !frontIsClear();
}
function leftIsClear(){
 turnLeft();
 look = frontIsClear();
 turnRight();
 return look;
} 
function leftIsBlocked(){
return !leftIsClear();
}
function rightIsClear() {
 turnReft();
 look = frontIsClear();
 turnLeft();
 return look;

}
function rightIsBlocked(){
 return !rightIsClear();
}

function noBeepersPresent(){
 return !beepersPresent();
}
function beepersInBag() {
 if(beepersbag >0) return true;
   else return false;
}
function noBeepersInBag(){
 return !beepersInBag();
}

function facingNorth() {
  if(karelFacing == 'north') return true;
  else return false;
}
function notFacingNorth(){
  return !facingNorth();
}

function facingEast() {
  if(karelFacing == 'east') return true;
  else return false;
}
function notFacingEast(){
  return !facingEast();
}

function facingSouth() {
  if(karelFacing == 'south') return true;
  else return false;
}
function notFacingSouth(){
  return !facingSouth();
}

function facingWest() {
  if(karelFacing == 'west') return true;
  else return false;
}
function notFacingWest(){
  return !facingWest();
}
function beepersPresent(){
  if(mode=="auto"){ if(beepers[karelY*avenues+karelX]>0) return true;
                   else return false;}
  token = "beepers:("+(karelX+1)+","+(karelY+1)+")";
  if (worldMap.indexOf(token) ==-1) return false;
  else return true;
}

/*******************************************************************************************************
*                                                                                                      *
*                                 World setup functions                                                *
*                                                                                                      *
********************************************************************************************************/

// World 
var worldMap = ""; var world = 0; var avenues=16; var streets=16; var cellSize = 0;
var colors = new Array("red","green","blue","yellow","orange","pink","brown","red");
var beeperbag = 0;

var parseX =0;var parseY =0;

/*******************************************************************************************************
*                                                                                                      *
*                                 Loads world parameters                                               *
*                                                                                                      *
********************************************************************************************************/

function loadWorld(){
  var x = 0, y = 0 ;
  var facing = 0;
  var beepers = 0;
  worldMap =document.getElementById('program').value; 
  worldMap=worldMap.toLowerCase();
  worldMap = worldMap.replace(/ /g,'');
  document.getElementById('program').value = worldMap;
  lines = worldMap.split('\n');
  for (k=0; k < lines.length; k++){ 
    line = lines[k].split(':');
    switch(line[0]){
      case 'dimension':parseCoordinates(line[1]); document.getElementById('rows').value = parseX; 
                     document.getElementById('cols').value = parseY; newWorld(); break;
      case 'wall': parseCoordinates(line[1]); side = findSide(line[1]); drawWall(parseX,parseY,side,"gray"); break;
      case 'beepers': parseCoordinates(line[1]); makeBeeper(parseX-1,parseY-1); break;
      case 'karel': parseCoordinates(line[1]); karelX = parseX-1; karelY=parseY-1;karelFacing = findSide(line[1]); 
                    putKarel(parseX-1,parseY-1);
			  document.getElementById('posX').value=parseX-1;
			  document.getElementById('posY').value=parseY-1;break;
      case 'speed': speed = parseFloat(line[1].replace('speed: ','')); document.getElementById('speed').value = speed;break;
      case 'beeperbag':  side = line[1].replace('beeperbag: ',''); 
                         if(side == 'infinite') beeperbag = Infinity;
                         else beeperbag = parseInt(line[1].replace('beeperbag: ','')); break;
      default: break;
    }

  }
  worldMap =document.getElementById('program').value; 
}

function parseCoordinates(line){
  parts = line.split(',');
  var xx = parts[0].split('(');
  var yy = parts[1].split(')');
  parseX = parseInt(xx[1]);
  parseY = parseInt(yy[0])
}

function findSide(line){
  if (line.indexOf('south') !=-1) return 'south';
  if (line.indexOf('east') !=-1) return 'east';
  if (line.indexOf('west') !=-1) return 'west';
  return 'error';
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Draw a wall                                                          *
*                                                                                                      *
********************************************************************************************************/


function drawWall(x,y,side,color){
      x--; y = streets-y;
      world.setColor(color);
      world.setStroke(1);
      switch (side){
	   case 'west': world.fillRect(x*cellSize,y*cellSize,2,cellSize); break;
	   case 'south': world.fillRect(x*cellSize,(y+1)*cellSize,cellSize,2); break;    
         default:break; 
	}
      world.paint();
}
function deleteWall(x,y,side,color){
      x--; y = streets-y;
      world.setColor("white");
      world.setStroke(1);
      switch (side){
	   case 'west': 	world.fillRect(x*cellSize,y*cellSize,2,cellSize); 
                      	world.setColor("gainsboro");
			    	world.fillRect(x*cellSize,y*cellSize,1,cellSize); break;
	   case 'south': 	world.fillRect(x*cellSize,(y+1)*cellSize,cellSize,2); 
				world.setColor("gainsboro");
			    	world.fillRect(x*cellSize,(y+1)*cellSize,cellSize,1); break;    
         default:break; 
	}
      world.paint();
}


/*******************************************************************************************************
*                                                                                                      *
*                                 Draw a number of walls - randomly distributed                        *
*                                                                                                      *
********************************************************************************************************/

function randomWalls(number){
  for(j = 0; j < number; j++)
  {
    x = Math.floor(Math.random()*avenues);
    y = Math.floor(Math.random()*streets);
    s = Math.floor(Math.random()*2);
    number  = Math.floor(number);
    if( (x==0 && s==1) || ( y==0 && s==0)) continue;
    switch(s){
      case 0: side = "south";break;
      case 1: side = "west";break;
      default: break;
    }
    wall = "wall:("+(x+1)+","+(y+1)+")"+side;
    if(worldMap.indexOf(wall) == -1) {
      drawWall(x+1,y+1,side,"gray");
      worldMap +=wall+'\n';
    }
    else j--;
  }
  consoleWrite(number+ " walls generated");
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Clear World                                                          *
*                                                                                                      *
********************************************************************************************************/


function clearWorld(){
newWorld();
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Clear console                                                        *
*                                                                                                      *
********************************************************************************************************/


function clearConsole(){
  document.getElementById('console').value="";
}

/*******************************************************************************************************
*                                                                                                      *
*                                 World Design                                                         *
*                                                                                                      *
********************************************************************************************************/
function changeMap(e){
  
  mouseX = e.pageX;
  mouseY = e.pageY;
  x=mouseX-(progSize+20); 
  y=cellSize*streets+63-mouseY;
  //alert(x+','+y);
  if( x > worldSize || x < 0) return;
  if( y > worldSize || y < 0) return;
  switch(design){
    case "Walls": newWall(x,y);break;
    case "Beepers": newBeeper(x,y);break;
    default: break;
  }
}
function newBeeper(x,y){
  xb = Math.floor(x/cellSize);
  yb = Math.floor(y/cellSize);
  oldX = karelX; oldY = karelY;
  karelX= xb; karelY=yb;
  putBeeperM();
  karelX=oldX;
  karelY=oldY
}

function makeBeeper(x,y){
  oldX = karelX; oldY = karelY;
  karelX= x; karelY=y;
  putrunBeeper();
  karelX=oldX;
  karelY=oldY;
}

function newWall(x,y){
     xb = Math.floor(x/cellSize);
     yb = Math.floor(y/cellSize);
     dwest = x-xb*cellSize;
     deast = (xb+1)*cellSize - x;
     dnorth = (yb+1)*cellSize-y;
     dsouth = y-yb*cellSize;
     min=Math.min(Math.min(dwest,deast),Math.min(dsouth,dnorth));
     if(min == deast) { xb++;side="west";}
        else if(min == dwest) side="west";
             else if(min == dsouth) side="south";
                  else {yb++;side="south";}
    wall = "wall:("+(xb+1)+","+(yb+1)+")"+side;    
    if(worldMap.indexOf(wall) == -1) {worldMap +=wall+'\n'; drawWall(xb+1,yb+1,side,"gray");}
    else { worldMap = worldMap.replace(wall,'');deleteWall(xb+1,yb+1,side,"gainsboro");}      
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Random paint                                                         *
*                                                                                                      *
********************************************************************************************************/

function randomPaint(){
  
  if(stop) {stop = false; return;}
  toDo = Math.floor(Math.random()*100) % 6;
  n = Math.floor(Math.random()*100)%140
  color = document.getElementById('colors').options[n].value;
  switch (toDo){
    case 0: if(frontIsClear()) move();
            else turnLeft();
            break;
    case 1: turnLeft();break;
    case 2: paintCorner(color);break;
    default: if(frontIsClear()) move();
            else turnLeft();
            break;

  }
  myT = setTimeout("randomPaint()",50+100/speed);
}
/*******************************************************************************************************
*                                                                                                      *
*                                 Random print                                                         *
*                                                                                                      *
********************************************************************************************************/

function randomPrint(){
  
  if(stop) {stop = false; letters = new Array(2500);for(i=0; i < 2500; i++) letters[i] = "";return;}
  toDo = Math.floor(Math.random()*7);
  char = Math.floor(Math.random()*52-1);
  char = karelAlphabet.substr(char, 1);
  switch (toDo){
    case 0: if(frontIsClear()) move();
            else turnLeft();
            break;
    case 1: turnLeft(); break;
    case 2:
    case 3:
    case 4:
    case 5: if(letters[karelX*avenues+karelY] == "") {
			printCorner(char);
			letters[karelX*avenues+karelY]=char;
                        if(frontIsClear()) move();
                        else turnLeft();
            }
            break;
    case 6:
            if(letters[karelX*avenues+karelY] != "") {
                  world.setColor("white");
		  world.fillRect(cellSize*karelX+2,(streets-karelY-1)*cellSize+2,cellSize-4,cellSize-4);
                  world.paint();
		  letters[karelX*avenues+karelY]="";
                  redrawKarel();
            }
            break;
    default: if(frontIsClear()) move();
            else turnLeft();
            break;

  }
  myT = setTimeout("randomPrint()",50+100/speed);
}

/*******************************************************************************************************
*                                                                                                      *
*                                 Random walk                                                          *
*                                                                                                      *
********************************************************************************************************/


function randomWalk(){
  if(stop) {stop = false; return;}
  ran=Math.floor(Math.random()*13);
  showStatus();
  if(ran < 8) {
	if(frontIsClear()) move();
      else turnLeft();
  }      
  else turnLeft();
  myT = setTimeout("randomWalk()",100/speed);
}
/*******************************************************************************************************
*                                                                                                      *
*                                 Random beepers                                                         *
*                                                                                                      *
********************************************************************************************************/

function randomBeepers(number){
  saveX=karelX;
  saveY=karelY;
  for(j = 0; j < number; j++)
  {
    karelX = Math.floor(Math.random()*avenues);
    karelY = Math.floor(Math.random()*streets);
    size = Math.floor(cellSize/5);
    if(size < 2) size=2;
    disp = Math.floor(cellSize/5);
   
    if (!beepersPresent())
    {
      beeperName="T"+karelX+"_"+karelY;
      world.drawBeeper(karelX,karelY,size,size)
      world.paint();
    }  
    addBeeper(); 
    beepers[karelY*avenues+karelX]++;
  }
  karelX=saveX;
  karelY=saveY;
  consoleWrite(number+" beepers generated");
}

function compileWorld(){

 document.getElementById('program').value = worldMap; 
 curProgram = 'map';


}

function ChangeWorld(a,s){

   avenues = a;
   streets = s;
   world.clear();
   initWorld();

}