/*
Javascript Puzzle game
By Kik kik _at_ unixsol.org
Copyright (C) 2009 Krum Lozev
Project page http://kik.dgd-bg.com/codes/puzzle/
Use freely and keep this header intact.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 */
var
	Ph = [],	// Puzzle holder imgIds
	Pc = [],	// Puzzle current posId=>imgId
	Pdw = 0,	// Puzzle dimentions width  => boxes horizontal
	Pdh = 0;	// Puzzle dimentions height => boxes vertical

function Puzzle (obj, imgcube) {
	Pdh = imgcube.length;
	Pdw = imgcube[0].length;
//	alert(Pdw+'x'+Pdh);
	var arr4rand = []; // Prepare array for randomizing positions
	for (var i=0; i<Pdw*Pdh; i++) {
		arr4rand.push(i);
	}
	for (var i=0; i<Pdh; i++) {
		for (var j=0; j<Pdw; j++) {
			var piece_id = i*Pdw+j;
			Ph[piece_id] = new Pbox (
				piece_id,
				imgcube[i][j]
			);
			Ph[piece_id].CORRECT_POS = piece_id;

			Ph[piece_id].APPEND(obj);

			/* Prepare random position for this piece */
			var pos = Math.floor(Math.random()*arr4rand.length);
			var rnd = arr4rand[pos];
			var posx = rnd%Pdw;
			var posy = (rnd-posx)/Pdw;
			Ph[piece_id].SETPOS(posx*Piece_w, posy*Piece_h, true, rnd);
			/* Pop out this position */
			arr4rand.splice(pos, 1);
		}
	}
}

function PuzzleSwapPieces (pos1, pos2) {
	if (pos1<0 || pos2<0 || pos1>=Pdw*Pdh || pos2>=Pdw*Pdh)
		return;
	// Move 1set
	var tmp = Ph[Pc[pos2]];
	var x=pos2%Pdw, y=(pos2-x)/Pdw;
	Ph[Pc[pos1]].SETPOS(x*Piece_w, y*Piece_h, false, pos2);

	var x=pos1%Pdw, y=(pos1-x)/Pdw;
	tmp.SETPOS(x*Piece_w, y*Piece_h, false, pos1);

	Ph[Pc[pos2]].ACTIVATE();

	PuzzleCheckCorrect ();
}

function PuzzleCongratulations () {
	/* TODO: time, win message, next game ... etc */
	document.getElementById("Heading").innerHTML = 'Congratulations!';
}

function PuzzleCheckCorrect () {
	for (k in Ph) {
		if (Ph[k].CURRENT_POS!=Ph[k].CORRECT_POS)
			return;
	}
	PuzzleCongratulations ();
}

/* Objects */
function Puzzle_Controls ( obj ) {
	this.OBJ		= obj;
	this.OBJ.style.width	= Piece_w + 'px';
	this.OBJ.style.height	= Piece_h + 'px';
	// Place the picker frame
	this.OBJ.style.top = '0px';
	this.OBJ.style.left = '0px';

	this.parent;

	var	active=false,
		t = this,
		selector_position=0;

	var	a_top = document.createElement('div'),
		a_bot = document.createElement('div'),
		a_lef = document.createElement('div'),
		a_rig = document.createElement('div');

		a_top.style.top		= '0px';
		a_top.style.left	= Math.round(Piece_w/2) + 'px';
		a_top.innerHTML		= '^';

		a_bot.style.bottom	= '0px';
		a_bot.style.left	= Math.round(Piece_w/2) + 'px';
		a_bot.innerHTML		= 'v';

		a_lef.style.left	= '0px';
		a_lef.style.top		= Math.round(Piece_h/2) + 'px';
		a_lef.innerHTML		= '&lt;';

		a_rig.style.right	= '0px';
		a_rig.style.top		= Math.round(Piece_h/2) + 'px';
		a_rig.innerHTML		= '&gt;';

	this.OBJ.appendChild(a_top);
	this.OBJ.appendChild(a_bot);
	this.OBJ.appendChild(a_lef);
	this.OBJ.appendChild(a_rig);

	this.PLACE = function (PboxObj) {
		active = true;
		this.OBJ.className='active';
		selector_position		= PboxObj.CURRENT_POS;
		this.OBJ.style.left		= PboxObj.X + 'px';
		this.OBJ.style.top		= PboxObj.Y + 'px';
		this.parent			= PboxObj;
	}
	this.PIECEPICK = function () {
		active = true;
		Ph[Pc[selector_position]].ACTIVATE();
		this.OBJ.className='active';
	}
	this.PIECERELEASE = function () {
		active = false;
		this.OBJ.className='';
	}

	this.MOVE = function (direction) {
		var piece1 = selector_position, piece2;
		switch (direction) {
			case 'up' :
				piece2 = piece1 - Pdw;
				break;
			case 'down' :
				piece2 = piece1 + Pdw;
				break;
			case 'left':
				piece2 = piece1 - 1;
				break;
			case 'right':
				piece2 = piece1 + 1;
				break;
		}

		if (piece2<0 || piece2>=Pdw*Pdh) {
			return;
		}
		selector_position = piece2;
		if (active) {
			PuzzleSwapPieces(piece1, piece2);
		} else {
			// Where do we go from here ... :)
			var x=selector_position%Pdw, y=(selector_position-x)/Pdw;
			this.OBJ.style.left	= x*Piece_w + 'px';
			this.OBJ.style.top	= y*Piece_h + 'px';
		}
	}

	/* Move events */
	a_top.onclick = function () {	t.MOVE('up');	};
	a_bot.onclick = function () {	t.MOVE('down');	};
	a_lef.onclick = function () {	t.MOVE('left');	};
	a_rig.onclick = function () {	t.MOVE('right');};

	/* Shortcuts */
	window.onkeypress = function (e) {
		var key = e.which || e.keyCode;
		switch (key) {
			case 32 : // Space
			case 13 : // Enter
				if (active)
					t.PIECERELEASE();
				else
					t.PIECEPICK();
				return false;
			case 27 : // ESC
				if (active)
					t.PIECERELEASE();
				break;
			case 40 : // v
				t.MOVE('down');
				return false;
			case 39 : // >
				t.MOVE('right');
				return false;
			case 38 : // ^
				t.MOVE('up');
				return false;
			case 37 : // <
				t.MOVE('left');
				return false;
		}
	}
}

function Pbox (id, imageSrc) {
	this.ID		= id;
	this.IMG;

	this.CORRECT_POS;
	this.CURRENT_POS;

	var imgSrc	= imageSrc;
	var timer	= false;

	this.IMG = document.createElement('img');
	this.IMG.src = imgSrc;
	this.IMG.id	= 'PuzzlePiece' + this.ID;

	this.X;
	this.Y;

	var t = this;

	this.APPEND = function ( obj ) {
		obj.appendChild(this.IMG);
	}

	this.SETPOS = function (x, y, EFF_OFF, posId) {
// 		if (!EFF_OFF) {
// 			alert(x+'x'+y + ' position: ' +posId);
// 		}

		this.X = x;
		this.Y = y;
		this.CURRENT_POS = posId;
		Pc[posId] = this.ID;
//		if (EFF_OFF) {
			this.IMG.style.left	= x+'px';
			this.IMG.style.top	= y+'px';
//		} /* TODO else -> do effects */
	}

	/* Events */
	this.ACTIVATE = function (e) {
		PuzCont.PLACE(t);
	}

	this.IMG.onclick=t.ACTIVATE;

	return this;
}
