// Parameters
var thick = 5;
var penalty = 60;
var penalty_cap = 8;
var top_limit = 100;
var msg_rate = 100;
var msg_steps = 10;
var msg_opacity = 1;
var msg_bar_opacity = 0.2;

// Ajax variables
var xml_obj = null;

// Game variables
var na = 0;
var game_str = '';
var game_on = 0;
var game = [];
var cols = [];
var rows = [];
var grid_x = 0;
var grid_y = 0;
var pixel_total = 0;
var pixel_count = 0;
var penalty_factor = 0;
var coord_x = -1;
var coord_y = -1;
var right_start = '';
var enter_name = 0;
var best_times_id = '';
var game_post = 0;
var times_offset = 0;
var times_limit = 20;

// Timer variables
var timer_count = 0;
var timer = null;
var timer_on = 0;
var timer_pause = 0;

// Message variables
var msg_timer = null;
var msg_id = '';
var msg_step = 0;

// Dialogue variables
var dialogue_drag = '';
var dialogue_dimension = {};
var dialogue_positions = {};
var dialogue_zindex = 500;
var last_mx = 0;
var last_my = 0;

// Penalty variables
var penalty_divs = [];
var penalty_count = 0;
var penalty_size = {};
var penalty_rate = 50;
var penalty_steps = 10;
var penalty_timer = null;
var penalty_opacity = 1;
var penalty_raise = 20;
var penalty_on = 0;

// Page variables
var pages = { 'directions' : [ 1, 6 ] };

//-------------------------------------------------------//
// INITIALIZING FUNCTIONS                                //
//-------------------------------------------------------//

function initialize () {
	// fetch the XML Http Request object
	if (window.ActiveXObject) { xml_obj = new ActiveXObject('Microsoft.XMLHTTP'); }
	else if (window.XMLHttpRequest) { xml_obj = new XMLHttpRequest(); }

	na = parseInt(document.info.na.value);
	if (!na) {
		refreshAd();
		centerAd();
	}

	var your_name = getCookie('your_name')
	if (your_name && document.times && document.times.name) {
		document.times.name.value = your_name;
	}

	initPenalty();
	loadSelectBoxes();
	randomTheme();
	enableInput();

	// fix for IE flickering problem
	if (IE) { try { document.execCommand("BackgroundImageCache", false, true); } catch (err) {} }

	showBox('directions', 1, 1);
}

function loadSelectBoxes () {
	// Populate level box
	var maxlevel = document.info.maxlevel.value;
	for (var i=1; i<=maxlevel; i++) {
		document.parameters.level.options[document.parameters.level.options.length] = new Option(sprintf('Level %d', i), i);
	}

	// Populate theme box
	var count = 1;
	var info = eval('document.info.theme'+count);
	while (info) {
		if (info.value) {
			var pair = info.value.split('|');

			document.parameters.theme.options[document.parameters.theme.options.length] = new Option(pair[1], pair[0]);

			count++;
			info = eval('document.info.theme'+count);
		}
	}
}

function loadGameBox () {
	var box = document.getElementById('r_game');

	if (document.parameters.level.selectedIndex <= 0) {
		box.style.display = 'none;'
		showButtons();
		return;
	}

	var level = document.parameters.level.options[document.parameters.level.selectedIndex].value;

	// clear out the select game box
	document.parameters.game.options.length = 2;

	var count = 1;
	var info = eval('document.info.level'+level+'_game'+count);
	while (info) {
		var game_info = info.value.split(',');

		document.parameters.game.options[document.parameters.game.options.length] = new Option(sprintf('Game %d: %s', count, game_info[4]), info.value);

		count++;
		info = eval('document.info.level'+level+'_game'+count);
	}
	document.parameters.game.selectedIndex = 0;

	box.style.display = '';

	showButtons();
}

function showButtons () {
	if (document.parameters.level.selectedIndex > 0 && document.parameters.game.selectedIndex > 0) {
		toggleButton('r_button_new_game', 1);
		toggleButton('r_button_best_times', 1);
	}
	else {
		toggleButton('r_button_new_game', 0);
		toggleButton('r_button_best_times', 0);
	}
}

function toggleButton (id, on) {
	var box = document.getElementById(id);
	box.style.display = on ? '' : 'none';
}

function changeTheme () {
	if (document.parameters.theme.selectedIndex < 0) { return; }

	var css_id = document.parameters.theme.options[document.parameters.theme.selectedIndex].value;

	setCookie('theme', css_id);

	if (css_id == 'random') {
		theme_index = Math.floor(Math.random() * (document.parameters.theme.options.length - 1)) + 1;
		document.parameters.theme.selectedIndex = theme_index;
		css_id = document.parameters.theme.options[theme_index].value;
	}

	var css_file = sprintf('/css/game_%s.css', css_id);
	var css_box = document.getElementById('css');
	if (css_box) { css_box.setAttribute('href', css_file); }

	var css_ie_file = sprintf('/css/game_%s_ie.css', css_id);
	var css_ie_box = document.getElementById('css_ie');
	if (css_ie_box) { css_ie_box.setAttribute('href', css_ie_file); }
}

function randomTheme () {
	if (!document.parameters || !document.parameters.theme) { return; }

	var theme = getCookie('theme');

	if (theme) {
		for (var i=0; i<document.parameters.theme.options.length; i++) {
			if (document.parameters.theme.options[i].value == theme) {
				document.parameters.theme.selectedIndex = i;
			}
		}
	}
	else {
		var theme_index = Math.floor(Math.random() * document.parameters.theme.options.length);
		document.parameters.theme.selectedIndex = theme_index;
	}

	changeTheme();
}

//-------------------------------------------------------//
// GAME FUNCTIONS                                        //
//-------------------------------------------------------//

function newGame () {
	if (document.parameters.game.selectedIndex <= 0) { return; }

	penalty_divs = [];
	penalty_count = 0;
	penalty_on = 0;

	penalty_factor = 1;
	coord_x = -1;
	coord_y = -1;
	game_on = 1;
	enter_name = 0;

	mouse_left = false;
	mouse_middle = false;
	mouse_right = false;

	game_str = randomGame();
	if (document.parameters.game.selectedIndex > 1) {
		game_str = document.parameters.game.options[document.parameters.game.selectedIndex].value;
	}

	if (timer) { stopTimer(); }
	if (timer_pause) {
		showGame();
		timer_pause = 0;
	}

	if (!na) { refreshAd(); }

	hideMessages();
	createGame(game_str);
	centerBox('game_box');
	startTimer();

	if (getCookie('hide_directions')) {
		hideBox('directions');
	}
	hideBox('enter_name');
}

function hideGame () {
	var game_box = document.getElementById('game_box');
	if (game_box) { game_box.style.display = 'none'; }
}

function showGame () {
	var gamebox = document.getElementById('game_box');
	if (gamebox) { gamebox.style.display = ''; }
}

function randomGame () {
	var level = document.parameters.level.options[document.parameters.level.selectedIndex].value;
	var size = level * thick;

	var game_random = sprintf('%d,%d,', size, size);
	var cutoff = 0.5;
	
	if (level == 3) { cutoff = 0.65; }
	else if (level == 4) { cutoff = 0.7; }
	else if (level == 5) { cutoff = 0.75; }
	else if (level >= 6) { cutoff = 0.8; }

	for (var x=0; x<size; x++) {
		for (var y=0; y<size; y++) {
			game_random = game_random + (Math.random() < cutoff ? 1 : 0);
		}
	}
	game_random += ',random_game,Random Game';

	return game_random;
}

function createGame (game_string) {
	var game_param = game_string.split(',');

	grid_x = game_param[0];
	grid_y = game_param[1];
	grid_pixels = game_param[2];
	game_id = game_param[3];
	game_name = game_param[4];

	game = [];
	rows = [];
	cols = [];
	pixel_count = 0;
	pixel_total = 0;

	// Read from game string and parse it
	for (var x=0; x<grid_x; x++) {
		var col = [];
		for (var y=0; y<grid_y; y++) {
			var index = y * grid_x + x;
			var pixel = grid_pixels.substr(index, 1);
			var cell_info = new Object;

			cell_info['status'] = 'e';					// e - empty, x - crossed, m - marked
			cell_info['pixel'] = (pixel == '1') ? 1 : 0;

			col.push(cell_info);
		}
		game.push(col);
	}

	// Determine row counts
	for (var y=0; y<grid_y; y++) {
		var row = [];
		var onoff = 0;
		var count = 0;
		for (var x=0; x<grid_x; x++) {
			if (x == grid_x - 1 && game[x][y]['pixel'] == 1) {
				count++;
				pixel_total += count;
				row.push({ 'label' : count, 'marked' : 0 });
			}
			if (onoff == 0 && game[x][y]['pixel'] == 1) {
				onoff = 1;
				count++;
			}
			else if (onoff == 1 && game[x][y]['pixel'] == 0) {
				onoff = 0;
				pixel_total += count;
				row.push({ 'label' : count, 'marked' : 0 });
				count = 0;
			}
			else if (onoff == 1 && game[x][y]['pixel'] == 1) {
				count++;
			}
		}
		rows.push(row);
	}

	// Determine column counts
	for (var x=0; x<grid_x; x++) {
		var col = [];
		var onoff = 0;
		var count = 0;
		for (var y=0; y<grid_y; y++) {
			if (y == grid_y - 1 && game[x][y]['pixel'] == 1) {
				count++;
				col.push({ 'label' : count, 'marked' : 0 });
			}
			if (onoff == 0 && game[x][y]['pixel'] == 1) {
				onoff = 1;
				count++;
			}
			else if (onoff == 1 && game[x][y]['pixel'] == 0) {
				onoff = 0;
				col.push({ 'label' : count, 'marked' : 0 });
				count = 0;
			}
			else if (onoff == 1 && game[x][y]['pixel'] == 1) {
				count++;
			}
		}
		cols.push(col);
	}

	generateZero();
	generateGrid();
	generateMap();
}

function centerAll () {
	centerAd();
	centerBox('game_box');
	centerBox('directions', 1);
	centerBox('best_times', 1);
	centerBox('enter_name', 1);
	centerBox('message_bar');
	centerBox('pause');
	centerBox('youwin');
	centerBox('gameover');
}

function endGame (win) {
	if (coord_x >= 0 && coord_y >= 0) { highlightCross(coord_x, coord_y, 0); }

	game_on = 0;

	updateLabels();
	stopTimer();
	showMessage(win ? 'youwin' : 'gameover');

	if (win) {
		var time_box = document.getElementById('your_time');

		removeChildren(time_box);
		time_box.appendChild(document.createTextNode(formatTime(timer_count)));

		enter_name = 1;
		showBox('enter_name', 1, 1);
	}
}

//-------------------------------------------------------//
// GRID GENERATING FUNCTIONS                             //
//-------------------------------------------------------//

function generateGrid () {
	var grid = document.getElementById('grid');

	// Clear the grid content
	removeChildren(grid);

	var tbody = document.createElement('tbody');
	var tr = document.createElement('tr');

	var td = document.createElement('td');
	td.id = 'logo';
	td.className = 'logo';
	td.setAttribute('align', 'center');
	td.setAttribute('valign', 'middle');
	tr.appendChild(td);

	var td = document.createElement('td');
	td.className = 'v1';
	tr.appendChild(td);

	for (var x=0; x<grid_x; x++) {
		var td = document.createElement('td');
		td.className = 'col';
		generateColumnInfo(td, x);
		td.id = sprintf('col-%d', x);
		tr.appendChild(td);

		var td = document.createElement('td');
		td.className = ((x+1) % thick == 0) ? 'v1' : 'v2';
		tr.appendChild(td);
	}
	tbody.appendChild(tr);

	generateRowBorder(tbody, 1, 0);

	for (var y=0; y<grid_y; y++) {
		generateRow(tbody, y);
		generateRowBorder(tbody, ((y+1) % thick == 0) ? 1 : 0, (y == grid_y - 1) ? 1 : 0);
	}

	grid.appendChild(tbody);
}

function generateMap () {
	var logo = document.getElementById('logo');
	var table = document.createElement('table');
	var tbody = document.createElement('tbody');

	table.className = 'imagemap';

	for (var y=0; y<grid_y; y++) {
		var tr = document.createElement('tr');
		for (var x=0; x<grid_x; x++) {
			var td = document.createElement('td');
			td.id = sprintf('map-%d-%d', x, y);
			td.className = 'e';

			tr.appendChild(td);
		}
		tbody.appendChild(tr);
	}

	table.appendChild(tbody);
	logo.appendChild(table);
}

function generateZero () {
	for (var x=0; x<grid_x; x++) {
		if (cols[x].length == 0) {
			for (var y=0; y<grid_y; y++) { game[x][y]['status'] = 'x'; }
		}
	}

	for (var y=0; y<grid_y; y++) {
		if (rows[y].length == 0) {
			for (var x=0; x<grid_x; x++) { game[x][y]['status'] = 'x'; }
		}
	}
}

function generateRowInfo (td, index) {
	if (rows[index].length == 0) {
		var b = document.createElement('b');
		b.appendChild(document.createTextNode('0'));
		td.appendChild(b);
		return;
	}

	for (var i=0; i<rows[index].length; i++) {
		if (i > 0) { td.appendChild(document.createTextNode('  ')); }
		if (rows[index][i]['marked']) {
			var b = document.createElement('b');
			b.appendChild(document.createTextNode(rows[index][i]['label']));
			td.appendChild(b);
		}
		else {
			td.appendChild(document.createTextNode(rows[index][i]['label']));
		}
	}
}

function generateColumnInfo (td, index) {
	if (cols[index].length == 0) {
		var b = document.createElement('b');
		b.appendChild(document.createTextNode('0'));
		td.appendChild(b);
		return;
	}

	for (var i=0; i<cols[index].length; i++) {
		if (i > 0) { td.appendChild(document.createElement('br')); }
		if (cols[index][i]['marked']) {
			var b = document.createElement('b');
			b.appendChild(document.createTextNode(cols[index][i]['label']));
			td.appendChild(b);
		}
		else {
			td.appendChild(document.createTextNode(cols[index][i]['label']));
		}
	}
}

function generateRow (tbody, index) {
	var tr = document.createElement('tr');

	var td = document.createElement('td');
	td.className = 'row';
	generateRowInfo(td, index);
	td.id = sprintf('row-%d', index);
	tr.appendChild(td);

	var td = document.createElement('td');
	td.className = 'v3';
	tr.appendChild(td);

	for (var x=0; x<grid_x; x++) {
		var td = document.createElement('td');
		td.className = 'cell-e';
		if (game[x][index]['status'] == 'x') { td.className = 'cell-x'; }
		else if (game[x][index]['status'] == 'm') { td.className = 'cell-m'; }
		td.id = sprintf('cell-%dx%d', x, index);
		tr.appendChild(td);

		var td = document.createElement('td');
		td.className = ((x+1) % thick == 0) ? 'v3' : 'v4';
		tr.appendChild(td);

		if (game[x][index]['status'] == 'm') {
			var icell = document.getElementById(sprintf('map-%d-%d', x, index));
			icell.className = 'm';
		}
	}

	tbody.appendChild(tr);
}

function generateRowBorder (tbody, bold, final) {
	var tr = document.createElement('tr');

	var td = document.createElement('td');
	td.className = bold ? 'h1' : 'h2';
	tr.appendChild(td);

	var td = document.createElement('td');
	var x1 = bold ? 'x1' : 'xf';

	if (final) { x1 = 'x5'; }
	td.className = x1;
	tr.appendChild(td);

	for (var x=0; x<grid_x; x++) {
		var td = document.createElement('td');
		td.className = bold ? 'h3' : 'h4';
		tr.appendChild(td);

		var td = document.createElement('td');
		var x1 = (x != grid_x - 1) ? 'x1' : 'x3';
		var x2 = (x != grid_x - 1) ? 'x2' : 'x4';

		if (final && x1 == 'x1') { x1 = 'x5'; }
		else if (final && x1 == 'x3') { x1 = 'x6'; }

		if (bold) { td.className = ((x+1) % thick == 0) ? x1 : 'xt'; }
		else { td.className = ((x+1) % thick == 0) ? 'xf' : x2; }
		tr.appendChild(td);
	}

	tbody.appendChild(tr);
}

//-------------------------------------------------------//
// USER INPUT FUNCTIONS                                  //
//-------------------------------------------------------//

function enableInput () {
	document.onkeyup = keyUp;
	document.onselectstart = nothing;
	document.oncontextmenu = nothing;
	document.onmousedown = mouseDown;
	document.onmouseup = mouseUp;
	document.onmousemove = mouseMove;

	document.onmouseout = mouseOut;
}

function parseTarget (targetid) {
	if (targetid.indexOf('cell-') == 0) {
		var pieces = targetid.split('-');
		var coord = pieces[1].split('x');
		return coord;
	}
	return;
}

function nothing (e) {
	return false;
}

function keyUp (e) {
	var event = getEvent(e);
	var target = getTarget(event);

	if (event.keyCode == 13) {				// enter key
		var box = document.getElementById('enter_name');
		if (enter_name) { submitTime(); }
	}
	else if (event.keyCode == 32) {				// spacebar
		if (game_on) {
			if (timer_pause) {
				if (IE) { hideMessage('pause'); }
				else { startFadeMessage(); }
				timer_on = 1;
				runTimer();
				showGame();
				timer_pause = 0;
			}
			else {
				showMessage('pause');
				stopTimer();
				hideGame();
				timer_pause = 1;
			}
		}
	}
	else if (event.keyCode == 27) {		// escape key 
		toggleBox('google');
	}
}

function mouseDown (e) {
	var event = getEvent(e);
	var target = getTarget(event);
	var coord = parseTarget(target.id);

	getMouseClick(event);

	if ((findID(target, 'directions_title1') || findID(target, 'directions_title2') || findID(target, 'directions_title3')) && target.className != 'button_close') {
		dialogue_drag = 'directions';
		last_mx = getMouseX(event);
		last_my = getMouseY(event);
		dialogue_positions['directions'] = [ last_mx, last_my ];
	}
	else if ((findID(target, 'best_times_title1') || findID(target, 'best_times_title2') || findID(target, 'best_times_title3')) && target.className != 'button_close') {
		dialogue_drag = 'best_times';
		last_mx = getMouseX(event);
		last_my = getMouseY(event);
		dialogue_positions['best_times'] = [ last_mx, last_my ];
	}

	// Move window up
	if (findID(target, 'directions')) {
		var dialogue = document.getElementById('directions');
		dialogue.style.zIndex = dialogue_zindex++;
	}
	else if (findID(target, 'best_times')) {
		var dialogue = document.getElementById('best_times');
		dialogue.style.zIndex = dialogue_zindex++;
	}

	if (target.nodeName.toLowerCase() == 'input') {
		return true;
	}

	if (!timer_on) { return false; }

	if (mouse_left && coord) {
		if (game[coord[0]][coord[1]]['pixel']) {
			if (game[coord[0]][coord[1]]['status'] == 'e') {
				target.className = 'cell-m-on';
				game[coord[0]][coord[1]]['status'] = 'm';
				pixel_count++;

				var icell = document.getElementById(sprintf('map-%d-%d', coord[0], coord[1]));
				icell.className = 'm';

				if (pixel_count == pixel_total) {
					endGame(1);
					return;
				}
			}
			else if (game[coord[0]][coord[1]]['status'] == 'x') {
				target.className = 'cell-e-on';
				game[coord[0]][coord[1]]['status'] = 'e';
			}
		}
		else if (game[coord[0]][coord[1]]['status'] != 'x') {
			target.className = 'cell-x-on';
			game[coord[0]][coord[1]]['status'] = 'x';

			// Penalize for mistake
			showPenalty(penalty_factor, getMouseX(event), getMouseY(event));
			timer_count += penalty * penalty_factor;
			penalty_factor *= 2;
			penalty_factor = (penalty_factor > penalty_cap) ? penalty_cap : penalty_factor;
		}
	}
	else if (mouse_right && coord) {
		if (game[coord[0]][coord[1]]['status'] == 'e') {
			right_start = 'x';
			target.className = 'cell-x-on';
			game[coord[0]][coord[1]]['status'] = 'x';
		}
		else if (game[coord[0]][coord[1]]['status'] == 'x') {
			right_start = 'e';
			target.className = 'cell-e-on';
			game[coord[0]][coord[1]]['status'] = 'e';
		}
	}

	return false;
}

function mouseUp (e) {
	var event = getEvent(e);
	var target = getTarget(event);
	var coord = parseTarget(target.id);

	dialogue_drag = '';

	mouse_left = false;
	mouse_middle = false;
	mouse_right = false;
	right_start = '';

	if (timer_on) { updateLabels(); }
}

function mouseOut (e) {
	var event = getEvent(e);
	var target = getTarget(event);
	var totarget = getToTarget(event);

	if (totarget) { return; }

	dialogue_drag = '';

	mouse_left = false;
	mouse_middle = false;
	mouse_right = false;
	right_start = '';

	if (timer_on) { updateLabels(); }
}

function mouseMove (e) {
	var event = getEvent(e);
	var target = getTarget(event);
	var coord = parseTarget(target.id);

	if (dialogue_drag) {
		var dialogue = document.getElementById(dialogue_drag);
		var new_x = parseInt(dialogue.style.left) + (getMouseX(event) - last_mx);
		var new_y = parseInt(dialogue.style.top) + (getMouseY(event) - last_my);
		var dialogue_width = parseInt(dialogue.style.width);
		var dialogue_height = parseInt(dialogue.style.height);

		// Check to make sure it stays in the window boundary
		if (new_x < 0) { new_x = 0; }
		else if (new_x + dialogue_width >= screenWidth()) { new_x = screenWidth() - dialogue_width; }
		if (new_y < 0) { new_y = 0; }
		else if (new_y + dialogue_height >= screenHeight()) { new_y = screenHeight() - dialogue_height; }

		dialogue.style.left = new_x;
		dialogue.style.top = new_y;
		dialogue_positions[dialogue_drag] = [ new_x, new_y ];
	}
	last_mx = getMouseX(event);
	last_my = getMouseY(event);

	if (!timer_on) { return; }

	if (mouse_left && coord) {
		if (game[coord[0]][coord[1]]['pixel']) {
			if (game[coord[0]][coord[1]]['status'] == 'e') {
				target.className = 'cell-m-on';
				game[coord[0]][coord[1]]['status'] = 'm';
				pixel_count++;

				var icell = document.getElementById(sprintf('map-%d-%d', coord[0], coord[1]));
				icell.className = 'm';

				if (pixel_count == pixel_total) {
					endGame(1);
					return;
				}
			}
		}
		else {
			if ((coord_x != coord[0] || coord_y != coord[1]) && game[coord[0]][coord[1]]['status'] != 'x') {
				target.className = 'cell-x';
				game[coord[0]][coord[1]]['status'] = 'x';

				// Penalize for mistake
				showPenalty(penalty_factor, getMouseX(event), getMouseY(event));
				timer_count += penalty * penalty_factor;
				penalty_factor *= 2;
				penalty_factor = (penalty_factor > penalty_cap) ? penalty_cap : penalty_factor;
			}
		}
	}
	else if (mouse_right && coord) {
		if (coord_x != coord[0] || coord_y != coord[1]) {
			if (game[coord[0]][coord[1]]['status'] == 'e' || game[coord[0]][coord[1]]['status'] == 'x') {
				target.className = (right_start == 'x') ? 'cell-x-on' : 'cell-e-on';
				game[coord[0]][coord[1]]['status'] = (right_start == 'x') ? 'x' : 'e';
			}
		}
	}

	if (coord) {
		if (coord_x != coord[0] || coord_y != coord[1]) {
			if (coord_x >= 0 && coord_y >= 0) {
				highlightCross(coord_x, coord_y, 0);
			}
			highlightCross(coord[0], coord[1], 1);
			coord_x = coord[0];
			coord_y = coord[1];
		}
	}
	else {
		if (coord_x >= 0 && coord_y >= 0 && !coord) {
			highlightCross(coord_x, coord_y, 0);
			coord_x = -1;
			coord_y = -1;
		}
	}
}

function findID (obj, id) {
	if (obj.id == id) { return 1; }
	return obj.parentNode ? findID(obj.parentNode, id) : 0;
}

function highlightCross (mx, my, on) {
	if (IE) { return; }

	var level = document.parameters.level.options[document.parameters.level.selectedIndex].value;

	// Gets too busy to highlight everything when there are too many cells
	if (level <= 3) {
		for (var x=0; x<grid_x; x++) {
			if (x == mx) { continue; }
			highlightCell(x, my, on);
		}

		for (var y=0; y<grid_y; y++) {
			if (y == my) { continue; }
			highlightCell(mx, y, on);
		}
	}

	highlightCol(mx, on);
	highlightRow(my, on);
	highlightCell(mx, my, on);
}

function highlightCol (mx, on) {
	var col = document.getElementById(sprintf('col-%d', mx));
	col.className = on ? 'col-on' : 'col';
}

function highlightRow (my, on) {
	var row = document.getElementById(sprintf('row-%d', my));
	row.className = on ? 'row-on' : 'row';
}

function highlightCell (mx, my, on) {
	var cell = document.getElementById(sprintf('cell-%dx%d', mx, my));
	var stat = game[mx][my]['status'];

	if (stat == 'e') { cell.className = on ? 'cell-e-on' : 'cell-e'; }
	else if (stat == 'm') { cell.className = on ? 'cell-m-on' : 'cell-m'; }
	else if (stat == 'x') { cell.className = on ? 'cell-x-on' : 'cell-x'; }
}

//-------------------------------------------------------//
// TIMER FUNCTIONS                                       //
//-------------------------------------------------------//

function formatTime (count) {
	var hour = parseInt(count / 3600);
	var min = parseInt((count % 3600) / 60);
	var sec = (count % 3600) % 60;
	if (hour < 10) { hour = '0' + hour; }
	if (min < 10) { min = '0' + min; }
	if (sec < 10) { sec = '0' + sec; }
	return hour + ':' + min + ':' + sec;
}

function startTimer () {
	var timer_box = document.getElementById('timer');

	timer_pause = 0;
	timer_count = 0;
	timer_on = 1;

	removeChildren(timer_box);
	timer_box.appendChild(document.createTextNode(formatTime(timer_count)));

	timer = setInterval('runTimer()', 1000);
}

function runTimer () {
	var timer_box = document.getElementById('timer');

	if (!timer_on) { return; }

	checkTimer();

	timer_count++;
	removeChildren(timer_box);
	timer_box.appendChild(document.createTextNode(formatTime(timer_count)));
}

function stopTimer () {
	clearInterval(timer);
	timer = null;
	timer_on = 0;
}

function checkTimer () {
	var timer_box = document.getElementById('timer');

	if (timer_count > 215999) {
		// Set time to 59:59:59
		timer_count = 215999;
		removeChildren(timer_box);
		timer_box.appendChild(document.createTextNode(formatTime(timer_count)));

		endGame(0);
	}
}

function updateLabels () {
	// Read each column and find what was marked
	for (var x=0; x<grid_x; x++) {
		var count = 0;
		var list = [];
		var marked = 0;

		// Reading top to bottom
		for (var y=0; y<grid_y; y++) {
			if (game[x][y]['status'] == 'e') {
				break;
			}
			else if (game[x][y]['status'] == 'm') {
				count++;
			}
			else if (game[x][y]['status'] == 'x') {
				if (count > 0) { list.push(count); }
				count = 0;
			}
			if (y == grid_y - 1) {
				if (count > 0) { list.push(count); }
			}
		}

		for (var i=0; i<list.length; i++) {
			if (list[i] == cols[x][i]['label']) {
				cols[x][i]['marked'] = 1;
				marked = 1;
			}
		}

		count = 0;
		list = [];

		// Reading bottom to top
		for (var y=grid_y-1; y>=0; y--) {
			if (game[x][y]['status'] == 'e') {
				break;
			}
			else if (game[x][y]['status'] == 'm') {
				count++;
			}
			else if (game[x][y]['status'] == 'x') {
				if (count > 0) { list.push(count); }
				count = 0;
			}
			if (y == 0) {
				if (count > 0) { list.push(count); }
			}
		}

		for (var i=0; i<list.length; i++) {
			if (list[i] == cols[x][cols[x].length-(1+i)]['label']) {
				cols[x][cols[x].length-(1+i)]['marked'] = 1;
				marked = 1;
			}
		}

		if (marked) {
			var col = document.getElementById(sprintf('col-%d', x));
			removeChildren(col);
			generateColumnInfo(col, x);
		}
	}

	// Read each row and find what was marked
	for (var y=0; y<grid_y; y++) {
		var count = 0;
		var list = [];
		var marked = 0;

		// Reading left to right
		for (var x=0; x<grid_x; x++) {
			if (game[x][y]['status'] == 'e') {
				break;
			}
			else if (game[x][y]['status'] == 'm') {
				count++;
			}
			else if (game[x][y]['status'] == 'x') {
				if (count > 0) { list.push(count); }
				count = 0;
			}
			if (x == grid_x - 1) {
				if (count > 0) { list.push(count); }
			}
		}

		for (var i=0; i<list.length; i++) {
			if (list[i] == rows[y][i]['label']) {
				rows[y][i]['marked'] = 1;
				marked = 1;
			}
		}

		count = 0;
		list = [];

		// Reading right to left
		for (var x=grid_x-1; x>=0; x--) {
			if (game[x][y]['status'] == 'e') {
				break;
			}
			else if (game[x][y]['status'] == 'm') {
				count++;
			}
			else if (game[x][y]['status'] == 'x') {
				if (count > 0) { list.push(count); }
				count = 0;
			}
			if (x == 0) {
				if (count > 0) { list.push(count); }
			}
		}

		for (var i=0; i<list.length; i++) {
			if (list[i] == rows[y][rows[y].length-(1+i)]['label']) {
				rows[y][rows[y].length-(1+i)]['marked'] = 1;
				marked = 1;
			}
		}

		if (marked) {
			var row = document.getElementById(sprintf('row-%d', y));
			removeChildren(row);
			generateRowInfo(row, y);
		}
	}
}

//-------------------------------------------------------//
// MESSAGE FUNCTIONS                                     //
//-------------------------------------------------------//

function showMessage (id) {
	if (msg_timer) {
		clearTimeout(msg_timer);
		msg_timer = null;
	}
	msg_id = id;

	var message_bar = document.getElementById('message_bar');
	message_bar.style.display = '';
	message_bar.style.zIndex = dialogue_zindex++;

	var message = document.getElementById(id);
	message.style.display = '';
	message.style.zIndex = dialogue_zindex++;

	if (IE) { message_bar.filter = sprintf('alpha(opacity=%d)', msg_bar_opacity * 100); }
	else { message_bar.style.opacity = msg_bar_opacity; }

	if (IE) { message.filter = sprintf('alpha(opacity=%d)', msg_opacity * 100); }
	else { message.style.opacity = msg_opacity; }

	centerBox('message_bar');
	centerBox(id);
}

function hideMessage (id) {
	var message_bar = document.getElementById('message_bar');
	message_bar.style.display = 'none';

	var message = document.getElementById(id);
	message.style.display = 'none';

	msg_id = '';
}

function centerMessage (id) {
	var message_bar = document.getElementById('message_bar');
	message_bar.style.top = Math.round((screenHeight() - parseInt(message_bar.style.height)) / 2);

	var message = document.getElementById(id);
	message.style.left = Math.round((screenWidth() - parseInt(message.style.width)) / 2);
	message.style.top = Math.round((screenHeight() - parseInt(message.style.height)) / 2);
}

function hideMessages () {
	hideMessage('pause');
	hideMessage('youwin');
	hideMessage('gameover');
}

function startFadeMessage () {
	msg_step = msg_steps;
	fadeMessage();
}

function fadeMessage () {
	if (!msg_id) { return; }

	var message = document.getElementById(msg_id);
	var message_bar = document.getElementById('message_bar');
	var percent = msg_step / msg_steps;

	if (IE) {
		message_bar.filter = sprintf('alpha(opacity=%d)', msg_bar_opacity * 100);
		message.filter = sprintf('alpha(opacity=%d)', msg_opacity * 100);
	}
	else {
		message_bar.style.opacity = percent * msg_bar_opacity;
		message.style.opacity = percent * msg_opacity;
	}

	msg_step--;

	if (msg_step >= 0) { msg_timer = setTimeout('fadeMessage()', msg_rate); }
	else { hideMessage(msg_id); }
}

//-------------------------------------------------------//
// AJAX FUNCTIONS                                        //
//-------------------------------------------------------//

function post (type, url) {
	if (game_post) { return; }

	var file = createFile(type);

	game_post = 1;

	xml_obj.open('POST', url, true);
	xml_obj.onreadystatechange = handleStateChange;
	xml_obj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	xml_obj.send(sprintf('file=%s', file));
}

function createFile (type) {
	switch (type) {
	case 'save':
		var your_name = document.times.name.value;
		var level = document.parameters.level.options[document.parameters.level.selectedIndex].value;
		var game_info = game_str.split(',');
		var game_id = game_info[3];

		your_name = your_name.replace(/[^A-Za-z0-9\-\. ]/gi, '');

		setCookie('your_name', your_name);

		return encodeURIComponent(sprintf('save,%d,%s,%d,%s|%s', level, game_id, timer_count, your_name, game_str));
		break;
	case 'times':
		if (document.parameters.level.selectedIndex <= 0) { return; }
		if (document.parameters.game.selectedIndex <= 0) { return; }

		game_str = document.parameters.game.options[document.parameters.game.selectedIndex].value;

		var level = document.parameters.level.options[document.parameters.level.selectedIndex].value;
		var game_info = game_str.split(',');
		var game_id = document.parameters.game.selectedIndex == 1 ? 'random_game' : game_info[3];
		var game_name = document.parameters.game.options[document.parameters.game.selectedIndex].text;

		return encodeURIComponent(sprintf('times,%d,%s,%s,%d,%d', level, game_id, game_name, times_offset, times_limit));
		break;
	}
}

function handleStateChange () {
	if (xml_obj.readyState == 4) {
		if (xml_obj.status == 200) {
			var response = xml_obj.responseText;
			
			game_post = 0;

			if (response.indexOf('times') == 0) { handleBestTimes(response); }
			else if (response.indexOf('save') == 0) { handleSave(); }
		}
	}
}

function handleBestTimes (response) {
	var pieces = response.split('|');
	var table = document.getElementById('best_times_table');

	if (!table || !pieces) { return; }

	removeChildren(table);

	// Add title
	var game_info = pieces[0].split(',');
	var t_offset = parseInt(game_info[4]);
	var t_limit = parseInt(game_info[5]);
	var t_count = parseInt(game_info[6]);
	var tbody = document.createElement('tbody');
	var tr = document.createElement('tr');
	var td = IE ? document.createElement('<td colspan="3">') : document.createElement('td');
	var title = sprintf('Level %d %s (#%d - #%d)', game_info[1], game_info[3], t_offset+1, t_offset+t_limit);

	if (!IE) { td.setAttribute('colspan', 3); }
	td.className = 'header';
	td.appendChild(document.createTextNode(title));
	tr.appendChild(td);
	tbody.appendChild(tr);

	// Add column labels
	var tr = document.createElement('tr');
	var td1 = document.createElement('td');
	var td2 = document.createElement('td');
	var td3 = document.createElement('td');

	td1.className = 'label_name';
	td1.appendChild(document.createTextNode('Name'));
	tr.appendChild(td1);
	td2.className = 'label_time';
	td2.appendChild(document.createTextNode('Time'));
	tr.appendChild(td2);
	td3.className = 'label_createdon';
	td3.appendChild(document.createTextNode('Date and Time'));
	tr.appendChild(td3);
	tbody.appendChild(tr);

	for (var i=1; i<pieces.length; i++) {
		if (!pieces[i]) { continue; }

		var dt = new Date();
		var info = pieces[i].split(',');
		var total = parseInt(info[6]);
		var tr = document.createElement('tr');
		var td1 = document.createElement('td');
		var td2 = document.createElement('td');
		var td3 = document.createElement('td');

		dt.setTime(info[0] * 1000);
		var dt_month = month_names[dt.getMonth()].substr(0, 3);
		var dt_day = dt.getDate();
		var dt_year = dt.getFullYear();
		var dt_hour = pad((dt.getHours() % 12) ? dt.getHours() % 12 : 12, 2);
		var dt_min = pad(dt.getMinutes(), 2);
		var dt_sec = pad(dt.getSeconds(), 2);
		var dt_ampm = dt.getHours() < 12 ? 'AM' : 'PM';
		var dt_format = sprintf('%s %s, %s at %s:%s:%s %s', dt_month, dt_day, dt_year, dt_hour, dt_min, dt_sec, dt_ampm);

		var name = info[4];
		name += total > 1 ? sprintf(' (%d)', total) : '';

		td1.className = 'info_name';
		td1.appendChild(document.createTextNode(name));
		tr.appendChild(td1);
		td2.className = 'info_time';
		td2.appendChild(document.createTextNode(formatTime(info[5])));
		tr.appendChild(td2);
		td3.className = 'info_createdon';
		td3.appendChild(document.createTextNode(dt_format));
		tr.appendChild(td3);

		tbody.appendChild(tr);
	}

	// Add next and prev page buttons
	var tr = document.createElement('tr');
	var td = IE ? document.createElement('<td colspan="3">') : document.createElement('td');
	var stable = document.createElement('table');
	var stbody = document.createElement('tbody');
	var str = document.createElement('tr');
	var std1 = document.createElement('td');
	var std2 = document.createElement('td');
	var a1 = document.createElement('a');
	var a2 = document.createElement('a');
	var img1 = document.createElement('img');
	var img2 = document.createElement('img');

	td.className = 'info_buttons';
	if (!IE) { td.setAttribute('colspan', 3); }
	
	stable.style.width = '100%';
	std2.setAttribute('align', 'right');
	
	img1.src = '/images/shared/invdot.gif';
	img1.className = 'button_prev_page';
	img1.setAttribute('border', 0);
	a1.setAttribute('href', 'javascript:prevBestTimes();');

	img2.src = '/images/shared/invdot.gif';
	img2.className = 'button_next_page';
	img2.setAttribute('border', 0);
	a2.setAttribute('href', 'javascript:nextBestTimes();');

	var prev = false;
	var next = false;
	if (t_offset != 0) {
		a1.appendChild(img1);
		std1.appendChild(a1);
		str.appendChild(std1);
		prev = true;
	}
	if (t_offset + t_limit < t_count) {
		a2.appendChild(img2);
		std2.appendChild(a2);
		str.appendChild(std2);
		next = true;
	}
	if (prev || next) {
		stbody.appendChild(str);
		stable.appendChild(stbody);
		td.appendChild(stable);
		tr.appendChild(td);
		tbody.appendChild(tr);
	}

	table.appendChild(tbody);

	if (best_times_id && best_times_id != game_info[2]) {
		hideBox('best_times');
	}
	best_times_id = game_info[2];

	if (dialogue_positions['best_times']) {
		showBox('best_times');
	}
	else {
		showBox('best_times', 1, 1);
	}
	hideBox('loading_bar');
}

function handleSave () {
	hideBox('enter_name');
	hideBox('loading_bar');
	viewBestTimes();
}

function prevBestTimes () {
	times_offset -= times_limit;
	showLoadingBox('Loading...');
	post('times', 'server/times.php');
}

function nextBestTimes () {
	times_offset += times_limit;
	showLoadingBox('Loading...');
	post('times', 'server/times.php');
}

function viewBestTimes () {
	times_offset = 0;
	showLoadingBox('Loading...');
	post('times', 'server/times.php');
}

function viewDirections () {
	if (dialogue_positions['directions']) {
		showBox('directions');
	}
	else {
		showBox('directions', 1, 1);
	}
}

function submitTime () {
	if (!document.times || !document.times.name) { return; }
	if (document.times.name.value == '') { alert('Please enter a name!'); return; }

	showBox('enter_name');
	enter_name = 0;

	showLoadingBox('Saving...');
	post('save', 'server/save.php');
}

//-------------------------------------------------------//
// PENALTY FUNCTIONS                                     //
//-------------------------------------------------------//

function initPenalty () {
	var penalty_1 = document.getElementById('penalty_1');
	var penalty_2 = document.getElementById('penalty_2');
	var penalty_4 = document.getElementById('penalty_4');
	var penalty_8 = document.getElementById('penalty_8');

	penalty_size = {
		'penalty_1' : [ penalty_1.offsetWidth, penalty_1.offsetHeight ],
		'penalty_2' : [ penalty_2.offsetWidth, penalty_2.offsetHeight ],
		'penalty_4' : [ penalty_4.offsetWidth, penalty_4.offsetHeight ],
		'penalty_8' : [ penalty_8.offsetWidth, penalty_8.offsetHeight ]
	};

	penalty_1.style.display = 'none';
	penalty_2.style.display = 'none';
	penalty_4.style.display = 'none';
	penalty_8.style.display = 'none';
}

function showPenalty (penalty_amt, x, y) {
	var id = sprintf('penalty_%d', penalty_amt);
	var new_id = sprintf('penalty_%d', penalty_count);
	var body = document.getElementById('body');
	var div_new = document.createElement('div');

	div_new.id = new_id;
	div_new.className = id;

	var new_x = Math.floor(x - (penalty_size[id][0] / 2));
	var new_y = Math.floor(y - (penalty_size[id][1] / 2));

	div_new.style.left = new_x;
	div_new.style.top = new_y;

	var div_added = body.appendChild(div_new);

	penalty_divs.push({ 'id' : new_id, 'x' : new_x, 'y' : new_y, 'step' : penalty_steps, 'obj' : div_added });
	penalty_count++;

	if (!penalty_on) {
		penalty_timer = setTimeout('runPenalty()', penalty_rate);
		penalty_on = 1;
	}
}

function runPenalty () {
	var body = document.getElementById('body');
	var penalty_divs_new = [];

	for (var i=0; i<penalty_divs.length; i++) {
		var penalty_box = penalty_divs[i]['obj'];
		var percent = penalty_divs[i]['step'] / penalty_steps;

		penalty_box.style.top = penalty_divs[i]['y'] - ((1 - percent) * penalty_raise);
		if (!IE) { penalty_box.style.opacity = percent * penalty_opacity; }

		if (penalty_divs[i]['step'] <= 0) {
			penalty_box.style.display = 'none';
			body.removeChild(penalty_box);
			continue;
		}
		penalty_divs[i]['step']--;
		penalty_divs_new.push(penalty_divs[i]);
	}
	penalty_divs = penalty_divs_new;

	if (penalty_divs.length > 0) {
		penalty_timer = setTimeout('runPenalty()', penalty_rate);
	}
	else {
		penalty_timer = null;
		penalty_on = 0;
	}
}

//-------------------------------------------------------//
// PAGE FUNCTIONS                                        //
//-------------------------------------------------------//

function turnPage (id, direction) {
	if (!pages[id]) { return; }

	var current = pages[id][0];
	for (var i=1; i<=pages[id][1]; i++) {
		var page = document.getElementById(sprintf('%s_page%d', id, i));
		if (page && page.style.display == '') { current = i; break; }
	}

	var next = direction ? current + 1 : current - 1;
	if (next < 1 || next > pages[id][1]) { return; }

	var button_prev = document.getElementById(sprintf('r_%s_prev', id));
	var button_next = document.getElementById(sprintf('r_%s_next', id));

	button_prev.style.display = (next == 1) ? 'none' : '';
	button_next.style.display = (next == pages[id][1]) ? 'none' : '';

	var page_current = document.getElementById(sprintf('%s_page%d', id, current));
	var page_next = document.getElementById(sprintf('%s_page%d', id, next));

	page_current.style.display = 'none';
	page_next.style.display = '';

	pages[id][0] = next;
}

//-------------------------------------------------------//
// MISCELLANEOUS FUNCTIONS                               //
//-------------------------------------------------------//

function toggleBox (id, center, marker) {
	var box = document.getElementById(id);
	if (box) {
		if (box.style.display == 'none') {
			box.style.display = '';
			box.style.zIndex = dialogue_zindex++;
			if (center) { centerBox(id, marker); }
		}
		else {
			box.style.display = 'none';
		}
	}
}

function showBox (id, center, marker) {
	var box = document.getElementById(id);
	if (box) {
		box.style.display = '';
		box.style.zIndex = dialogue_zindex++;
		if (center) { centerBox(id, marker); }
	}
}

function hideBox (id) {
	var box = document.getElementById(id);
	if (box) { box.style.display = 'none'; }

	if (id == 'directions') {
		setCookie('hide_directions', 1);
	}
}

function centerBox (id, marker) {
	var box = document.getElementById(id);
	if (box) {
		if (marker) {
			var marker = document.getElementById(sprintf('marker_%s', id));

			if (!dialogue_dimension[id]) {
				dialogue_dimension[id] = [ findPosX(marker) + marker.offsetWidth, findPosY(marker) + marker.offsetHeight ];
			}

			// Move to 0,0
			//box.style.left = 0;
			//box.style.top = 0;

			box.style.left = Math.floor((screenWidth() - dialogue_dimension[id][0]) / 2);
			box.style.top = Math.floor((screenHeight() - dialogue_dimension[id][1]) / 2);
		}
		else if (box.offsetHeight) {
			var top = Math.floor((screenHeight() - box.offsetHeight) / 2);
			box.style.left = Math.floor((screenWidth() - box.offsetWidth) / 2);
			box.style.top = (top < top_limit) ? top_limit : top;
		}
		else {
			var top = Math.floor((screenHeight() - parseInt(box.style.height)) / 2);
			box.style.left = Math.floor((screenWidth() - parseInt(box.style.width)) / 2);
			box.style.top = (top < top_limit) ? top_limit : top;
		}
	}
}

function centerAd () {
	var id = 'google_ad';
	var ad = document.getElementById(id);
	var marker = document.getElementById(sprintf('marker_%s', id));

	// Move to 0,0
	//ad.style.left = 0;
	//ad.style.top = 0;

	if (!dialogue_dimension[id]) {
		dialogue_dimension[id] = [ findPosX(marker) + marker.offsetWidth, findPosY(marker) + marker.offsetHeight ];
	}

	var x = Math.floor(screenWidth() - dialogue_dimension[id][0]);
	var y = Math.floor((screenHeight() - dialogue_dimension[id][1]) / 2);

	ad.style.left = x >= 0 ? x : 0;
	ad.style.top = y >= 0 ? y : 0;
}

function refreshAd () {
	var ad_box = document.getElementById('google_ad');
	var ad_frame = document.getElementById('frame_google_ad');

	if (!ad_box || !ad_frame) { return; }

	ad_frame.src = 'google_ad.php';
	ad_box.style.display = '';
}

function showLoadingBox (msg) {
	var text_box = document.getElementById('loading_text');
	text_box.innerHTML = msg;
	showBox('loading_bar');
}

