var FIELDWIDTH = 20;
var FIELDHEIGHT = 20;

var BLOCK_EMPTY       = 0;
var BLOCK_USER        = 1;
var BLOCK_TARGET      = 2;
var BLOCK_CRATE       = 4;
var BLOCK_WALL        = 8;
var BLOCK_NOSHOW      = 9;

var DIR_NULL  = -1;
var DIR_UP    =  0;
var DIR_DOWN  =  1;
var DIR_LEFT  =  2;
var DIR_RIGHT =  3;
var DIR_PUSH  =  4;

function USER()
{
	this.x = 0;
	this.y = 0;
}

function SOKOBAN()
{
	this.field = new FIELD();
	this.user = new USER();
	this.key_left  = CookieRead("MooverKey_LEFT")==null?37:parseInt(CookieRead("MooverKey_LEFT"));
	this.key_up    = CookieRead("MooverKey_UP")==null?38:parseInt(CookieRead("MooverKey_UP"));
	this.key_right = CookieRead("MooverKey_RIGHT")==null?39:parseInt(CookieRead("MooverKey_RIGHT"));
	this.key_down  = CookieRead("MooverKey_DOWN")==null?40:parseInt(CookieRead("MooverKey_DOWN"));
	this.key_undo  = CookieRead("MooverKey_UNDO")==null?85:parseInt(CookieRead("MooverKey_UNDO"));
	this.key_redo  = CookieRead("MooverKey_REDO")==null?79:parseInt(CookieRead("MooverKey_REDO"));
	this.key_reset = CookieRead("MooverKey_RESET")==null?27:parseInt(CookieRead("MooverKey_RESET"));
	this.movelist         = '';
	this.undolist         = '';
	this.moves            = 0;
	this.pushes           = 0;
	this.displaymoves     = this.moves;
	this.displaypushes    = this.pushes;
	this.cowblinktimer    = 0;
	this.cowpicture       = new Array();
	this.movespan         = undefined;
	this.pushspan         = undefined;
	this.bestmovespanmove = undefined;
	this.bestmovespanpush = undefined;
	this.bestmovenamespan = undefined;
	this.bestmovedatespan = undefined;
	this.bestpushspanmove = undefined;
	this.bestpushspanpush = undefined;
	this.bestpushnamespan = undefined;
	this.bestpushdatespan = undefined;
}

/*****************************************************************************/

SOKOBAN.prototype.fillinside = function fillinside()
{
	for(var i=0;i<this.field.data.length;i++) if(this.field.data[i]==0) this.field.data[i]=BLOCK_NOSHOW;
	for(var i=0;i<this.field.view.length;i++) game.field.view[i]=-2;
	this.recursivefill(this.user.x,this.user.y);
}

/*****************************************************************************/

SOKOBAN.prototype.recursivefill = function recursivefill(x,y)
{
	if(this.field.data[x+(y*FIELDHEIGHT)]==BLOCK_NOSHOW) this.field.data[x+(y*FIELDHEIGHT)]=0;
	this.field.view[x+(y*FIELDHEIGHT)]=-1;
	if(x>0)            if(this.field.data[(x-1) +  (y   *FIELDHEIGHT)]!=8 && this.field.view[(x-1) +  (y   *FIELDHEIGHT)]==-2) this.recursivefill(x-1,y  );
	if(y>0)            if(this.field.data[ x    + ((y-1)*FIELDHEIGHT)]!=8 && this.field.view[ x    + ((y-1)*FIELDHEIGHT)]==-2) this.recursivefill(x  ,y-1);
	if(x+1<FIELDWIDTH) if(this.field.data[(x+1) +  (y   *FIELDHEIGHT)]!=8 && this.field.view[(x+1) +  (y   *FIELDHEIGHT)]==-2) this.recursivefill(x+1,y  );
	if(y+1<FIELDWIDTH) if(this.field.data[ x    + ((y+1)*FIELDHEIGHT)]!=8 && this.field.view[ x    + ((y+1)*FIELDHEIGHT)]==-2) this.recursivefill(x  ,y+1);
}

/*****************************************************************************/

FIELD.prototype.putsquare = function putsquare(x, y, c)
{
	this.image[x+(y*this.width)].src = IMAGES[c].src;
	
}

/*****************************************************************************/

SOKOBAN.prototype.moveuser = function moveuser(dir)
{
	//0:up,1:down,2:left,3:right
	var dx,dy,ddx,ddy;
	var oldblock,newblock,sunblock;
	var moveresult=DIR_NULL;
	dir&=~DIR_PUSH;
	oldblock = (dx=this.user.x)+((dy=this.user.y)*FIELDHEIGHT);
	if(dir==DIR_UP    && dy>0          ) dy--;
	if(dir==DIR_DOWN  && dy<FIELDHEIGHT) dy++;
	if(dir==DIR_LEFT  && dx>0          ) dx--;
	if(dir==DIR_RIGHT && dx<FIELDWIDTH ) dx++;
	newblock = (ddx=dx)+((ddy=dy)*FIELDHEIGHT);
	if(this.field.data[newblock]==BLOCK_EMPTY || this.field.data[newblock]==BLOCK_TARGET)
	{
		this.field.data[oldblock]^=BLOCK_USER;
		this.field.data[newblock]|=BLOCK_USER;
		moveresult=dir;
	} else {
		if(this.field.data[newblock]&BLOCK_CRATE)	
		{
			if(dir==DIR_UP    && ddy>0          ) ddy--;
			if(dir==DIR_DOWN  && ddy<FIELDHEIGHT) ddy++;
			if(dir==DIR_LEFT  && ddx>0          ) ddx--;
			if(dir==DIR_RIGHT && ddx<FIELDWIDTH ) ddx++;
			sunblock = ddx+(ddy*FIELDHEIGHT);
			if(this.field.data[sunblock]==BLOCK_EMPTY || this.field.data[sunblock]==BLOCK_TARGET)
			{
				moveresult=dir+DIR_PUSH;
				this.field.data[oldblock]^=BLOCK_USER;
				this.field.data[newblock]|=BLOCK_USER;
				this.field.data[newblock]^=BLOCK_CRATE;
				this.field.data[sunblock]|=BLOCK_CRATE;
			}
		}
	}
	if(moveresult!=DIR_NULL) 
	{
		this.user.x = dx;
		this.user.y = dy;
	}
	return moveresult;
}

/*****************************************************************************/

SOKOBAN.prototype.undomove = function undomove(dir)
{
	if(!this.movelist.length) return 0;
	var lastmove = parseInt(right(this.movelist,1));
	var dx,dy,oldblock,newblock,sunblock;
	oldblock = dx=this.user.x+((dy=this.user.y)*FIELDHEIGHT);
	if(lastmove&DIR_PUSH)
	{
		newblock = (dx=this.user.x)+((dy=this.user.y)*FIELDHEIGHT);
		if(lastmove==(DIR_PUSH|DIR_UP))    dy--,this.moveuser(DIR_DOWN);
		if(lastmove==(DIR_PUSH|DIR_DOWN))  dy++,this.moveuser(DIR_UP);
		if(lastmove==(DIR_PUSH|DIR_LEFT))  dx--,this.moveuser(DIR_RIGHT);
		if(lastmove==(DIR_PUSH|DIR_RIGHT)) dx++,this.moveuser(DIR_LEFT);
		oldblock = dx+(dy*FIELDHEIGHT);
		this.field.data[oldblock]^=BLOCK_CRATE;
		this.field.data[newblock]|=BLOCK_CRATE;
	} else {
		if(lastmove==DIR_UP)    this.moveuser(DIR_DOWN);
		if(lastmove==DIR_DOWN)  this.moveuser(DIR_UP);
		if(lastmove==DIR_LEFT)  this.moveuser(DIR_RIGHT);
		if(lastmove==DIR_RIGHT) this.moveuser(DIR_LEFT);
	}
	this.undolist+=lastmove;
	if(lastmove&DIR_PUSH) game.pushes--;--game.moves;
	this.movelist=left(this.movelist,this.movelist.length-1);
	return 1;
}

/*****************************************************************************/

SOKOBAN.prototype.redomove = function redomove()
{
	if(!this.undolist.length) return 0;
	var lastundo = parseInt(right(this.undolist,1));
	m=game.moveuser(lastundo);
	if(m!=DIR_NULL) game.movelist+=m.toString();
	if(m&DIR_PUSH) game.pushes++;++game.moves;
	this.undolist=left(this.undolist,this.undolist.length-1);
}

SOKOBAN.prototype.fillinfobox = function fillinfobox()
{
	var buffer='';
	buffer+="<div style='border:1px solid black;background:#FFFFFF;'><a href='http://www.bitbar.org/moover/'><img id=cow1 src='./images/happycow1.jpg' style='display:none;' border=0><img id=cow2 src='./images/happycow2.jpg' style='display:inline;' border=0><img src='./images/moover.jpg' border=0></a></div>";
	buffer+="<div style='border:1px solid black;height:4;font:3px Tahoma;'></div>";
	buffer+="<div style='border:1px solid black;'>Level Number: <b><span id=levelnumber>"+LEVEL_NUMBER+"</span></b></div>";
	if(LEVEL_PASSWORD!="") buffer+="<div style='border:1px solid black;'>Level Password: <span id=levelpassword>"+LEVEL_PASSWORD+"</span></div>";
	buffer+="<div style='border:1px solid black;'>Current Moove Count: <span id=movespan>0</span></div>";
	buffer+="<div style='border:1px solid black;'>Current Push Count: <span id=pushspan>0</span></div>";
	buffer+="<div style='border:1px solid black;height:6;font:3px Tahoma;'></div>";
	buffer+="<div style='border:1px solid black;'>Least Mooves Record: <span id=bestmovespanmove>none</span></div>";
	buffer+="<div style='border:1px solid black;'>Least Pushes Record: <span id=bestpushspanpush>none</span></div>";
	buffer+="<div style='border:1px solid black;height:6;font:3px Tahoma'></div>";
	buffer+="<div style='border:1px solid black;'><input type=text id=moveoutput style='display:none;width:100%;border:1px solid #663333' onfocus=\"this.style.border='1px solid #CC6666';this.style.color='#EEEEEE';\" onblur=\"this.style.border='1px solid #663333';this.style.color='#888888';\"></div>";
	buffer+="<div style='border:1px solid black;'><input type=text id=moveinput  style='display:none;width:100%;border:1px solid #333366' onfocus=\"this.style.border='1px solid #6666CC';this.style.color='#EEEEEE';\" onblur=\"this.style.border='1px solid #333366';this.style.color='#888888';\"></div>";
	this.field.messageframe.innerHTML = buffer;
	this.cowpicture[0]    = document.getElementById('cow1');
	this.cowpicture[1]    = document.getElementById('cow2');
	this.movespan         = document.getElementById('movespan');
	this.pushspan         = document.getElementById('pushspan');
	this.bestmovespanmove = document.getElementById('bestmovespanmove');
	this.bestpushspanpush = document.getElementById('bestpushspanpush');
	this.moveinput        = document.getElementById('moveinput');
	this.moveoutput       = document.getElementById('moveoutput');
	
	this.bestmovespanmove.innerHTML = RECORD_MOVE_MOVE>0?RECORD_MOVE_MOVE:'none';
	this.bestpushspanpush.innerHTML = RECORD_PUSH_PUSH>0?RECORD_PUSH_PUSH:'none';
}

/*****************************************************************************/

SOKOBAN.prototype.gamecomplete = function gamecomplete()
{
	var i;
	for(i=0;i<this.field.height*this.field.width;i++) if(this.field.data[i]==BLOCK_TARGET || this.field.data[i]==BLOCK_CRATE) return 0;
	return 1;
}

/*****************************************************************************/

SOKOBAN.prototype.completemessage = function completemessage()
{
	var buffer="";
	var moverecord=0;
	var pushrecord=0;
	var message="";
	if(!RECORD_MOVE_MOVE||(RECORD_MOVE_MOVE>game.moves)) moverecord=1;
	if(!RECORD_PUSH_PUSH||(RECORD_PUSH_PUSH>game.pushes)) pushrecord=1;
	switch(moverecord+pushrecord*2)
	{
		case 0: message = "Congratulations! You have completed the level. Click 'OK' to proceed to the next level."; break;
		case 1: message = "Congratulations! You have set a new record for this level by completing it with the fewest moves. Please enter your name in the box below to submit your score and proceed to the next level."; break;
		case 2: message = "Congratulations! You have set a new record for this level by completing it with the fewest pushes. Please enter your name in the box below to submit your score and proceed to the next level."; break;
		case 3: message = "Congratulations! You have set a new record for this level by completing it with the fewest moves and fewest pushes. Please enter your name in the box below to submit your score and proceed to the next level."; break;
	}
	if(moverecord+pushrecord) this.field.createinputbox(250,130); else this.field.createinputbox(250,85);
	buffer += "<form method=post action=garbage.php>";
	buffer += "<table width=100% height=100% border=0 cellspacing=0 cellpadding=10>";
	buffer += "<tr>";
	buffer += "<td align=justify valign=middle colspan=2>";
	buffer += message;
	buffer += "</td>"
	buffer += "</tr>";
	buffer += "<tr>";
	if(moverecord+pushrecord) buffer += "<td align=center valign=middle>";
	if(moverecord+pushrecord) buffer += "<input type=text name=playername value='Anonymous' size=25 onfocus=\"this.style.border='1px solid #DDDDDD';this.style.color='#EEEEEE';\" onblur=\"this.style.border='1px solid #888888';this.style.color='#888888';\">";
	if(moverecord+pushrecord) buffer += "</td>"
	if(moverecord+pushrecord) buffer += "<td align=center valign=middle>"; else buffer += "<td align=center valign=middle colspan=2>";
	buffer += "<input type=hidden name=movedata value='" + game.movelist + "'>";
	buffer += "<input type=hidden name=levelnumber value='" + LEVEL_NUMBER + "'>";
	buffer += "<input type=submit value='  OK  ' onfocus=\"this.style.border='1px solid #DDDDDD';this.style.color='#EEEEEE';\" onblur=\"this.style.border='1px solid #888888';this.style.color='#888888';\" onmouseover=\"this.style.border='1px solid #DDDDDD';this.style.color='#EEEEEE';\" onmouseout=\"this.style.border='1px solid #888888';this.style.color='#888888';\">";
	buffer += "</td>"
	buffer += "</tr>";
	buffer += "</table>";
	buffer += "</form>";
	this.field.inputboxinnerframe.innerHTML = buffer;
}

/*****************************************************************************/

SOKOBAN.prototype.intromessage = function intromessage()
{
	var buffer="";
	var message="Congratulations! You have reached level " + LEVEL_NUMBER + ".<br>The password for this level is '" + LEVEL_PASSWORD + "'.";
	this.field.createinputbox(250,85);
	buffer += "<table width=100% height=100% border=0 cellspacing=0 cellpadding=10>";
	buffer += "<tr>";
	buffer += "<td align=justify valign=middle colspan=2>";
	buffer += message;
	buffer += "</td>"
	buffer += "</tr>";
	buffer += "<tr>";
	buffer += "<td align=center>";
	buffer += "<input type=button value='  OK  ' onclick=\"PlaceHolder.removeChild(this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode);\" onfocus=\"this.style.border='1px solid #DDDDDD';this.style.color='#EEEEEE';\" onblur=\"this.style.border='1px solid #888888';this.style.color='#888888';\" onmouseover=\"this.style.border='1px solid #DDDDDD';this.style.color='#EEEEEE';\" onmouseout=\"this.style.border='1px solid #888888';this.style.color='#888888';\">";
	buffer += "</td>"
	buffer += "</tr>";
	buffer += "</table>";
	this.field.inputboxinnerframe.innerHTML = buffer;
}

/*****************************************************************************/

SOKOBAN.prototype.cowblink = function cowblink()
{
	if(this.cowblinktimer)
	{
		this.cowblinktimer--;
		if(!this.cowblinktimer)
		{
			this.cowpicture[0].style.display='none';
			this.cowpicture[1].style.display='inline';
		} 
	} else {
		if(!random(80)) 
		{
			this.cowblinktimer = random(7)+7;
			this.cowpicture[1].style.display='none';
			this.cowpicture[0].style.display='inline';
		}
	}
	
}

