'use strict';

/* validated with: http://www.jslint.com/ */

/* false means read-only; true means we can write to it */
/*global window: false, console: false, wf_letterColors: true, page: false, boardLength: false, numSquares: false, premiums: false, color_w: false, color_y: false, color_r: false, ctr_color: false, dls_color: false, dws_color: false, tls_color: false, tws_color: false, qls_color: false, qws_color: false, nul_color: false, gen_color: false, wf_foundWords: false, wf_missingWords: false, wf_tiles: false, wf_board: false, wf_game: false, wf_lexicon: false, wf_wordNum: false, Effect: false */
/*jslint browser: true, eqeqeq: true, plusplus:false */

/*members Color, Direction, Highlight, Premium, Pulsate, Shake, alert, 
altKey, apply, backgroundColor, blur, body, charAt, className, 
clientWidth, close, concat, contentDocument, contentWindow, ctr, 
ctrlKey, defaults, direction, disabled, display, distance, dls, 
document, down, duration, dws, endcolor, error, event, focus, 
fromCharCode, gen, getElementById, height, href, indexOf, innerHTML, 
join, keyCode, length, letter, location, multipleReplace, name, 
offsetHeight, offsetWidth, onkeydown, open, overflow, premium, 
prototype, pulses, push, qls, qws, red, replace, restorecolor, right, 
search, shiftKey, slice, spc, split, squares, srcElement, startcolor, 
style, substr, substring, target, title, tls, toLowerCase, tws, value, 
visibility, warn, which, white, word, writeln, x, y, yellow
*/

var cellSelection = 'tiles';
var previousClassName = '';
var keyCode;

var foundWords = [];
var missingWords = [];
var wordNum = wf_wordNum;

// We need to record the last x coordinate of the last cellSelection, but not the last y coordinate. Here's why:
// When we are on the board, we always know to go "up one row or down one row", even if we are in the "tiles" input box.
// However, if we are in the "tiles" input box and we go "up one row or down one row", we need to know to which x coordinate.
// We need to store the x coordinate that the user was last on before they entered the "tiles" box.
// Otherwise the cursor will "jump" to the below default every time we arrowed up or down out of the "tiles" box.
var xLast = (boardLength / 2) - 0.5; // default to middle of the board - 10 for super scrabble, 7 otherwise










// Additions to base object prototypes

String.prototype.multipleReplace = function(substring, newstring) {
	var finalString = this;
	while (finalString.indexOf(substring) !== -1) {
		finalString = finalString.replace(substring, newstring);
	}
	
	return finalString;
};










//Auxiliary functions.

//Returns the value of a key inside of a GET request in the URL. (http://www.lexicalwordfinder.com/?key1=value1&key2=value2&... )
//This function is no longer used anywhere; handy if needed.
function queryString(key)
{
	var query_string, keyValues, keyValue, i;
	query_string = decodeURIComponent(window.location.search.substring(1));
	keyValues = query_string.split('&');
	
	for (i = 0; i < keyValues.length; ++i) {
		keyValue = keyValues[i].split('=');
		if (keyValue[0] === key) {
			return keyValue[1];
		}
	}
	
	return false;
}



//Determines the scrollbar width of the browser to help us set the proper window size of some of the IFRAMEs.
function scrollBarWidth()
{
	document.body.style.overflow = 'hidden'; 
	var width = document.body.clientWidth;
	document.body.style.overflow = 'scroll'; 
	width -= document.body.clientWidth; 
	if(!width) {
		width = document.body.offsetWidth - document.body.clientWidth;
	}
	document.body.style.overflow = ''; 
	
	return width; 
}



/**
 * Concatenates the values of a variable into an easily readable string
 * by Matt Hackett [scriptnode.com]
 * @param {Object} x The variable to debug
 * @param {Number} max The maximum number of recursions allowed (keep low, around 5 for HTML elements to prevent errors) [default: 10]
 * @param {String} sep The separator to use between [default: a single space ' ']
 * @param {Number} l The current level deep (amount of recursion). Do not use this parameter: it's for the function's own use
 */
function print_r(x, max, sep, l) {

	l = l || 0;
	max = max || 10;
	sep = sep || ' ';

	if (l > max) {
		return "[WARNING: Too much recursion]\n";
	}

	var
		i,
		r = '',
		t = typeof x,
		tab = '';

	if (x === null) {
		r += "(null)\n";
	} else if (t === 'object') {

		l++;

		for (i = 0; i < l; i++) {
			tab += sep;
		}

		if (x && x.length) {
			t = 'array';
		}

		r += '(' + t + ") :\n";

		for (i in x) {
			try {
				r += tab + '[' + i + '] : ' + print_r(x[i], max, sep, (l + 1));
			} catch(e) {
				return "[ERROR: " + e + "]\n";
			}
		}

	} else {

		if (t === 'string') {
			if (x === '') {
				x = '(empty)';
			}
		}

		r += '(' + t + ') ' + x + "\n";

	}

	return r;

}
var var_dump = print_r;










// Creates the ability to have default paremters.
Function.prototype.defaults = function()
{
	var fff, aaa;
	
	fff = this;
	aaa = new Array(fff.length-arguments.length).concat(Array.prototype.slice.apply(arguments));
	
	return function() { return fff.apply(fff, Array.prototype.slice.apply(arguments).concat( aaa.slice(arguments.length, aaa.length))); };
};



function Enum() {}
Enum.Color = { white:'0', yellow:'1', red:'2' };
Enum.Direction = { right:'0', down:'1' };
Enum.Premium = { ctr:'0', dls:'1', dws:'2', tls:'3', tws:'4', qls:'5', qws:'6', spc:' ', gen:'8' };

var PremiumColors = [ctr_color, dls_color, dws_color, tls_color, tws_color, qls_color, qws_color, nul_color, gen_color];



// WORD OBJECT TYPE
function Word(value, word, x, y, direction)
{
	this.value = value;
	this.word = word;
	this.x = x;
	this.y = y;
	this.direction = direction;
}

// Populate foundWords[] with data.
if (wf_foundWords !== "") {
	var foundWords_array = wf_foundWords.split(' ');
	for (var i = 0; i < foundWords_array.length; ) {
		var value = foundWords_array[i++];
		var word = foundWords_array[i++];
		var x = parseInt(foundWords_array[i++], 10);
		var y = parseInt(foundWords_array[i++], 10);
		var direction = (foundWords_array[i++] === '0' ? Enum.Direction.right : Enum.Direction.down);
	
		// Notice: 5 here.
		foundWords[(i/5) - 1] = new Word(value, word, x, y, direction);
	}
}

// Populate missingWords[] with data.
if (wf_missingWords !== "") {
	var missingWords_array = wf_missingWords.split(' ');
	for (var i = 0; i < missingWords_array.length;) {
		var value = null;
		var word = missingWords_array[i++];
		var x = parseInt(missingWords_array[i++], 10);
		var y = parseInt(missingWords_array[i++], 10);
		var direction = (missingWords_array[i++] === '0' ? Enum.Direction.right : Enum.Direction.down);
	
		// Notice: 4 here. (No "value" data in the string.)
		missingWords[(i/4) - 1] = new Word(value, word, x, y, direction);
	}
}



function Square()
{
	var n;
	
	this.letter = '';
	this.premium = Enum.Premium.gen;
	
	// Default constructor argument override.
	// Example usage: var square = new Square({letter:'a', color:'Enum.yellow'});
	for (n in arguments[0]) {
		this[n] = arguments[0][n];
	}
}



function Board()
{
	var x, y, letter;
	
	this.squares = [];
	
	for (x = 0; x < boardLength; ++x) {
		this.squares[x] = [];
		
		for (y = 0; y < boardLength; ++y) {
			letter = wf_board[y * boardLength + x];
			if (!(('a' <= letter && letter <= 'z') || ('A' <= letter && letter <= 'Z'))) {
				letter = '';
			}
			
			this.squares[x][y] = new Square({letter:letter, premium:premiums.charAt(y * boardLength + x)});
		}
	}
}
var board = new Board();










// Adds a highlight behind the (new or missing) word.
function addHighlight(wordObject, color)
{
	var x, y, i;

	x = wordObject.x;
	y = wordObject.y;
	for (i = 0; i < wordObject.word.length; ++i) {
		document.getElementById('div' + x + '.' + y).className = 'highlighted';
		document.getElementById('div' + x + '.' + y).style.backgroundColor = color;
		if (wordObject.direction === Enum.Direction.right) {
			++x;
		} else {
			++y;
		}
	}
}



// Creates a dashed outline around the new word to help further accentuate it.
function addWordAndBorderAndHighlight(wordObject, color)
{
	if (!wordObject) {
		console.warn("addWordAndBorderAndHighlight(wordObject, color): wordObject is null, returning.");
		return;
	}
	
	var x, y, i;
	
	addHighlight(wordObject, color);

	x = wordObject.x;
	y = wordObject.y;
	for (i = 0; i < wordObject.word.length; ++i) {
		document.getElementById('cell' + x + '.' + y).value = wordObject.word.charAt(i);
		
		if (wordObject.direction === Enum.Direction.right) {
			// clear the border between letters
			if (i === 0) {
				document.getElementById('cell' + x + '.' + y).className = 'highlightedSquareL';
			} else if (i === wordObject.word.length - 1) {
				document.getElementById('cell' + x + '.' + y).className = 'highlightedSquareR';
			} else {
				document.getElementById('cell' + x + '.' + y).className = 'highlightedSquareMR';
			}
		} else {
			// clear the border between letters
			if (i === 0) {
				document.getElementById('cell' + x + '.' + y).className = 'highlightedSquareT';
			} else if (i === wordObject.word.length - 1) {
				document.getElementById('cell' + x + '.' + y).className = 'highlightedSquareB';
			} else {
				document.getElementById('cell' + x + '.' + y).className = 'highlightedSquareMD';
			}
		}

		if (wordObject.direction === Enum.Direction.right) {
			++x;
		} else {
			++y;
		}
	}
}



// Removes the dashed outline created by the previous function.
function removeBorder(newWordNum)
{
	var wordObject, newWordObject, x, y, i;	// newWordObject is used to remove flicker caused by removing and immediately readding a border for a new highlighted word.

	wordObject = foundWords[wordNum];
	if (newWordNum !== undefined) {
		newWordObject = foundWords[newWordNum];
	}

	x = wordObject.x;
	y = wordObject.y;
	for (i = 0; i < wordObject.word.length; ++i) {
		if (newWordNum === undefined ||
				!(newWordObject.direction === Enum.Direction.right && y === newWordObject.y && (x >= newWordObject.x && x < newWordObject.x + newWordObject.word.length)) ||
				!(newWordObject.direction === Enum.Direction.down && x === newWordObject.x && (y >= newWordObject.y && y < newWordObject.y + newWordObject.word.length))
			) {
			document.getElementById('cell' + x + '.' + y).className = 'square';
		}
		
		if (wordObject.direction === Enum.Direction.right) {
			++x;
		} else {
			++y;
		}
	}
}



// Removes the highlighting in a cell.
function removeHighlight(x, y)
{
	var cell, color;
	
	cell = document.getElementById('div' + x + '.' + y);
	color = PremiumColors[board.squares[x][y].premium];
	
	// TODO: This shouldn't be necessary, but it is for some reason...
	if (!color) {
		color = '#FFFFFF';
	}
	
	cell.className = 'notHighlighted';
	cell.style.backgroundColor = color;
}



// Removes the dashed outline and highlight around a new word.
// newWordObject WILL BE THE NEW WORD that will be added shortly... it's passed in so that we know not to modify those tiles. (firefox flickered otherwise.)
function removeBorderAndHighlight(newWordNum)
{
	var wordObject, newWordObject, x, y, i;

	wordObject = foundWords[wordNum];
	if (newWordNum !== undefined) {
		newWordObject = foundWords[newWordNum];
	}
	
	removeBorder(newWordNum);

	x = wordObject.x;
	y = wordObject.y;
	for (i = 0; i < wordObject.word.length; ++i) {
		if (newWordNum === undefined ||
			!(newWordObject.direction === Enum.Direction.right && y === newWordObject.y && (x >= newWordObject.x && x < newWordObject.x + newWordObject.word.length)) ||
			!(newWordObject.direction === Enum.Direction.down && x === newWordObject.x && (y >= newWordObject.y && y < newWordObject.y + newWordObject.word.length))
		) {
			removeHighlight(x,y);
		}
		
		if (wordObject.direction === Enum.Direction.right) {
			++x;
		} else {
			++y;
		}
	}
}










//Move left one square.
//This function should never be called if we're in the "tiles" box because the user should remain in that box since it contains multiple characters within it!
function moveLeft()
{
	var x, y;
	
	x = parseInt(cellSelection.substr(4).split('.')[0], 10);
	y = parseInt(cellSelection.substr(4).split('.')[1], 10);
	
	document.getElementById(cellSelection = 'cell' + (x+boardLength-1)%boardLength + '.' + y).focus();
}



// Move right one square.
// This function should never be called if we're in the "tiles" box because the user should remain in that box since it contains multiple characters within it!
function moveRight()
{
	var x, y;
	
	x = parseInt(cellSelection.substr(4).split('.')[0], 10);
	y = parseInt(cellSelection.substr(4).split('.')[1], 10);
	
	document.getElementById(cellSelection = 'cell' + (x+1)%boardLength + '.' + y).focus();
}



// Move up one square.
// If we're on the top row, cycle around to the "tiles" box. If we're in the "tiles" box, move up to the bottom row.
function moveUp()
{
	var x, y;
	
	if (cellSelection === 'tiles')
	{
		document.getElementById(cellSelection = 'cell' + xLast + '.' + (boardLength-1)).focus();
		return;
	}

	x = parseInt(cellSelection.substr(4).split('.')[0], 10);
	y = parseInt(cellSelection.substr(4).split('.')[1], 10);
	
	xLast = x;
	
	if (y === 0) {
		document.getElementById(cellSelection = 'tiles').focus();
	} else {
		document.getElementById(cellSelection = 'cell' + xLast + '.' + (y-1)).focus();
	}
}



// Move down one square.
// If we're on the last row, move to the "tiles" box. If we're in the "tiles" box, cycle around back to the top.
function moveDown()
{
	var x, y;
	
	if (cellSelection === 'tiles')
	{
		document.getElementById(cellSelection = 'cell' + xLast + '.' + 0).focus();
		return;
	}

	x = parseInt(cellSelection.substr(4).split('.')[0], 10);
	y = parseInt(cellSelection.substr(4).split('.')[1], 10);
	
	xLast = x;
	
	if (y === boardLength-1) {
		document.getElementById(cellSelection = 'tiles').focus();
	} else {
		document.getElementById(cellSelection = 'cell' + xLast + '.' + (y+1)).focus();
	}
}



document.onkeydown = 
function keyDown(ev)
{
	var sourceCell;
	
	if (!ev) {
		ev = window.event;
	}

	if (ev.which) {
		keyCode = ev.which;
	} else if (ev.keyCode) {
		keyCode = ev.keyCode;
	} else {
		window.alert('Exception: function keyDown()');
	}

	// don't handle ctrl/alt events
	if (ev.ctrlKey || ev.altKey) {
		return;
	}

	// return false on the below two so we don't output any numbers. just do nothing.
	
	// number row keys
	if (keyCode >= 48 && keyCode <= 57) {
		return false;
	}
	// numpad numeric 0 & 5
	if (keyCode === 96 || keyCode === 101) {
		return false;
	}
	
	if (!(			// arrow keys
					(37 <= keyCode && keyCode <= 40) ||
					// lowercase & uppercase keycodes
					(65 <= keyCode && keyCode <= 90) ||
					// backspace
					keyCode === 8 ||
					// del
					keyCode === 46 ||
					// numpad down/left/right/up
					keyCode === 98 || keyCode === 100 || keyCode === 102 || keyCode === 104 ||	// numbers
					// numpad diagonals
					keyCode === 97 || keyCode === 99 || keyCode === 103 || keyCode === 105 ||	// diagonal numbers
					keyCode === 35 || keyCode === 34 || keyCode === 36 || keyCode === 33		// diagonal arrows
			 )
		) {
		return;
	}
	
	// Don't reverse the order of this if/else. MSIE gets grumpy.
	if (ev.target && ev.target.name) {
		sourceCell = ev.target.name; // other
	} else if (ev.srcElement && ev.srcElement.name) {
		sourceCell = ev.srcElement.name; // MSIE
	}

	if (!sourceCell) {
		document.getElementById(cellSelection).focus();
		// Needed to prevent a double duplicate of the first tile letter input. (?)
		//if (cellSelection === 'tiles') {
		//	return false;	// this line was causing problems with color changing so i commented this out.
		//}
	}
	
	// Per the above line, use cellSelection from here on out...

	if (cellSelection === 'tiles' && (keyCode === 37 || keyCode === 39 || keyCode === 100 || keyCode === 102)) { // left & right
		return;
	}

	if (cellSelection !== 'tiles' && ((keyCode >= 65 && keyCode <= 90) || (keyCode === 8 || keyCode === 46))) {
		if (keyCode >= 65 && keyCode <= 90) { // keyboard letter. could be uppercase or lowercase.
			if (ev.shiftKey) {
				document.getElementById(cellSelection).value = String.fromCharCode(keyCode);
			} else {
				document.getElementById(cellSelection).value = String.fromCharCode(keyCode).toLowerCase();
			}
		}
		if (keyCode === 8 || keyCode === 46) { // backspace & del
			document.getElementById(cellSelection).value = '';
		}
		
		if (page === 'game') {

			// Stops color consistency issues on a later user blur.
			document.getElementById(cellSelection).blur();
			
			x = parseInt(cellSelection.substr(4).split('.')[0], 10);
			y = parseInt(cellSelection.substr(4).split('.')[1], 10);
			
			// Remove the cell's highlighting on edit.
			removeHighlight(x,y);
			
			// If the edit is within a new word, remove the border also.
			if (foundWords[wordNum].direction === Enum.Direction.right) {
				if (y === foundWords[wordNum].y && (x >= foundWords[wordNum].x && x < foundWords[wordNum].x + foundWords[wordNum].word.length)) {
					removeBorder();
				}
			} else {
				if (x === foundWords[wordNum].x && (y >= foundWords[wordNum].y && y < foundWords[wordNum].y + foundWords[wordNum].word.length)) {
					removeBorder();
				}
			}
			
			// Stops color consistency issues on a later user blur.
			document.getElementById(cellSelection).focus();
		
		}
		
		return;
	}
	
	/*jslint white: false */
	
	// vertical/horizontal movements
	if (keyCode === 37 || keyCode === 100) { moveLeft(); return false; }
	else if (keyCode === 38 || keyCode === 104) { moveUp(); return false; }
	else if (keyCode === 39 || keyCode === 102) { moveRight(); return false; }
	else if (keyCode === 40 || keyCode === 98) { moveDown(); return false; }

	// diagonal movements (numpad 1/3/7/9 keys) - always move up/down first to avoid problems with the "tiles" box.
	else if (keyCode === 97 || keyCode === 35) { moveDown(); moveLeft(); return false; }
	else if (keyCode === 99 || keyCode === 34) { moveDown(); moveRight(); return false; }
	else if (keyCode === 103 || keyCode === 36) { moveUp(); moveLeft(); return false; }
	else if (keyCode === 105 || keyCode === 33) { moveUp(); moveRight(); return false; }
	
};










// Some users don't know to not enter all uppercase on the main board, because uppercase represents value-less blank tiles.
// Finish this stub up later.
function verifyNotAllUppercase()
{
	// Temporary function bypass.
	return true;
}



// Used as a logical subroutine of verify() only.
function numberOfBlankTiles()
{
	var tiles, numBlanks, i;
	
	tiles = document.getElementById('tiles').value;
	numBlanks = 0;
	
	for (i = 0; i < tiles.length; ++i) {
		if ((tiles.charAt(i) < 'a' || tiles.charAt(i) > 'z') && (tiles.charAt(i) < 'A' || tiles.charAt(i) > 'Z')) {
			++numBlanks;
		}
	}
	
	return numBlanks;
}



// Make sure that this gets set to false somewhere on page load. There was a bug with users hitting the "back" button and the buttons still being disabled.
function enableFormButtons()
{
	document.getElementById('search').disabled = false;
	document.getElementById('clear').disabled = false;
	return true;
}



// This function is used to prevent users from double clicking "submit" and accidentally submitting the query twice.
function disableFormButtons()
{
	document.getElementById('search').disabled = true;
	document.getElementById('clear').disabled = true;
	return true;
}



// Make sure that we have valid input before we submit the query.
function verify()
{
	if (document.getElementById('tiles').value === '' || numberOfBlankTiles() > 2 || !verifyNotAllUppercase()) {
		//if (document.getElementById('tiles').value === '')
		//	alert('At least one tile must be supplied.');

		if (numberOfBlankTiles() > 2) {
			window.alert('A maximum of two blank tiles may be input.');
		}

		Effect.Shake('divLowerBoardInput', { duration:0.5, distance:10 });
		Effect.Pulsate('tiles', { duration:1.5, pulses:5 });
		(new Effect.Highlight('tiles', { duration:5.0, startcolor:'#ff9999', endcolor:'#ffffff', restorecolor:'#ffffff' } ));
		document.getElementById('tiles').focus();
		return false;
	}

	disableFormButtons();
	return true;
}



var MOVING_DOT_UPDATE_DELAY_IN_MILLISECONDS = 333;
var TOTAL_DOTS = 4;
// Used to make the four dots in "Searching...." move.
function movingDots(numDots)
{
	if (numDots === undefined) {
		numDots = 0;
	} else {
		numDots = parseInt(numDots, 10);
	}
	
	for (var i = 1; i <= TOTAL_DOTS; ++i) {
		if (i <= numDots) {
			document.getElementById('spanDot' + i).style.visibility = 'visible';
		} else {
			document.getElementById('spanDot' + i).style.visibility = 'hidden';
		}
	}
	
	setTimeout('movingDots(' + (numDots+1)%(TOTAL_DOTS+1) + ')', MOVING_DOT_UPDATE_DELAY_IN_MILLISECONDS);
}



// Clears everything on the page and displays "Searching...." in the center of the screen.
function displayPleaseWait()
{
	var stringBuilder, i;
	
	stringBuilder = [];
	
	if (numberOfBlankTiles() === 2) {
		stringBuilder.push('<span class="overlay">Wow, you have two blank tiles!<br /><br />Searching</span>');
	} else {
		stringBuilder.push('<span class="overlay">Searching</span>');
	}
	
	for (i = 1; i <= TOTAL_DOTS; ++i) {
		stringBuilder.push('<span id="spanDot' + i + '" class="overlay">.</span>');
	}
	
	document.getElementById('divCenteredInnerWrapper').innerHTML = stringBuilder.join('');
	
	movingDots();
}



// This function takes all of the form input and converts the (very lengthy 255 or 441 squares worth of board data!) into a much more elegant, compact, intuitive HTTP GET request that the users can now paste to one another to see the same board/page.
function submitBoard()
{
	var stringBuilder, boardValues, tileValues;
	
	if (!verify()) {
		return false;
	} else {
		disableFormButtons();
	}
	
	stringBuilder = [];
	
	for (y = 0; y < boardLength; ++y) {
		for (x = 0; x < boardLength; ++x) {
			if (!document.getElementById('cell' + x + '.' + y).value) {
				stringBuilder.push('-');
			} else {
				stringBuilder.push(document.getElementById('cell' + x + '.' + y).value);
			}
		}
	}
	boardValues = stringBuilder.join('');
	
	// Also save the values of the tiles box since we'll be clearing everything on the screen (including the 'tiles at hand' box) within the next function call.
	tileValues = document.getElementById('tiles').value;
	
	displayPleaseWait();

	document.location.href = '?game=' + wf_game + '&tiles=' + tileValues + '&board=' + boardValues + '&lexicon=' + wf_lexicon;
	
	// Be sure to return false instead here if we're using this function to determine whether or not the browser should handle the submit,
	// because we never want it to.her
	return true;
}



// Clears the board and returns the user to the main page.
function clearBoard()
{
	disableFormButtons();
	document.location.href = '/';
}










//This function is only called by toggleDisplayOfWordDefinition()
function generateWordDefinition()
{
	// if height here is modified, update in 'definitions' file also.
																														//  allowtransparency="true" frameborder="0" are necessary below because of internet explorer. thank you for not being standards compliant as usual, IE.
	document.getElementById('tdWordDefinition').innerHTML = '<iframe id="iframeWordDefinition" class="wordDefinition" height="385" width="180" allowtransparency="true" frameborder="0" src="define.php?word=' + foundWords[wordNum].word.toLowerCase() +'"></iframe>';
	
	document.getElementById('iframeWordDefinition').height = document.getElementById('tdBoard').offsetHeight - 2;
}



var wordDefinitionOn = false;
var wordDefinitionGenerated = false;

//Gets called when the user clicks on the word played to see its definition.
function toggleDisplayOfWordDefinition()
{
	wordDefinitionOn = !wordDefinitionOn;
	
	if (!wordDefinitionGenerated) {
		wordDefinitionGenerated = true;
		generateWordDefinition();
	}

	if (wordDefinitionOn) {
		document.getElementById('iframeWordDefinition').style.display = 'inline';
	} else {
		document.getElementById('iframeWordDefinition').style.display = 'none';
	}
}










// Gets called when the user clicks [more...]
function generateBoard()
{
	var stringBuilder, premiumColor;
	
	board = new Board();
	
	stringBuilder = [];
	
	stringBuilder.push('<table id="tableBoard" class="board"><tbody>');

	for (y = 0; y < boardLength; ++y) {
		stringBuilder.push('<tr>');
		for (x = 0; x < boardLength; ++x) {
			stringBuilder.push('<td>');
			
			premiumColor = PremiumColors[board.squares[x][y].premium];

			switch (board.squares[x][y].premium) {
				case Enum.Premium.ctr:
				case Enum.Premium.dls:
				case Enum.Premium.dws:
				case Enum.Premium.tls:
				case Enum.Premium.tws:
				case Enum.Premium.qls:
				case Enum.Premium.qws:	stringBuilder.push('<div class="premiumSquare" style="background-color:' + premiumColor + '; outline-color:' + premiumColor + ';">'); break;
				case Enum.Premium.spc:	stringBuilder.push('<div class="normalSquare"  style="background-color:' + premiumColor + ';">'); break;
				case Enum.Premium.gen:	stringBuilder.push('<div class="normalSquare"  style="background-color:' + premiumColor + '; outline-color:' + premiumColor + ';">'); break;
				default:				console.error('Exception: printBoardAndWordInfo() - switch (board.squares[x][y].premium)');
			}

				stringBuilder.push('<div class="notHighlighted" id="div' + x + '.' + y + '">');
				
					stringBuilder.push('<input class="square" type="text" size="1" maxlength="1" id="cell' + x + '.' + y + '" name="cell' + x + '.' + y + '" value="" autocomplete="off" onkeydown="this.select();" onkeyup="this.select();" onmouseup="if (cellSelection === \'cell' + x + '.' + y + '\') this.select();" onfocus="previousClassName = this.className; this.className = \'focusedSquare\'; cellSelection = \'cell' + x + '.' + y + '\'; this.select();" onblur="this.className = previousClassName;" />');
	
				stringBuilder.push('</div>');
				
			stringBuilder.push('</div></td>');
		}
	
		stringBuilder.push('</tr>');
	}

	stringBuilder.push('</tbody></table>');

	document.getElementById('tdBoard').innerHTML = stringBuilder.join('');
}



var boardGenerated = false;

// word is an index starting at 0
// OR word is -1 to load the page default (not necessarily 0) determined by 'i' in "&word=i" in the GET request in the URL.
// Here's the heart of our board display generation.
// 1) Create a big string of 225 or 441 'w' 's to indicate that the square should be white.
// 2) Changes these values to an 'r' to indicate that the square should be red. (For missing words.) Print each missing word warning in the same step.
// 3) Change these values to a 'y' to indicate that the square should be yellow. (For the found word.) Print the found word in the same step.
// 4) Generate the board using the above w/r/y values! This is the most complicated step.
// In the last step, if a user goes back and edits one of the 'r' or 'y' squares, JavaScript is written (during this step as well) telling it to reset to a 'w' since they edited the square.
function displayBoardAndWordInfo()
{
	if (!boardGenerated) {
		boardGenerated = true;
		generateBoard();
	}

	if (page === 'game') {
		// We have to build up the string if we're using innerHTML, because you can't append to innerHTML as you go.
		var stringBuilder, i, x , y, missingWordNum, missingWord;
		
		stringBuilder = [];
		for (i = 0; i < missingWords.length; ++i) {
			stringBuilder.push('<h2>Warning: "<span class="redBackground lighterLinkColor">' + missingWords[i].word + '</span>" is invalid.</h2>');
		}
	
		if (foundWords.length !== 0) {
			document.title = 'Lexical Word Finder - ' + wf_game.multipleReplace('_', ' ') + ' - ' + foundWords[wordNum].word + ' for ' + foundWords[wordNum].value + ' points';
			stringBuilder.push('<h2>Played "<a href="#" onclick="toggleDisplayOfWordDefinition(); return false;"' + ((missingWords.length !== 0) ? ' class="yellowBackground">' : '>') + foundWords[wordNum].word + '</a>" for ' + foundWords[wordNum].value + ' points. [<a href="#" onclick="toggleDisplayOfMoreResults(); return false;">more...</a>]</h2>');
		} else {
			stringBuilder.push('<h2>No words found!</h2>');
		}
	
		document.getElementById('captionWordPlayed').innerHTML = stringBuilder.join('');
		stringBuilder = [];
		
		// Fill in the letters.
		for (y = 0; y < boardLength; ++y) {
			for (x = 0; x < boardLength; ++x) {
				document.getElementById('cell' + x + '.' + y).value = board.squares[x][y].letter;
			}
		}

		// Add red missing word highlight.
		for (missingWordNum = 0; missingWordNum < missingWords.length; ++missingWordNum) {
			missingWord = missingWords[missingWordNum];
			
			for (i = 0; i < missingWord.word.length; ++i) {
				addHighlight(missingWord, color_r);
			}
		}
		
		// Add found word, border, and highlight.
		addWordAndBorderAndHighlight(foundWords[wordNum], color_y);
	}
	
	// Reset definition state.
	wordDefinitionGenerated = false;
	wordDefinitionOn = false;
}










// Used from within generateMoreResults() to forward the user to the selected word URL.
function linkToSelectedWord()
{
	document.location.href='?game=' + wf_game + '&tiles=' + wf_tiles + '&board=' + wf_board + '&lexicon=' + wf_lexicon + '&word=' + (wordNum+1);
}

//This function is only called by toggleDisplayOfMoreResults()
function generateMoreResults()
{
	var iframeMoreWords, doc, wordData, i, scrollBarSize;
	
	
	
	// Also change width in "definition" file if width is changed here.
																										  //  allowtransparency="true" frameborder="0" are necessary below because of internet explorer. thank you for not being standards compliant as usual, IE.
	document.getElementById('tdMoreWords').innerHTML = '<!--div id="divMoreResults" style="display:none;"><div--><iframe id="iframeMoreWords" height="385" width="180" allowtransparency="true" frameborder="0"></iframe><!--/div></div-->';
	
	iframeMoreWords = document.getElementById('iframeMoreWords');
	doc = iframeMoreWords.contentDocument;
	if (doc === undefined || doc === null) {
		doc = iframeMoreWords.contentWindow.document;
	}
	doc.open();
	
	wordData = wf_foundWords.split(' ');
	i = 0;

	doc.writeln('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
	doc.writeln('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">');
	doc.writeln('<head>');
	doc.writeln('<title>Lexical Word Finder - ' + wf_game.multipleReplace('_', ' ') + ' - Top ' + (wordData.length/5) + ' Words</title>');
	doc.writeln('<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1" />');
	doc.writeln('<link rel="stylesheet" type="text/css" href="/includes/style.css" />');
	doc.writeln('<![if !IE]>');
	//doc.writeln('<scr'+'ipt ty'+'pe="text/javascript" src="http://www.google.com/jsapi"><\/script>');
	//doc.writeln('<scr'+'ipt ty'+'pe="text/javascript">google.load("jquery", "1.4");<\/script>');
	doc.writeln('<scr'+'ipt ty'+'pe="text/javascript" src="/includes/jquery/jquery-1.4.1.min.js"><\/script>');
	doc.writeln('<scr'+'ipt ty'+'pe="text/javascript" src="/includes/tablesorter/jquery.tablesorter.min.js"><\/script>');
	doc.writeln('<scr'+'ipt ty'+'pe="text/javascript">');
	doc.writeln('$(document).ready(function()');
	doc.writeln('{');
	doc.writeln('	$("#tableMoreWords").tablesorter(');
	doc.writeln('	{');
	doc.writeln('		widgets: ["zebra"]');
	doc.writeln('	});');
					scrollBarSize = scrollBarWidth(window);
	doc.writeln('	parent.document.getElementById("iframeMoreWords").width = ' + ((scrollBarSize && scrollBarSize !== 0) ? scrollBarSize : '17') + ' + document.getElementById("tableMoreWords").offsetWidth;');
	doc.writeln('}); ');
	doc.writeln('<\/script>');
	doc.writeln('<![endif]>');
	doc.writeln('</head>');
	doc.writeln('<body class="moreWords lighterLinks">');
	
	doc.writeln('<table id="tableMoreWords">');
	//																																					(star)
	doc.writeln('<thead><tr><!-- th><big><a href="#" onclick="return false;">#<span></span></a></big></th --><th><big><a href="#" onclick="return false;">&#9733;<span></span></a></big></th><th style="text-align:left;"><big><a href="#" onclick="return false;">word<span></span></a></big></th><th><big><a href="#" onclick="return false;">x<span></span></a></big></th><th><big><a href="#" onclick="return false;">y<span></span></a></big></th><th><big><a href="#" onclick="return false;">&darr;<span></span></a></big></th></tr></thead>');
	doc.writeln('<tbody>');
	while (i < wordData.length) {
		doc.writeln('<tr onmouseover="parent.document.getElementById(parent.cellSelection).blur(); parent.removeBorderAndHighlight(' + (i/5) + '); parent.wordNum=' + (i/5) + '; parent.displayBoardAndWordInfo();" onclick="parent.wordNum=' + (i/5) + '; parent.linkToSelectedWord();">');
		
		doc.writeln('<!-- td>' + ((i/5)+1) + '</td -->');
		doc.writeln('<td>' + wordData[i++] + '</td>');
		doc.writeln('<td>' + wordData[i++] + '</td>');
		doc.writeln('<td>' + (++wordData[i++]) + '</td>');
		doc.writeln('<td>' + (boardLength-wordData[i++]) + '</td>');
		if (wordData[i++] === '0') {
			doc.writeln('<td>&rarr;</td>');
		} else {
			doc.writeln('<td>&darr;</td>');
		}
		
		doc.writeln('</tr>');
	}
	doc.writeln('</tbody>');
	doc.writeln('</table>');
	doc.writeln('</body>');
	doc.writeln('</html>');
	
//	var script = doc.createElement('script');
//	script.src = '/includes/tablesorter/jquery.tablesorter.min.js';
//	script.type = 'text/javascript';
//	doc.getElementsByTagName('head')[0].appendChild(script);
//	
//	script = doc.createElement('script');
//	script.src = '/includes/jquery/jquery-1.4.min.js';
//	script.type = 'text/javascript';
//	doc.getElementsByTagName('head')[0].appendChild(script);

	doc.close();

	iframeMoreWords.height = document.getElementById('tdBoard').offsetHeight - 2;
}



var moreResultsOn = false;
var moreResultsGenerated = false;

// Gets called when the user clicks [more...]
function toggleDisplayOfMoreResults()
{
	moreResultsOn = !moreResultsOn;
	
	if (!moreResultsGenerated) {
		moreResultsGenerated = true;
		generateMoreResults();
	}
	
	//Effect.toggle('divMoreResults', 'slide', { duration:1.0, delay:0.0, scaleX:true, scaleY:false } );
	//Effect.toggle('divMoreResults', 'appear', { duration:1.0, delay:0.0, scaleX:true, scaleY:false } );
	
	if (moreResultsOn) {
		document.getElementById('iframeMoreWords').style.display = 'inline';
	} else {
		document.getElementById('iframeMoreWords').style.display = 'none';
	}
}


