// morphmatch.js
// Copyright 2008 The Wyrmkeep Entertainment Co. All rights reserved.

// Things to do:
// - Identify valid move after 20(?) seconds

function random() {
	random.seed = (random.seed * random.a + random.c) % random.m;
	return random.seed / random.m;
}
function irandom( m ) {
	return Math.floor(random() * m);
}
random.m = 714025; random.a = 4096; random.c = 150889;
random.seed = (new Date()).getTime() % random.m;

var base_x, base_y;
var pf_x = 8;
var pf_y = 8;
var pf_size = pf_x * pf_y;
var num_tiles = 7;
var frame = 0;
var allow_tile_click = true;
var allow_message_click = false;
var operate = false;
var fillgrid = false;
var newlevel = false;
var hidemessage = false;
var selected_tile = -1;
var swap_tile_1;
var swap_tile_2;
var debug_on = false;
var normal_ms = 250;
var fill_ms = 100;
var level_up_ms = 1000;
var frame_ms = normal_ms;
var score = 0;
var delta_score = 0;
var level = 1;
var last_level_score = 0;
var next_level_score = 250;
var multiplier = 1;
var orb_tile_num = num_tiles;

var can_play_audio = false;

var iPhoneKludge = (navigator.userAgent.indexOf('iPhone') != -1 || navigator.userAgent.indexOf('iPod') != -1);

var playfield = new Array(pf_size);
var zapped = new Array(pf_size);
var orbset = new Array(pf_size);
var tiles = new Array(num_tiles);
var tiles_sel = new Array(num_tiles);
var undo_playfield = new Array(pf_size);

var level_up_image = new Image();
level_up_image.src = "levelcomplete.gif";

var game_over_image = new Image();
game_over_image.src = "gameover.gif";

var explode_tile = new Image();
explode_tile.src = "explode.gif";

var orb_tile = new Image();
orb_tile.src = "tile8.gif";
var orb_sel_tile = new Image();
orb_sel_tile.src = "tile8s.gif";

for (i=0;i<num_tiles;i++) {
	tiles[i] = new Image();
	tiles[i].src = "tile" + i + ".gif";
	tiles_sel[i] = new Image();
	tiles_sel[i].src = "tile" + i + "s.gif";
}

function copy_playfield(src, dst) {
	for (var i=0;i<pf_size;i++) { dst[i] = src[i]; }
}

function swap_playfield(src, dst) {
	for (var i=0;i<pf_size;i++) { var t = dst[i]; dst[i] = src[i]; src[i] = t; }
}

function play_sound(soundobj) {
	if (can_play_audio) {
		document.getElementById(soundobj).Play();
	}
}

function set_text(name, text) {
	if (document.all) {
		document.getElementById(name).innerText = text;
	} else {
		document.getElementById(name).textContent = text;
	}
}

function start_game() {
	var grid = document.getElementById("grid");
	base_x = findPosX(grid);
	base_y = findPosY(grid);

	var matchObj = document.getElementById('match');
	can_play_audio = (matchObj != null && ('Play' in matchObj));

	setup_board();

	setTimeout("animate()", frame_ms);

	set_text('loading', '');
}

function setup_board() {
	var i, j;
	var num, count, value;
	var good;

	for (i=0;i<pf_size;i++) {
		playfield[i] = irandom(num_tiles);
	}

	do {
		good = true;
		for (i=0;i<pf_x && good;i++) {
			count = 1;
			num = playfield[i];
			for (j=1;j<pf_y && good;j++) {
				value = playfield[i + j * pf_x];
				if (value == num) {
					if (++count == 3) {
						playfield[i + j * pf_x] = irandom(num_tiles);
						good = false;
						break;
					}
				} else {
					count = 1;
					num = value;
				}
			}
		}
		if (!good) continue;
		for (j=0;j<pf_y && good;j++) {
			count = 1;
			num = playfield[j * pf_x];
			for (i=1;i<pf_x && good;i++) {
				value = playfield[i + j * pf_x];
				if (value == num) {
					if (++count == 3) {
						playfield[i + j * pf_x] = irandom(num_tiles);
						good = false;
						break;
					}
				} else {
					count = 1;
					num = value;
				}
			}
		}
	} while (!good);

	for (i=0;i<pf_size;i++) {
		set_tile(i, (i % pf_x) * 64, Math.floor(i / pf_x) * 64);
	}
}

function animate() {
	if (hidemessage) {
		hidemessage = false;
		hide_message();
	}

	if (operate)
		perform_check();
	else if (fillgrid)
		drop_tiles();
	else if (newlevel)
		start_level();
	else if (delta_score >= next_level_score - last_level_score)
		level_up();
	else if (!any_moves())
		game_over();

	frame++;
	setTimeout("animate()", frame_ms);
}

function wipe_on_x(sy) {
	// wipe on x
	for (var i=0;i<pf_x;i++)
		zapped[i + sy * pf_x] = true;
}

function wipe_on_y(sx) {
	// wipe on y
	for (var j=0;j<pf_y;j++)
		zapped[sx + j * pf_x] = true;
}

function perform_check() {
	var i, j, k, n;
	var num, count;
	var was_fillgrid = fillgrid;
	var points = 0;
	var color = -1;
	var bonus = false;
	var sx, sy, ix, iy;
	var used_orb = false;

	allow_tile_click = true;
	fillgrid = false;

	for (i=0;i<pf_size;i++)
		zapped[i] = false;

	if (!was_fillgrid && (playfield[swap_tile_1] == orb_tile_num || playfield[swap_tile_2] == orb_tile_num)) {
		sx = swap_tile_1 % pf_x;
		sy = Math.floor(swap_tile_1 / pf_x);
		ix = swap_tile_2 % pf_x;
		iy = Math.floor(swap_tile_2 / pf_x);

		if (playfield[swap_tile_1] == orb_tile_num && playfield[swap_tile_2] == orb_tile_num) {
			if (sy == iy) {
				wipe_on_x(sy);
				wipe_on_y(ix);
				wipe_on_y(sx);
			} else {
				wipe_on_y(sx);
				wipe_on_x(iy);
				wipe_on_x(sy);
			}
			points = 35;
		} else {
			if (sy == iy) wipe_on_x(sy);
			else wipe_on_y(sx);
			points = 25;
		}
		allow_tile_click = false;
		used_orb = true;
	} else {
		for (i=0;i<pf_x;i++) {
			count = 1;
			num = playfield[i];
			for (j=1;j<pf_y;j++) {
				n = i + j * pf_x;
				value = playfield[n];
				if (num != -1 && num == value) {
					count++;
					if (count > 3) {
						zapped[n] = true;
						points = points + 5;
					} else if (count == 3) {
						zapped[n] = true;
						zapped[n - pf_x] = true;
						zapped[n - 2 * pf_x] = true;
						allow_tile_click = false;
						points = points + 10;

						if (color == -1)
							color = value;
						else if (color != value)
							bonus = true;
					}
				} else {
					count = 1;
					num = value;
				}
			}
		}

		for (j=0;j<pf_y;j++) {
			count = 1;
			num = playfield[j * pf_x];
			for (i=1;i<pf_x;i++) {
				n = i + j * pf_x;
				value = playfield[n];
				if (num != -1 && num == value) {
					count++;
					if (count > 3) {
						zapped[n] = true;
						points = points + 5;
					} else if (count == 3) {
						zapped[n] = true;
						zapped[n - 1] = true;
						zapped[n - 2] = true;
						allow_tile_click = false;
						points = points + 10;

						if (color == -1)
							color = value;
						else if (color != value)
							bonus = true;
					}
				} else {
					count = 1;
					num = value;
				}
			}
		}
	}

	if (!allow_tile_click) {
		var nm, np;

		if (!used_orb) {
			sx = swap_tile_1 % pf_x;
			sy = Math.floor(swap_tile_1 / pf_x);
			ix = swap_tile_2 % pf_x;
			iy = Math.floor(swap_tile_2 / pf_x);

			for (i=0;i<pf_size;i++)
				orbset[i] = false;

			for (i=0;i<pf_x;i++) {
				for (j=0;j<pf_y;j++) {
					n = i + j * pf_x;
					if (zapped[n]) {
						num = playfield[n];
						nm = n - 1;
						np = n + 1;
						if (i >= 2 && i < pf_x - 2 && zapped[nm] && playfield[nm] == num && !orbset[nm] && zapped[np] && playfield[np] == num && !orbset[np]) {
							// possible 4 wide
							nm = n - 2;
							np = n + 2;
							if ((zapped[nm] && playfield[nm] == num && !orbset[nm]) || (zapped[np] && playfield[np] == num && !orbset[np])) {
								// make an orb, mark used
								if (multiplier == 1) {
									if (j == sy) {
										playfield[swap_tile_1] = -orb_tile_num;
										zapped[swap_tile_1] = false;
									} else if (j == iy) {
										playfield[swap_tile_2] = -orb_tile_num;
										zapped[swap_tile_2] = false;
									} else {
										//alert('bad initial horizontal orb match: ' + j + ' ' + sy + ' ' + iy);
										playfield[n] = orb_tile_num;
										zapped[n] = false;
									}
								} else {
									playfield[n] = orb_tile_num;
									zapped[n] = false;
								}
								orbset[n] = true;
								orbset[n - 1] = true;
								orbset[n + 1] = true;
							}
						} else {
							nm = n - pf_x;
							np = n + pf_y;
							if (j >= 2 && j < pf_y - 2 && zapped[nm] && playfield[nm] == num && !orbset[nm] && zapped[np] && playfield[np] == num && !orbset[np]) {
								// possible 4 wide
								nm = n - 2 * pf_x;
								np = n + 2 * pf_x;
								if ((zapped[nm] && playfield[nm] == num && !orbset[nm]) || (zapped[np] && playfield[np] == num && !orbset[np])) {
									// make an orb, mark used
									if (multiplier == 1) {
										if (i == sx) {
											playfield[swap_tile_1] = -orb_tile_num;
											zapped[swap_tile_1] = false;
										} else if (i == ix) {
											playfield[swap_tile_2] = -orb_tile_num;
											zapped[swap_tile_2] = false;
										} else {
											//alert('bad initial vertical orb match: ' + i + ' ' + sx + ' ' + ix);
											playfield[n] = orb_tile_num;
											zapped[n] = false;
										}
									} else {
										playfield[n] = orb_tile_num;
										zapped[n] = false;
									}
									orbset[n] = true;
									orbset[n - pf_x] = true;
									orbset[n + pf_x] = true;
								}
							}
						}
					}
				}
			}
		}

		for (i=0;i<pf_size;i++) {
			if (zapped[i]) {
				playfield[i] = -1;
			}
		}

		if (bonus)
			points = Math.floor(1.5 * points);

		if (points) {
			score = score + points * multiplier;
			delta_score = delta_score + points * multiplier;
			multiplier = 2 * multiplier;
			set_text('score', '' + score);

			var delta = delta_score;
			var need = next_level_score - last_level_score;
			if (delta > need)
				delta = need;
			document.getElementById('bar').width = Math.ceil(255 * delta_score / need);
		}

		for (i=0;i<pf_size;i++) {
			num = playfield[i];
			if (num == -1) {
				set_tile_exploded(i);
			} else if (num == -orb_tile_num) {
				playfield[i] = orb_tile_num;
				set_tile(i, (i % pf_x) * 64, Math.floor(i / pf_x) * 64);
			}
		}

		fillgrid = true;
		frame_ms = 150;
		play_sound('match');

	} else if (!was_fillgrid) {
		// This means that last action was invalid.
		sx = swap_tile_1 % pf_x;
		sy = Math.floor(swap_tile_1 / pf_x);
		ix = swap_tile_2 % pf_x;
		iy = Math.floor(swap_tile_2 / pf_x);
		k = playfield[swap_tile_1];
		playfield[swap_tile_1] = playfield[swap_tile_2];
		playfield[swap_tile_2] = k;
		set_tile(swap_tile_1, sx * 64, sy * 64);
		set_tile(swap_tile_2, ix * 64, iy * 64);
		if (selected_tile != -1)
			set_tile_selected(selected_tile, false);
		selected_tile = -1;
	}

	operate = false;
}

function drop_tiles() {
	var i, j, k;

	operate = true;
	frame_ms = normal_ms;

	// first drop tiles
	for (i=0;i<pf_x;i++) {
		for (j=pf_y - 1;j>0;j--) {
			k = i + j * pf_x;
			if (playfield[k] == -1) {
				playfield[k] = playfield[k - pf_x];
				playfield[k - pf_x] = -1;
				operate = false;
			}
		}
	}

	// fill top row
	for (i=0;i<pf_x;i++) {
		if (playfield[i] == -1) {
			playfield[i] = irandom(num_tiles);
			operate = false;
		}
	}

	if (!operate) {
		for (i=0;i<pf_size;i++) {
			if (playfield[i] == -1) {
				hide_tile(i);
			} else {
				set_tile(i, (i % pf_x) * 64, Math.floor(i / pf_x) * 64);
			}
		}
	}

	if (!operate)
		frame_ms = fill_ms;
}

function level_up() {

	for (var i=0;i<pf_size;i++)
		set_tile_exploded(i);

	show_message("levelcomplete");

	frame_ms = level_up_ms;
	newlevel = true;
}

function start_level() {
	setup_board();

	frame_ms = normal_ms;
	newlevel = false;
	delta_score = 0;
	last_level_score = next_level_score;
	next_level_score = 2 * next_level_score;
	level = level + 1;
	hidemessage = true;
	
	set_text('level', '' + level);
	document.getElementById('bar').width = 1;
}

function valid_move() {
	var i, j, n;
	var num, count;

	for (i=0;i<pf_x;i++) {
		count = 1;
		num = playfield[i];
		for (j=1;j<pf_y;j++) {
			n = i + j * pf_x;
			value = playfield[n];
			if (num != -1 && num == value) {
				count++;
				if (count == 3) return true;
			} else {
				count = 1;
				num = value;
			}
		}
	}

	for (j=0;j<pf_y;j++) {
		count = 1;
		num = playfield[j * pf_x];
		for (i=1;i<pf_x;i++) {
			n = i + j * pf_x;
			value = playfield[n];
			if (num != -1 && num == value) {
				count++;
				if (count == 3) return true;
			} else {
				count = 1;
				num = value;
			}
		}
	}

	return false;
}

function any_moves() {
	var i, j, m, n, t;
	var valid;

	for (i=0;i<pf_x;i++) {
		for (j=0;j<pf_y-1;j++) {
			m = i + j * pf_x;
			n = i + j * pf_x + pf_x;
			if (playfield[m] == orb_tile_num || playfield[n] == orb_tile_num)
				return true;
			t = playfield[m];
			playfield[m] = playfield[n];
			playfield[n] = t;
			valid = valid_move();
			t = playfield[m];
			playfield[m] = playfield[n];
			playfield[n] = t;
			if (valid) return true;
		}
	}

	for (j=0;j<pf_y;j++) {
		for (i=0;i<pf_x-1;i++) {
			m = i + j * pf_x;
			n = i + j * pf_x + 1;
			if (playfield[m] == orb_tile_num || playfield[n] == orb_tile_num)
				return true;
			t = playfield[m];
			playfield[m] = playfield[n];
			playfield[n] = t;
			valid = valid_move();
			t = playfield[m];
			playfield[m] = playfield[n];
			playfield[n] = t;
			if (valid) return true;
		}
	}

	return false;
}

function game_over() {
	show_message("gameover");
	frame_ms = level_up_ms;
	allow_message_click = true;
	allow_tile_click = false;
}

function restart_game() {
	setup_board();

	hidemessage = true;
	frame_ms = normal_ms;
	newlevel = false;
	score = 0;
	delta_score = 0;
	last_level_score = 0;
	next_level_score = 250;
	level = 1;
	multiplier = 1;
	frame = 0;
	allow_tile_click = true;

	set_text('level', '1');
	set_text('score', '0');
	document.getElementById('bar').width = 1;
}

function message_click() {
	if (!allow_message_click) return;

	allow_message_click = false;
	gameover = false;
	show_high_scores();
}

function tile_click(index) {
	if (!allow_tile_click) {
		if (allow_message_click)
			message_click();

		return;
	}
	
	if (selected_tile == -1) {
		selected_tile = index;
		set_tile_selected(selected_tile, true);
	} else if (selected_tile != index) {
		var sx = selected_tile % pf_x;
		var sy = Math.floor(selected_tile / pf_x);
		var ix = index % pf_x;
		var iy = Math.floor(index / pf_x);

		if ((sy == iy && (sx + 1 == ix || sx - 1 == ix)) ||
			(sx == ix && (sy + 1 == iy || sy - 1 == iy))) {

			if (playfield[selected_tile] == orb_tile_num ||
				playfield[index] == orb_tile_num ||
				playfield[selected_tile] != playfield[index]) {

				copy_playfield(playfield, undo_playfield);

				// just swap for now
				var t = playfield[selected_tile];
				playfield[selected_tile] = playfield[index];
				playfield[index] = t;
				set_tile(selected_tile, sx * 64, sy * 64);
				set_tile(index, ix * 64, iy * 64);
				allow_tile_click = false;
				operate = true;
				swap_tile_1 = selected_tile;
				swap_tile_2 = index;
				multiplier = 1;
			} else {
				set_tile_selected(selected_tile, false);
			}

			selected_tile = -1;
		} else {
			set_tile_selected(selected_tile, false);
			selected_tile = index;
			set_tile_selected(selected_tile, true);
		}
	}
}

function findPosX(obj) {
	var curleft = 0;
	if(obj.offsetParent)
		while(1)
		{
			curleft += obj.offsetLeft;
			if(!obj.offsetParent)
				break;
			obj = obj.offsetParent;
		}
	else if(obj.x)
		curleft = obj.x;
//	if (iPhoneKludge)
//		curleft += 8;
	return curleft;
}

function findPosY(obj) {
	var curtop = 0;
	if(obj.offsetParent)
		while(1)
		{
			curtop += obj.offsetTop;
			if(!obj.offsetParent)
				break;
			obj = obj.offsetParent;
		}
	else if(obj.y)
		curtop = obj.y;
//	if (iPhoneKludge)
//		curtop += 8;
	return curtop;
}

function set_tile(index, x, y) {
	var imgnum = index + first_tile_image;
	document.images[imgnum].src = "tile" + playfield[index] + ".gif";
	document.images[imgnum].style.left = base_x + x;
	document.images[imgnum].style.top = base_y + y;
}

function set_tile_selected(index, sel) {
	var imgnum = index + first_tile_image;
	document.images[imgnum].src = "tile" + playfield[index] + (sel ? "s" : "") + ".gif";
}

function set_tile_exploded(index) {
	var imgnum = index + first_tile_image;
	document.images[imgnum].src = "explode.gif";
}

function hide_tile(index) {
	var imgnum = index + first_tile_image;
	document.images[imgnum].style.left = -64;
	document.images[imgnum].style.top = -64;
}

function show_message(name) {
	var imgnum = first_tile_image + pf_x * pf_y;
	document.images[imgnum].src = name + ".gif";
	document.images[imgnum].style.left = base_x + 128;
	document.images[imgnum].style.top = base_y + 3 * 64;
}

function hide_message() {
	var imgnum = first_tile_image + pf_x * pf_y;
	document.images[imgnum].style.left = -256;
	document.images[imgnum].style.top = -128;
}

function show_high_scores() {
	var en = document.getElementById("entername");
	en.src = 'EnterName.php?score=' + score;
	en.style.left = base_x + 128;
	en.style.top = base_y + 48;
	en.style.width = 256;
	en.style.height = 416;

	hidemessage = true;
}

function handle_key(e) {
	if(window.event) { // IE
		keynum = e.keyCode;
  	} else if (e.which) { // Netscape/Firefox/Opera
		keynum = e.which;
	}
	keychar = String.fromCharCode(keynum);
	
	if (keychar == 'U') {
		swap_playfield(undo_playfield, playfield);
		for (var i=0;i<pf_size;i++) {
			set_tile(i, (i % pf_x) * 64, Math.floor(i / pf_x) * 64);
		}
	} else if (keychar == 'E') {
		show_high_scores();
	} else if (keychar == 'O') {
		game_over();
	}
}
if (debug_on)
	document.onkeydown = handle_key;

game_is_ready = 1;
