function getmap(x,y){
    return map[y][x];
}

function setmap(x,y,c){
    //var z;
   //a z=map[y].substr(0,x)+c+map[y].substr(x+1,map[y].length-x-1);
    //alert(map[y]+"\n"+map[y]);
    //map[y]=z;
    map[y][x]=c;
}

function setmap2(x,y,c){
    map2[y][x]=c;
}


function getmax_x(){
    var max=0;
    for (var x=0;x<map.length;x++){
	if (max<map[x].length) max=map[x].length;
    }
    return max;
}

function getmax_y(){
    return map.length;
}

function isstone(c){
    if (c=='$'||c=='*') return true;
    return false;
}

function istarget(c){
    if (c=='.'||c=='*'||c=="+") return true;
    return false;
}

function iswalkable(c){
    if (c==' '||c=='.'||c=='@'||c=="+") return true;
    return false;
}

function getx(x){
    x.src=i_stone.src;
}

function log(t){
    //d.tf.ta.value=d.tf.ta.value+t+"\n";
    window.status=t;
}

function draw(x,y,type){
    var t=type;
    var c=map[y][x];
    if (istarget(c)) t=t+"_";
    eval("d.i"+x+"_"+y+".src=i_"+t+".src;");
    if (type=="stone"){
	if (istarget(c)) setmap(x,y,'*');
	else setmap(x,y,'$');
    }
    else if (type=='field'){
	if (istarget(c)) setmap(x,y,'.')
	else setmap(x,y,' ');
    }
    else if (type=='man'){
	if (istarget(c)) setmap(x,y,'+')
	else setmap(x,y,'@');
    }
    else if (type=='manani'){
	if (istarget(c)) setmap(x,y,'.')
	else setmap(x,y,' ');
    }
}

function step(direction){
    // LEFT  / 1
    // UP    / 2
    // RIGHT / 3
    // DOWN  / 4
    var newx=man[0];
    var newy=man[1];
    var oldx=man[0];
    var oldy=man[1];
    if (direction==1) newx--
    else if (direction==2) newy--;
    else if (direction==3) newx++;
    else if (direction==4) newy++;
    else{
	log("wrong direction");
	return;
    }

    if (newx<0 || newy<0 || newx>=max_x || newy>=max_y){
	log("There's no way out");
	return;
    }

    if (map[newy][newx]=="#"){
	log("Ouch! there's a wall");
	return;
    }
    var wasstone=0;
    if (isstone(map[newy][newx])){
	var newx_=newx;
	var newy_=newy;
	var oldx_=oldx;
	var oldy_=oldy;

	if (direction==1) newx_--
	else if (direction==2) newy_--;
	else if (direction==3) newx_++;
	else if (direction==4) newy_++;

	if (newx_<0 || newy_<0 || newx_>=max_x || newy_>=max_y) {
	    log("Stone to nomansland?");
	    return;
	}
	if (map[newy_][newx_]=="#"){
	    log("there's a wall!");
	    return;
	}
	if (isstone(map[newy_][newx_])){
	    log("RTFM!");
	    return;
	}
	log("I'm moving");
	if (istarget(map[newy][newx])){
	    targets_ok--;
	    log(targets_ok+" stone"+(targets_ok==1 ? "" : "s")+" of "+targets+" finished");
	}
	if (istarget(map[newy_][newx_])){
	    targets_ok++;
	    log(targets_ok+" stone"+(targets_ok==1 ? "" : "s")+" of "+targets+" finished");
	}
	draw(newx_,newy_,"stone");
	hist.push(new Array("stone", newx,newy,newx_,newy_));
	wasstone=1;
    }


    //d.tf.txt.value=key+ " GOTO: "+newx+":"+newy+" targets "+targets+" targets_ok: "+targets_ok;
    draw(oldx,oldy,"field");
    hist.push(new Array("man", oldx,oldy,newx,newy));
    draw(newx,newy,"man");
    man[0]=newx;
    man[1]=newy;
    if (targets_ok==targets){
	if (maxlevelnumber==levelnumber){
	    log("You have completed all levels in "+collectionname);
	    confirm("You have completed all levels in "+collectionname);
	    window.location.href="start.php";
	}else {
	    log("Level "+levelnumber+" in "+collectionname+" completed");
	    confirm("Level "+levelnumber+" in "+collectionname+" completed");
	    window.location.href="start.php?collection="+collectionname+"&lnr="+(levelnumber+1);
	}
    }
    if (!wasstone) log("I'm walking");
}

function keyaction(key,alt,ctrl,shift){
    //37 = LEFT         / 1
    //38 = UP           / 2
    //39 = RIGHT        / 3
    //40 = DOWN         / 4
    //48 = 0 (UNDO)
    if (istimer) return false;
    if      (key==56  || key==104 || key==38 ) step(2)
    else if (key==52  || key==100 || key==37 ) step(1)
    else if (key==54  || key==102 || key==39 ) step(3)
    else if (key==50  || key==98  || key==40 ) step(4)
    else if (key==48  || key==96  || key==85 || key==117 || key==8) undo();
    else {
	log("Key "+key+" unknown");
	return true;
    }
    return false;

}


//    moves, posX, posY, targetX, targetY
function mover(moves,xpos,ypos,_x,_y){
    var oldX=xpos;
    var oldY=ypos;
    if (runs>1000000) {
        log("MAXRUNS");
	if (!runsalerted){
	    alert("MAXRUNS");
	    runsalerted=1;
	}
        return;
    }
    runs++;
    var a;
    if (ypos-1 >= 0 && map2[ypos-1][xpos]>moves && iswalkable(map[ypos-1][xpos]) ) {
	ypos--;
	setmap2(xpos,ypos,moves);
	if (xpos == _x && ypos == _y) found=1;
	mover(moves+1,xpos,ypos,_x,_y);
    }
    xpos=oldX; ypos=oldY;
    if (ypos+1 < max_y && map2[ypos+1][xpos]>moves && iswalkable(map[ypos+1][xpos]) ) {
	ypos++;
	setmap2(xpos,ypos,moves);
	if (xpos == _x && ypos == _y) found=1;
	mover(moves+1,xpos,ypos,_x,_y);
    }
    xpos=oldX; ypos=oldY;
    if (xpos-1 >= 0 && map2[ypos][xpos-1]>moves && iswalkable(map[ypos][xpos-1]) ) {
	xpos--;
	setmap2(xpos,ypos,moves);
	if (xpos == _x && ypos == _y) found=1;
	mover(moves+1,xpos,ypos,_x,_y);
    }
    xpos=oldX; ypos=oldY;
    if (xpos+1 < max_x && map2[ypos][xpos+1]>moves && iswalkable(map[ypos][xpos+1]) ) {
	xpos++;
	setmap2(xpos,ypos,moves);
	if (xpos == _x && ypos == _y) found=1;
	mover(moves+1,xpos,ypos,_x,_y);
    }
    return;

}

function findbest(xpos,ypos){
    var best=map2[ypos][xpos];
    var xdiff=0;
    var ydiff=0;
    if (ypos-1 >= 0 && ( map2[ypos-1][xpos]<best && iswalkable(map[ypos-1][xpos]))){
	best=map2[ypos-1][xpos];
	xdiff=0; ydiff=0;
	ydiff=-1;
    }
    if (ypos+1 < max_y && (map2[ypos+1][xpos]<best && iswalkable(map[ypos+1][xpos]))){
	best=map2[ypos+1][xpos];
	xdiff=0; ydiff=0;
	ydiff=1;
    }
    if (xpos-1 >= 0 && (map2[ypos][xpos-1]<best && iswalkable(map[ypos][xpos-1])) ){
	best=map2[ypos][xpos-1];
	xdiff=0; ydiff=0;
	xdiff=-1;
    }
    if (xpos+1 < max_x && (map2[ypos][xpos+1]<best && iswalkable(map[ypos][xpos+1]) )){
	best=map2[ypos][xpos+1];
	xdiff=0; ydiff=0;
	xdiff=1;
    }
    var ret=new Array();
    if (!ret.push){
	ret.push=function (rein){ ret[ret.length]=rein; }
    }
    ret.push(xpos+xdiff);
    ret.push(ypos+ydiff);
    return ret;

}

var runs=0;
var runsalerted=0;
var found=0;
var istimer=0;
var timerID;
var timerID2;
var usetimer2=1;

function timedraw(_x,_y){
    var oldx;
    var oldy;
    var mannew;
    clearTimeout(timerID);
    if (man[0]==_x && man[1]==_y){
	draw(man[0],man[1],"man");
	istimer=0;
	return;
    }
    oldx=man[0];
    oldy=man[1];
    mannew=findbest(man[0],man[1]);
    if (mannew[0]==man[0] && mannew[1]==man[1]){
	log("findbest error");
	istimer=0;
	return;
    }
    man=mannew;
    if (useani){
	if (Netscape){
	    if (map[oldy][oldx]=="."){
		i_manani_=new Image(24,24);  i_manani_.src='img/manani_.gif?x='+Math.random();
	    } else {
		i_manani=new Image(24,24);  i_manani.src='img/manani.gif?x='+Math.random();
	    }
	}
	draw(oldx,oldy,"manani");
    }else{
	draw(oldx,oldy,"field");
	draw(man[0],man[1],"man");
    }
    if (man[0]==_x && man[1]==_y){
	draw(man[0],man[1],"man");
	istimer=0;
	return;
    }
    timerID=setTimeout("timedraw("+_x+","+_y+")",50);
}

function walkto(_x,_y,undo){
    var d=top.sok.window.document;
    var c;
    if (istimer) return;
    //d.tf.ta.value="";
    //log("walkto "+_x+", "+_y);
    //click on stone to move
    if (isstone(map[_y][_x])&&!undo){
	var ok=true;
	if      (man[0]==_x && man[1]==_y-1) step(4); // DOWN
	else if (man[0]==_x && man[1]==_y+1) step(2); // UP
	else if (man[0]==_x-1 && man[1]==_y) step(3); // RIGHT
	else if (man[0]==_x+1 && man[1]==_y) step(1); // LEFT
	else ok=false;
	if (!ok) return;

    }
    if (!iswalkable(map[_y][_x])){
	log("not possible");
	return;
    }
    map2=new Array;
    for (var y=0; y<max_y; y++){
	map2[y]=new Array();
	if (!map2.push){
	    map2.push=function (rein){ map2[map2.length]=rein; }
	}

	for (var x=0; x<max_x; x++){
	    c=map[y][x];
	    if (iswalkable(c)) map2[y].push(1000001);
	    else map2[y].push(1000002);
	}
    }

    setmap2(_x,_y,0);
    runs=0;
    runsalerted=0;
    found=0;
    //    moves, posX, posY, targetX, targetY
    mover(1,_x,_y,man[0],man[1]);
    setmap2(_x,_y,0);
    if (found==1){
	if (!undo) log("Found a way");
	if (!undo) hist.push(new Array("walk",man[0],man[1],_x,_y));
	istimer=1;
	timerID=setTimeout("timedraw("+_x+","+_y+")",10);
	d.f2.lnr.focus(); /* avoid ugly selected image */
    } else {
	log("Impossible");
    }
    return;

}

function undo(){
    var hl=hist.length-1;
    var x1; var y1; var x2; var y2;

    if (hl>=0){
	log("UNDO");
	//log("Hist: "+hist[hl][0]+","+hist[hl][1]+","+hist[hl][2]+","+hist[hl][3]+","+hist[hl][4]);
	if (hist[hl][0]=="man"){
	    draw(hist[hl][3],hist[hl][4],"field");
	    man[0]=hist[hl][1];
	    man[1]=hist[hl][2];
	    draw(man[0],man[1],"man");
	    hist.pop();
	    hl=hist.length-1;
	    if (hl>=0 && hist[hl][0]=="stone"){
		x1=hist[hl][1];
		y1=hist[hl][2];
		x2=hist[hl][3];
		y2=hist[hl][4];
		if (istarget(map[y2][x2])) targets_ok--;
		if (istarget(map[y1][x1])) targets_ok++;
		draw(x2,y2,"field");
		draw(x1,y1,"stone");
		hist.pop();
	    }
	} else {
	    if (hist[hl][0]=="walk"){
		walkto(hist[hl][1],hist[hl][2], true);
		hist.pop();
	    }
	}


    } else log("Nothing in history");
}

function write_table(d,width,height){
    var c;
    var out;
    d.writeln("<table cellpadding=0 cellspacing=0 border=0>");
    for (var y=0;y<height;y++){
	d.writeln("<TR>");
	log("rendering line "+(y+1)+" of "+height);
	for (var x=0;x<width;x++){
	    d.write("<TD width=24 height=24>");
	    c=map[y][x];
	    if (!c || c==' ') out="field";
	    else if (c=='#') out="wall";
	    else if (c=='$') out="stone";
	    else if (c=='.') { out="field_"; targets++; }
	    else if (c=='*') { out="stone_"; targets++; targets_ok++; }
	    else if (c=='@'){
		man[0]=x;
		man[1]=y;
		out="man";
	    }
	    else if (c=='+'){
		man[0]=x;
		man[1]=y;
		out="man_";
		targets++;
	    }

	    //d.write("<IMG onclick=\"walkto("+x+","+y+",false);return(false);\" name=\"i"+x+"_"+y+"\" src=\"img/"+out+".png\">");
	    d.write("<A href=\"#\" onclick=\"walkto("+x+","+y+",false);return(false);\"> <img border=0 name=\"i"+x+"_"+y+"\" src=\"img/"+out+".png\" width=24 height=24 ></A>");
	    d.writeln("</TD>");
	}
	d.writeln("</TR>");
    }
    d.writeln("</TABLE>");
}

function forminput(timer){
    //37 = LEFT         / 1
    //38 = UP           / 2
    //39 = RIGHT        / 3
    //40 = DOWN         / 4
    //48 = 0 (UNDO)

    alert('x');
    if (timer) clearTimeout(timerID2);
    var val=d.tf.txt.value;
    for (var a=0;a<val.length;a++){
	if (val[a]=="8") step(2);
	else if (val[a]=="4") step(1);
	else if (val[a]=="6") step(3);
	else if (val[a]=="2") step(4);
	else if (val[a]=="0" || val[a]=="u") undo();
	window.status=window.status+val[a];
    }
    d.tf.txt.value="";
    if (timer){
	timerID2=setTimeout("forminput(true)",1000);
    }
    alert('y');
}

function ns4timer(){
    clearTimeout(timerID2);
    if (usetimer2==1){
	window.focus();
	d.tf.txt.focus();
    }
    timerID2=setTimeout("ns4timer()",10);
}
function newgame(){
    var a;
    log("Initializing...");
    d.clear();
    d.close();
    d.open("text/html");
    d.clear();
    d.writeln("<HTML>");
    d.writeln("<HEAD>");
    d.writeln("<TITLE>JSokoban</TITLE>");
    d.writeln("</HEAD>");
    d.writeln("<BODY BGCOLOR=white >");
    d.writeln("<center>");
    d.writeln("<font face=\"Arial,Helvetica\"><BR>");
    d.writeln("<H1>JSokoban</H1>");
    d.writeln("Full featured Sokoban written in JavaScript<BR><BR>");
    //d.writeln("Collection: "+collectionname+" ");
    //d.writeln("Level: "+levelnumber+"/"+maxlevelnumber+"<BR>");
    //d.writeln("<BR>");
    d.writeln("");
    write_table(d,max_x,max_y);
    d.writeln("<BR>");
    if ((Netscape && navigatorversion<5 ) || Opera || Konqueror){
	d.writeln("<table border=0 cellpadding=2 cellspacing=2 bgcolor=black>");
	d.writeln("<tr bgcolor=black><td bgcolor=white>8</td><td bgcolor=white>UP</td></tr>");
	d.writeln("<tr bgcolor=black><td bgcolor=white>4</td><td bgcolor=white>LEFT</td></tr>");
	d.writeln("<tr bgcolor=black><td bgcolor=white>6</td><td bgcolor=white>RIGHT</td></tr>");
	d.writeln("<tr bgcolor=black><td bgcolor=white>2</td><td bgcolor=white>DOWN</td></tr>");
	d.writeln("<tr bgcolor=black><td bgcolor=white>0</td><td bgcolor=white>UNDO</td></tr>");
	d.writeln("</table>");
	d.writeln("<BR>");
	d.writeln("<form name=\"tf\" action=\"start.php\">");
	d.writeln("MovingInput: <input type=text name=txt size=1 onChange=\"forminput(false)\"><BR>");
	d.writeln("<input type=checkbox checked name=chk onClick=\"usetimer2=d.tf.chk.checked\">Turn off auto-read");
	timerID2=setTimeout("ns4timer()",10);
	d.writeln("<input type=submit value=\" \">");
	d.writeln("</form>");
	top.window.onBlur=new Function("usetimer2=0");
	top.window.onFocus=new Function("usetimer2=1");
    }
    
    d.writeln("<table border=0 cellpadding=2 cellspacing=2 bgcolor=black>");
    d.writeln("<form name=f2 action=\"start.php\">");
    d.writeln("<tr bgcolor=black>");
    d.writeln("<td bgcolor=white>");
    d.writeln("Level:</td><td bgcolor=white>");
    d.writeln("<input type=hidden name=collection value=\""+collectionname+"\">");
    d.writeln("<select name=lnr size=1>");
    for (a=1;a<=maxlevelnumber;a++){
	d.write("<option value=\""+a+"\"");
	if (a==levelnumber) d.write(" selected");
	d.writeln(">"+a);
    }		    
    d.writeln("</select> ");
    d.writeln("</td>");
    d.writeln("<td bgcolor=white>");
    d.writeln("<input type=submit value=\" GO \" onSubmit=\"usetimer2=0\">");
    d.writeln("</td></tr>");
    d.writeln("</form>");
    d.writeln("<form name=f3 action=\"start.php\">");
    d.writeln("<tr bgcolor=black>");
    d.writeln("<td bgcolor=white>");
    d.writeln("Collection:</td><td bgcolor=white>");

    //d.writeln("<input type=text name=txt size=100>");
    //d.writeln("<textarea name=ta cols=120 rows=25></textarea>");
    d.writeln("<select name=collection size=1>");
    for (a=0;a<collections.length;a++){
	d.write("<option value=\""+collections[a]+"\"");
	if (collections[a]==collectionname) d.write(" selected");
	d.writeln(">"+collections[a]);
    }		    
    d.writeln("</select> ");
    d.writeln("</td>");
    d.writeln("<td bgcolor=white>");
    d.writeln("<input type=submit value=\" GO \" onSubmit=\"usetimer2=0\">");
    d.writeln("</td></tr>");
    d.writeln("</form>");
    d.writeln("</table>");
    d.writeln("<BR>");
    d.writeln("&copy; 2003 by <A href=\"http://www.ashberg.de/\" target=\"_TOP\">Folke Ashberg</A><BR>");
    d.writeln("<SMALL>");
    d.writeln("Grapics &quot;stolen&quot; from OpenSource <A href=\"http://hem.passagen.se/awl/ksokoban/\" target=_blank>ksokoban</A><BR>");
    d.writeln("JSokoban has been written completely in JavaScript<BR>");
    d.writeln("JSokoban has been tested with Netscape 4.7X, Mozilla, Firefox and Internet Explorer 5, 5.5, 6, 7<BR>");
    d.writeln("Keys: u: undo / arrow-keys or 8,4,6,2: move / mouse: auto-walk<BR>");
    d.writeln("</SMALL>");
    d.writeln("</font>");
    d.writeln("</center>");
    d.writeln("</body>");
    d.writeln("</html>");
    d.close();
    log("initialized");
    top.sok.window.focus();
}


var map2=new Array;
var d=top.sok.window.document;
var man=new Array();

var i_stone=new Image(24,24);   i_stone.src='img/stone.png';
var i_field=new Image;   i_field.src='img/field.png';
var i_man=new Image;     i_man.src='img/man.png';
var i_wall=new Image;    i_wall.src='img/wall.png';
var i_stone_=new Image;  i_stone_.src='img/stone_.png';
var i_field_=new Image;  i_field_.src='img/field_.png';
var i_man_=new Image;    i_man_.src='img/man_.png';
var i_manani=new Image;  i_manani.src='img/manani.gif';
var i_manani_=new Image; i_manani_.src='img/manani_.gif';
var max_x=getmax_x();
var max_y=getmax_y();
var targets=0;
var targets_ok=0;
var hist=new Array();
if (!hist.push){
    hist.push=function (rein){ 	hist[hist.length]=rein;  }
}
//TODO: pop ?

var useani=1;



