 /* sliding block puzzle 
  * (c)2006 Puzzle Genie admim_AT_puzzlegenie_DOT_com
  * For a commercial license, please contact the 
  * email address above.
  */ 

 /* Graphics */
 blank=new Image(2,2);
 blank.src="/games/fourbyfive/img/blank.png";
 emptyblock=new Image(50,50);
 emptyblock.src="/games/fourbyfive/img/emptyblock.png"
 selection=new Image(50,50);
 selection.src="/games/fourbyfive/img/selection.png";
 redblock=new Image(100,100);
 redblock.src="/games/fourbyfive/img/redblock.png";
 blueblockh=new Image(100,50);
 blueblockh.src="/games/fourbyfive/img/blueblockh.png";
 blueblockv=new Image(50,100);
 blueblockv.src="/games/fourbyfive/img/blueblockv.png";

 redblocktl=new Image(50,50);  // symbol R
 redblocktl.src="/games/fourbyfive/img/redblockTL.png";
 redblocktr=new Image(50,50);  // symbol r
 redblocktr.src="/games/fourbyfive/img/redblockTR.png";
 redblockbl=new Image(50,50);  // symbol S
 redblockbl.src="/games/fourbyfive/img/redblockBL.png";
 redblockbr=new Image(50,50);  // symbol s
 redblockbr.src="/games/fourbyfive/img/redblockBR.png";
 blueblockhl=new Image(50,50); // symbol H
 blueblockhl.src="/games/fourbyfive/img/blueblockHL.png";
 blueblockhr=new Image(50,50); // symbol h
 blueblockhr.src="/games/fourbyfive/img/blueblockHR.png";
 blueblockvt=new Image(50,100); // symbols V
 blueblockvt.src="/games/fourbyfive/img/blueblockVT.png";
 blueblockvb=new Image(50,100); // symbols v
 blueblockvb.src="/games/fourbyfive/img/blueblockVB.png";
 greenblock=new Image(40,40);  // symbol G
 greenblock.src="/games/fourbyfive/img/greenblock.png";

 /* browser detect */	
 var ua = navigator.userAgent.toLowerCase();
 var isOpera = (ua.indexOf('opera') != -1);
 var isIE7 = (ua.indexOf('msie 7') != -1)
 var isOldIE = (ua.indexOf('msie') != -1 && !isOpera && !isIE7);

 /* Animated Dixie */
 YAHOO.namespace('puzzpix.anim');
 YAHOO.puzzpix.anim.init = function() {
   var tendPoint = YAHOO.util.Dom.getXY('tend');
   var tattributes = {
      points: {
         to: tendPoint,
         control: [ [brWidth+380, 600], [-100, 200] ]
      },
      width: {by: 255},
      height: {by: 394}
   }

   tanim = new YAHOO.util.Motion('dixie', tattributes, 1, YAHOO.util.Easing.easeIn);
   tanim.animate();
 }

 /* Game object */
 var currgame;
 var cols = 4;
 var rows = 5;
 var MOVELEFT = 1;
 var MOVERIGHT = 2;
 var MOVEUP = 4;
 var MOVEDOWN = 8;

 function gameObj(start,finish){
	this.state = start;
	this.solution = finish;
	this.over = false;
	this.timer = 0;
	this.incTimer = incTimer;
	this.timeNow = timeNow;
	this.reset = gameReset;
	this.updateImage = drawBoard;
	this.drawSolution = drawSolution;
	this.isFree = checkStateFree;
	this.content = getContent;
	this.setContent = setContent;
	this.checkMove = checkMove;
	this.moveBlock = moveBlock;
	this.checkWin = checkWin;
 }

 function gameReset(start,finish){
	this.state = start;
	this.solution = finish;
	this.over = false;
	this.timer = 0;
	this.updateImage();
 }
 
 function checkWin(){
	for (var i=0; i<this.state.length; i++){
		if (this.state.charAt(i) != this.solution.charAt(i) && this.solution.charAt(i) != '*')
			return false;
	}
	return true;
 }

 function checkStateFree(row,col){
	return (this.content(row,col) == 'X' );
 }

 function getContent(row,col){
	if (row < 0 || row >= rows || col < 0 || col >= cols){
		return '-';//OOB
	}
	return ( this.state.charAt(row*cols + col) );
 }

 function setContent(row,col,lett){
	var stpos = row*cols + col;
	var t1='', t2='';
	if (stpos != 0)
		t1 = this.state.substr(0, stpos);
	if (stpos != (this.state.length-1))
		t2 = this.state.substr(stpos+1);
	this.state = t1+lett+t2;
 }

 function incTimer(){
	this.timer ++;
	if (this.timer > 356400)
		this.timer = 356400; // 99 hours!
 }

 function timeNow(){
    var hour = Math.floor(this.timer / 3600);
	var min = Math.floor( (this.timer - (3600*hour)) / 60);
	var sec = this.timer - (3600*hour) - (60*min);
	var ts = ((hour < 10) ? "0" : "") + hour;
		ts += ((min < 10) ? ":0" : ":") + min;
	    ts += ((sec < 10) ? ":0" : ":") + sec;
	return ts;
 }
 
 function checkMove(row, col){
	var lett = this.content(row, col);
	var retval = 0;
	var dof = 0;

	if (lett == 'r') {
		col -= 1;
		lett = 'R';
	} else if (lett == 'S'){
		row -= 1;
		lett = 'R';
	} else if (lett == 's'){
		row -= 1;
		col -= 1;
		lett = 'R';
	} else if (lett == 'h'){
		col -= 1;
		lett = 'H';
	} else if (lett == 'v'){
		row -= 1;
		lett = 'V';
	}

	if (lett == 'R'){
		if (this.isFree(row, col-1) && this.isFree(row+1, col-1)) 
			retval |= MOVELEFT;
		if (this.isFree(row, col+2) && this.isFree(row+1, col+2)) 
			retval |= MOVERIGHT;
		if (this.isFree(row-1, col) && this.isFree(row-1, col+1)) 
			retval |= MOVEUP;
		if (this.isFree(row+2, col) && this.isFree(row+2, col+1)) 
			retval |= MOVEDOWN;
	} else if (lett == 'H'){
		if (this.isFree(row, col-1))
            retval |= MOVELEFT;
		if (this.isFree(row, col+2))
            retval |= MOVERIGHT;
		if (this.isFree(row-1, col) && this.isFree(row-1, col+1))
			retval |= MOVEUP;
		if (this.isFree(row+1, col) && this.isFree(row+1, col+1))
			retval |= MOVEDOWN;
	} else if (lett == 'V'){
		if (this.isFree(row, col-1) && this.isFree(row+1, col-1))
            retval |= MOVELEFT;
		if (this.isFree(row, col+1) && this.isFree(row+1, col+1))
            retval |= MOVERIGHT;
		if (this.isFree(row-1, col))
			retval |= MOVEUP;
		if (this.isFree(row+2, col))
			retval |= MOVEDOWN;
	} else if (lett == 'G'){
		if (this.isFree(row, col-1))
            retval |= MOVELEFT;
		if (this.isFree(row, col+1))
            retval |= MOVERIGHT;
		if (this.isFree(row-1, col))
			retval |= MOVEUP;
		if (this.isFree(row+1, col))
			retval |= MOVEDOWN;
	}

	if ((retval & MOVELEFT) > 0)
		dof ++;
	if ((retval & MOVERIGHT) > 0)
		dof ++;
	if ((retval & MOVEUP) > 0)
		dof ++;
	if ((retval & MOVEDOWN) > 0)
		dof ++;

	if (dof == 1)
	{
		this.moveBlock(row, col, retval);
		return 16;
	}

	return retval;
 }

 function moveBlock(row, col, dir){
	var lett = this.content(row, col);
	if (lett=='R'){
		if (dir == MOVELEFT){
			this.setContent(row,col+1,'X');
            this.setContent(row+1,col+1,'X')
            this.setContent(row,col-1,'R')
			this.setContent(row,col,'r');
            this.setContent(row+1,col-1,'S')
            this.setContent(row+1,col,'s')
		} else if (dir == MOVERIGHT) {
			this.setContent(row,col,'X');
            this.setContent(row+1,col,'X')
            this.setContent(row,col+1,'R')
			this.setContent(row,col+2,'r');
            this.setContent(row+1,col+1,'S')
            this.setContent(row+1,col+2,'s')
		} else if (dir == MOVEUP) {
			this.setContent(row+1,col,'X');
            this.setContent(row+1,col+1,'X')
            this.setContent(row-1,col,'R')
			this.setContent(row-1,col+1,'r');
            this.setContent(row,col,'S')
            this.setContent(row,col+1,'s')
		} else if (dir == MOVEDOWN) {
			this.setContent(row,col,'X');
            this.setContent(row,col+1,'X')
            this.setContent(row+1,col,'R')
			this.setContent(row+1,col+1,'r');
            this.setContent(row+2,col,'S')
            this.setContent(row+2,col+1,'s')
		}
	} else if (lett == 'V'){
		if (dir == MOVELEFT){
			this.setContent(row,col-1,'V');
			this.setContent(row+1,col-1,'v');
			this.setContent(row,col,'X');
			this.setContent(row+1,col,'X');
		} else if (dir == MOVERIGHT) {
			this.setContent(row,col+1,'V');
			this.setContent(row+1,col+1,'v');
			this.setContent(row,col,'X');
			this.setContent(row+1,col,'X');
		} else if (dir == MOVEUP) {
			this.setContent(row-1,col,'V');
			this.setContent(row,col,'v');
			this.setContent(row+1,col,'X');
		} else if (dir == MOVEDOWN) {
			this.setContent(row+1,col,'V');
			this.setContent(row+2,col,'v');
			this.setContent(row,col,'X');
		}
	} else if (lett == 'H'){
		if (dir == MOVELEFT){
			this.setContent(row,col-1,'H');
			this.setContent(row,col,'h');
			this.setContent(row,col+1,'X');
		} else if (dir == MOVERIGHT) {
			this.setContent(row,col+1,'H');
			this.setContent(row,col+2,'h');
			this.setContent(row,col,'X');
		} else if (dir == MOVEUP) {
			this.setContent(row-1,col,'H');
			this.setContent(row-1,col+1,'h');
			this.setContent(row,col,'X');
			this.setContent(row,col+1,'X');
		} else if (dir == MOVEDOWN) {
			this.setContent(row+1,col,'H');
			this.setContent(row+1,col+1,'h');
			this.setContent(row,col,'X');
			this.setContent(row,col+1,'X');
		}
	} else if (lett == 'G'){
		if (dir == MOVELEFT){
			this.setContent(row,col-1,'G');
		} else if (dir == MOVERIGHT) {
			this.setContent(row,col+1,'G');
		} else if (dir == MOVEUP) {
			this.setContent(row-1,col,'G');
		} else if (dir == MOVEDOWN) {
			this.setContent(row+1,col,'G');
		}
		this.setContent(row,col,'X');
	}
	this.updateImage();
 }

 function drawBoard(){
	var row, col, xpos, yposi, lett;	
	var x=YAHOO.util.Dom.getX('gmboard');
	var y=YAHOO.util.Dom.getY('gmboard');
	if (isOldIE){
		x=x-2;
		y=y-2;//border bug
	}
	for (var p=0; p < this.state.length; p++){
		row = Math.floor(p / cols);
		col = p - (row * cols);
		lett = this.state.charAt(col + row * cols);
		var cell='gmcell_r'+row+'c_'+col;
		document.getElementById(cell).style.position="absolute";
		document.getElementById(cell).style.left=(x + col*50) +"px";
		document.getElementById(cell).style.top=(y + row*50) +"px";
		document.getElementById(cell).style.width="50px";
		document.getElementById(cell).style.height="50px";
		if (lett == 'R'){
			document.getElementById(cell).src = redblocktl.src;
		} else if (lett == 'r'){
			document.getElementById(cell).src = redblocktr.src;
		} else if (lett == 'S'){
			document.getElementById(cell).src = redblockbl.src;
		} else if (lett == 's'){
			document.getElementById(cell).src = redblockbr.src;
		} else if (lett == 'H'){
			document.getElementById(cell).src = blueblockhl.src;
		} else if (lett == 'h'){
			document.getElementById(cell).src = blueblockhr.src;
		} else if (lett == 'V'){
			document.getElementById(cell).src = blueblockvt.src;
		} else if (lett == 'v'){
			document.getElementById(cell).src = blueblockvb.src;
		} else if (lett == 'G'){
			document.getElementById(cell).src = greenblock.src;
		} else if (lett == 'X'){
			document.getElementById(cell).src = emptyblock.src;
		}
	}
 }

 function drawSolution(){
	var row, col, xpos, yposi, lett;	
	var x=YAHOO.util.Dom.getX('gmsolution');
	var y=YAHOO.util.Dom.getY('gmsolution');
	if (isOldIE){
		x=x-2;
		y=y-2;//border bug
	}
	for (var p=0; p < this.solution.length; p++){
		row = Math.floor(p / cols);
		col = p - (row * cols);
		lett = this.solution.charAt(col + row * cols);
		if (lett == '*')
			lett = 'X';
		var cell='gmsol_r'+row+'c_'+col;
		document.getElementById(cell).style.position="absolute";
		document.getElementById(cell).style.left=(x + col*25) +"px";
		document.getElementById(cell).style.top=(y + row*25) +"px";
		document.getElementById(cell).style.width="25px";
		document.getElementById(cell).style.height="25px";
		if (lett == 'R'){
			document.getElementById(cell).src = redblocktl.src;
		} else if (lett == 'r'){
			document.getElementById(cell).src = redblocktr.src;
		} else if (lett == 'S'){
			document.getElementById(cell).src = redblockbl.src;
		} else if (lett == 's'){
			document.getElementById(cell).src = redblockbr.src;
		} else if (lett == 'H'){
			document.getElementById(cell).src = blueblockhl.src;
		} else if (lett == 'h'){
			document.getElementById(cell).src = blueblockhr.src;
		} else if (lett == 'V'){
			document.getElementById(cell).src = blueblockvt.src;
		} else if (lett == 'v'){
			document.getElementById(cell).src = blueblockvb.src;
		} else if (lett == 'G'){
			document.getElementById(cell).src = greenblock.src;
		} else if (lett == 'X'){
			document.getElementById(cell).src = emptyblock.src;
		}
	}
 }

 /* End of game object */

 /* UI object */
 function uiObj(){
	this.x = -1;
 	this.y = -1;
	this.xscreen = -1;
	this.yscreen = -1;
	this.row = -1;
	this.col = -1;
	this.startrow = 0;
	this.startcol = 0;
	this.startlett ='';
	this.startmobility = 0;
	this.xoffset = 0;
	this.yoffset = 0;
	this.valid = false;
	this.multichoice = false;
	this.mobility = 0;
	this.setMobility = setMobility;
	this.getMobility = getMobility;
	this.fromEvent = eventPos;
	this.startChoosing = startChoosing;
	this.end = selectEnd;
 }

 function eventPos(e){
	var ev = YAHOO.util.Event.getEvent(e);
    this.x = YAHOO.util.Event.getPageX(ev) - YAHOO.util.Dom.getX('gmboard');
    this.y = YAHOO.util.Event.getPageY(ev) - YAHOO.util.Dom.getY('gmboard');
	if (isOldIE){
		this.x=this.x+2;
		this.y=this.y+2;//border bug
	}
	this.row = Math.floor((this.y-1) / 50);
	this.col = Math.floor((this.x-1) / 50);
	if (this.row >= 0 && this.row < rows && this.col >= 0 && this.col < cols){
		this.valid = true;
	} else {
		this.valid = false;
	}
 }

 function startChoosing(lett, mob){
	this.multichoice = true;
	this.startrow = this.row;
	this.startcol = this.col;
	this.mobility = mob;
	this.startlett = lett;

	var x=YAHOO.util.Dom.getX('gmboard');
	var y=YAHOO.util.Dom.getY('gmboard');
	var px = new Array();
	var py = new Array();

	if (lett == 'r') {
		this.startcol -= 1;
		this.startlett = 'R';
	} else if (lett == 'S'){
		this.startrow -= 1;
		this.startlett = 'R';
	} else if (lett == 's'){
		this.startrow -= 1;
		this.startcol -= 1;
		this.startlett = 'R';
	} else if (lett == 'h'){
		this.startcol -= 1;
		this.startlett = 'H';
	} else if (lett == 'v'){
		this.startrow -= 1;
		this.startlett = 'V';
	}
	
	lett=this.startlett;

	if ((mob & MOVELEFT) > 0){
		px.push((this.startcol-1)*50);
		py.push(this.startrow*50);
	}
	if ((mob & MOVERIGHT) > 0){
		if (lett=='G'){
			px.push((this.startcol+1)*50);
		} else if (lett=='H'){
			px.push((this.startcol+2)*50);
		}
		py.push(this.startrow*50);
	}
	if ((mob & MOVEUP) > 0){
		px.push(this.startcol*50);
		py.push((this.startrow-1)*50);
	}
	if ((mob & MOVEDOWN) > 0){
		px.push(this.startcol*50);
		if (lett=='G'){
			py.push((this.startrow+1)*50);
		} else if (lett=='V') {
			py.push((this.startrow+2)*50);
		}
	}

	var ox, oy;	
	ox = px.pop();
	oy = py.pop();
	document.getElementById('gmdisp1').style.left= (x+ox) + "px";
	document.getElementById('gmdisp1').style.top=(y+oy) + "px";
	document.getElementById('gmdisp1').src=selection.src;
	ox = px.pop();
	oy = py.pop();
	document.getElementById('gmdisp2').style.left= (x+ox) + "px";
	document.getElementById('gmdisp2').style.top=(y+oy) + "px";
	document.getElementById('gmdisp2').src=selection.src;
 }

 function selectEnd() {
	document.getElementById('gmdisp1').src=blank.src;
	document.getElementById('gmdisp2').src=blank.src;
	var dir = 0;
	if (this.row > this.startrow)
		dir = MOVEDOWN;
	else if (this.row < this.startrow)
		dir = MOVEUP;
	else if (this.col > this.startcol)
		dir = MOVERIGHT;
	else if (this.col < this.startcol)
		dir = MOVELEFT;
	this.multichoice = false;
	currgame.moveBlock(this.startrow, this.startcol, dir);
 }

 function setMobility(flag){
	this.mobility = flag;
 }

 function getMobility(){
	return this.mobility;
 }

 var uipos = new uiObj(); //persistent object

 /* End of UI object */
	
 function newGame(start, finish){
	if (currgame == undefined){
		currgame = new gameObj(start, finish);
	} else {
		currgame.reset(state);
	}
	currgame.updateImage();
	currgame.drawSolution();
	document.getElementById('gmtimer').innerHTML=currgame.timeNow().bold();
	document.getElementById('gmmessagediv').innerHTML="Click a block to move...";
	gt=setTimeout("timerTick()", 1000);
 }

 function endGame(message){
	YAHOO.puzzpix.anim.init();
	tripleflashmessage(message.bold());
	currgame.over = true;
 }

 function timerTick(){
	currgame.incTimer();
	if (currgame.over == false) {
		gt=setTimeout("timerTick()", 1000);
	}
	document.getElementById('gmtimer').innerHTML=currgame.timeNow().bold();
 }

 function selBlock(e){
	if (!currgame)
		return;
	if (currgame.over)
		return;

	uipos.fromEvent(e);
	if (!uipos.valid)
		return;
 
	if (!uipos.multichoice){
		var dof = currgame.checkMove(uipos.row, uipos.col);
		if (dof != 16){ 
			// we haven't moved (or cannot)
			if (dof != 0) {
				// multiple degrees of freedom
				document.getElementById('gmboard').style.cursor="crosshair";
				document.getElementById('gmmessagediv').innerHTML="Pick a square...";
				uipos.startChoosing(currgame.content(uipos.row, uipos.col), dof);
			} else {
				document.getElementById('gmmessagediv').innerHTML="You can\'t move that one!";
				var t1=setTimeout("document.getElementById('gmmessagediv').innerHTML='Click a block to move...'",1500);
			}
		}
	} else {
		if (currgame.isFree(uipos.row, uipos.col)){
			document.getElementById('gmboard').style.cursor="auto";
			document.getElementById('gmmessagediv').innerHTML="Click a block to move...";
			uipos.end();
		} else {
			document.getElementById('gmmessagediv').innerHTML="You can\'t move there!";
		}
	}

	if (this.checkWin()){
		endGame("YOU HAVE WON!!!");		
	}
 }
	
 function tripleflashmessage(message){
	var p = 500;
	var x=YAHOO.util.Dom.getX('gmboard') + 120;
	var y=YAHOO.util.Dom.getY('gmboard');
	YAHOO.util.Dom.setStyle('gmmessage', 'left', x + "px");
	YAHOO.util.Dom.setStyle('gmmessage', 'top', y + 150 + "px");
	document.getElementById('gmmessage').innerHTML=message;
	var animstr0="document.getElementById('gmmessage').innerHTML=''";
	var animstr1="document.getElementById('gmmessage').innerHTML='"+message+"'";
	var t1=setTimeout(animstr0,p);
	var t2=setTimeout(animstr1,p*2);
	var t1=setTimeout(animstr0,p*3);
	var t2=setTimeout(animstr1,p*4);
 }

