// round to the nearest whatever
function roundto(inputnum, precision) {
	return precision * Math.round(inputnum / precision);
}

// run through an array, return the last occurence of search string
function checkarray(array, lookingfor) {
	for (i = 0; i < array.length; i++) {
		if (array[i] == lookingfor) {
			return i;
		}
	}
	return -1;
}

// make it so an object is added, not just a single value
function playedthis (tileid, location) {
	this.filler = tileid;
	this.location = location;
}

// register removal from tilesit
function movedcheck(object) {
	tilesitcount--;
	tilesitcontents[object.tilesit] = false;
	object.tilesit = false;
	var square = object.location;
	if (square) {
		board[square].filler = false;
		board[square].points = false;
	}
	for (i = 0; i < playedthisturn.length; i++) {
		if (playedthisturn[i].location == object.location) {
			playedthisturn.splice(i, 1);
		}
	}
	if (object.id.charAt(0) == '_') {
		blank[object.id.charAt(1) - 1] = false;
	}
}

// when stopping dragging, snap to grid
function snapto(object) {
	// make sure the current tile is always on top
	object.onDragStart = function() {
		topzindex++;
		object.style.zIndex = topzindex;
	}

	// snap to the right tile, take note of what's going on
	object.onDragEnd = function(x, y) {
		var boardsquare = (15 * ((roundto(y, 40) - 80) / 40)) + ((roundto(x, 40) - 40) / 40);
		if ((x <= 20) || (x >= 620) || (y <= 60) || (y >= 660)) {
			filltilesit(object);
		}
		else if ((board[boardsquare].filler) && (!(board[boardsquare].filler == object.id))) {
			alert("Tile is already full");
			filltilesit(object);
		}
		else {
			movedcheck(object);
			object.style.top = roundto(y, 40) + "px";
			object.style.left = roundto(x, 40) + "px";
			object.location = boardsquare;
			playedthisturn.unshift(new playedthis(object.id, boardsquare));
			board[boardsquare].filler = object.id;
			board[boardsquare].newtile = true;
			board[boardsquare].points = object.points;
			if (object.id.charAt(0) == '_') {
				sortoutblank(object);
			}
		}
	}
}

// make sure valid input given for blank question
function sortoutblank(object) {
	var alphabet = new Array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); // nonsense one at start, since 0 == false
	var answer = prompt('Which letter do you want this blank tile to represent?', '').toLowerCase();
	if ((answer.length == 1) && (checkarray(alphabet, answer) != -1)) {
		blank[object.id.charAt(1) - 1] = answer;
	}
	else {
		sortoutblank(object);
	}
}

// wotsit to deal with tiles being brought into play
function filltilesit(object) {
	movedcheck(object);
	tilesitcount++;
	object.location = false;
	var lowest = checkarray(tilesitcontents, false);
	object.tilesit = lowest;
	object.style.left = 660 + "px";
	object.style.top = 200 + (lowest * 50) + "px";
	object.style.zIndex = topzindex;
	tilesitcontents[lowest] = object.id;
}

// things to do at end of turn - fix tiles in place
function endturn() {
	if (checkmoves()) {
		for (i = 0; i < playedthisturn.length; i++) {
			var tile = document.getElementById(playedthisturn[i].filler);
			Drag.init(tile, null, tile.style.left, tile.style.left, tile.style.top, tile.style.top);
			tile.style.zIndex = 2;
		}
		for (i = 0; i < tilesitcontents.length; i++) {
			if ((!tilesitcontents[i]) && (Letters.length)) {
				picktile();
			}
		}
		getscore();
		playedthisturn.splice(0, playedthisturn.length);
		words.splice(0, words.length);
		for (i = 0; i < board.length; i++) {
			board[i].newtile = false;
		}
		turnnum++;
		if ((!Letters.length) && (!tilesitcount)) {
			document.getElementById('endturnbutton').disabled = true;
			document.getElementById('swaptilesbutton').disabled = true;
		}
	}
}

// check everything is hunky dory and valid
function checkmoves() {
	if (!board[112].filler) {
		alert('You must fill the middle square on the first turn.');
		return false;
	}
	if (playedthisturn.length == 0) {
		alert('You must play at least one tile');
		return false;
	}
	if (!allinrow()) {
		alert('All tiles must be in a straight line.');
		return false;
	}
	if (!allcontinuous()) {
		alert('No gaps are allowed between letters in a word.');
		return false;
	}
	if (!attachedproperly()) {
		alert('New words must be joined to ones already on the board.');
		return false;
	}
	getwords();
	if (!words.length) {
		getwords();
	}
	if (!spellcheckall()) {
		alert('Word was not found in dictionary.');
		return false;
	}
	return true;
}

// check all the tiles played are in one line
function allinrow() {
	var countmoves = playedthisturn.length;
	var gotupto = 1;
	var sideways = false;
	var reftile = playedthisturn[0].location;

	rowstart = reftile - (reftile % 15);
	rowend = rowstart + 14;

	// check if all the tiles are in the same row
	for (j = 1; j < playedthisturn.length; j++) {
		var thislocation = playedthisturn[j].location;
		if ((thislocation >= rowstart) && (thislocation <= rowend)) {
			gotupto++;
			sideways = true;
		}
	}

	// and if they ain't, try looking at columns
	if (!sideways) {
		for (k = 1; k < playedthisturn.length; k++) {
			if ((playedthisturn[k].location % 15) == (reftile % 15)) {
				gotupto++;
			}
		}
	}

	// if all tiles are accounted for, then move is valid
	return (gotupto == countmoves);
}

// get a list of which tiles to check (if we're next to an edge, for instance)
function whichtocheck(square) {
	var squares = new Array();
	if ((square % 15) != 0) {
		squares.push(square - 1);
	}
	if ((square % 15) != 14) {
		squares.push(square + 1);
	}
	if ((square - 15) >= 0) {
		squares.push(square - 15);
	}
	if ((square + 15) <= 224) {
		squares.push(square + 15);
	}
	return squares;
}

// check all tiles are attached to another
function attached(square) {
	var checked = 0;
	var squareschecked = whichtocheck(square);
	for (m = 0; m < squareschecked.length; m++) {
		if (board[squareschecked[m]].filler) {
			checked++;
		}
	}
	return checked;
}

// also need to check that the lines all join on to proper ones
function allcontinuous() {
	// deal with just adding one tile
	if (playedthisturn.length == 1) {
		return true;
	}

	// now to deal with having more than one
	// this checks everything is connected to something
	for (i = 0; i < playedthisturn.length; i++) {
		if (attached(playedthisturn[i].location) == 0) {
			return false;
		}
	}

	// check there's no gap between wotsits in a column/row - already know they're all in the same one
	var issideways = sidewayscheck();
	gap = getgap(issideways);
	var limit = 2;
	var endones = 0;
	for (i = 0; i < playedthisturn.length; i++) {
		var location = playedthisturn[i].location;
		var onebefore = location - gap;
		var oneafter = location + gap;
		
		if ((!issideways) && ((onebefore < 0) || (oneafter > 224))) {
			endones++;
			continue;
		}
		if ((issideways) && ((location % 15 == 0) || (location % 15 == 14))) {
			endones++;
			continue;
		}
		if (!board[onebefore].filler) {
			endones++;
			continue;
		}
		if (!board[oneafter].filler) {
			endones++;
			continue;
		}
	}
	return (endones <= limit);
}

// check new words are joined onto old ones
function attachedproperly() {
	if (turnnum == 0) {
		return true;
	}

	if ((playedthisturn.length == 1) && (attached(playedthisturn[0].location) == 0)) {
		return false;
	}

	var list = new Array();
	for (i = 0; i < playedthisturn.length; i++) {
		list = list.concat(whichtocheck(playedthisturn[i].location));
	}

	for (i = 0; i < playedthisturn.length; i++) {
		var list = whichtocheck(playedthisturn[i].location);
		for (j = 0; j < list.length; j++) {
			if ((board[list[j]].filler) && (!board[list[j]].newtile)) {
				return true;
			}
		}
	}

	return false;
}

// check if sideways or not
function sidewayscheck() {
	if (playedthisturn.length == 1) {
		var played = playedthisturn[0].location;
		return ((board[played - 1].filler) || (board[played + 1].filler));
	}
	else {
		return ((playedthisturn[0].location % 15) != (playedthisturn[1].location % 15));
	}
}

// get the gap based on the input
function getgap(basis) {
	if (basis) {
		return 1;
	}
	return 15;
}

// now the move is ok, calculate score
function getscore() {
	for (i = 0; i < words.length; i++) {
		totalscore += words[i].points;
	}

	// if you used all your tiles, a bonus!
	if (playedthisturn.length == 7) {
		totalscore += 50;
	}

	// sort out cleaning used word bonuses
	for (i = 0; i < usedwbonus.length; i++) {
		board[usedwbonus[i]].tw = false;
		board[usedwbonus[i]].dw = false;
	}
	usedwbonus.splice(0, usedwbonus.length); // i don't know why it has to be a global array, but it does

	// now we've got it, flaunt it
	var tbody = document.getElementById('tbody1p');
	var newrow = tbody.insertRow(1);
	var newcol = newrow.appendChild(document.createElement('td'));
	newcol.appendChild(document.createTextNode(totalscore));
	if (tbody.rows.length > 11) {
		document.getElementById('scoretable1p').deleteRow(tbody.rows.length - 1);
	}
	newrow.style.fontWeight = 'bold';
	if (tbody.rows.length > 2) {
		tbody.rows[2].style.fontWeight = 'normal';
	}
}

// gives you a fresh pick
function swaptiles() {
	if (playedthisturn.length) {
		alert('You can\'t swap your tiles if you\'ve played any');
	}
	else {
		var boarddiv = document.getElementById('boarddiv');
		for (i = 0; i < tilesitcontents.length; i++) {
			if (tilesitcontents[i]) {
				var object = document.getElementById(tilesitcontents[i]);
				Letters.push(new letters(object.id, object.points));
				boarddiv.removeChild(object);
				tilesitcontents[i] = false;
				picktile();
			}
		}
	}
}

// pick a tile from the hat and get it ready
function picktile() {
	var numtouse = Math.round(Math.random() * Letters.length);
	var data = Letters[numtouse];
	if (data) {
		newtile = document.getElementById('boarddiv').appendChild(document.createElement('img'));
		newtile.id = data.id;
		var letter = data.id.charAt(0);
		var points = data.points;
		newtile.src = '../tiles/' + letter + '.gif';
		newtile.alt = letter + ': ' + points;
		newtile.style.position = 'absolute';
		Drag.init(newtile);
		snapto(newtile);
		newtile.points = points;
		newtile.location = false;
		filltilesit(newtile);
		Letters.splice(numtouse, 1);
	}
	else {
		picktile();
	}
}

// needed to fill in info about each word
function word(letters, points, dw, tw) {
	this.letters = letters;
	this.points = points;
}

// get all the words
function getwords() {
	// first the main word
	var mainwordsideways = sidewayscheck();
	getthisword(playedthisturn[0].location, mainwordsideways);

	// then the other, side words
	extrawordsgap = getgap(!mainwordsideways);
	for (i = 0; i < playedthisturn.length; i++) {
		var thistile = playedthisturn[i].location;
		var tilebefore = thistile - extrawordsgap;
		var tileafter = thistile + extrawordsgap;
		// if attached in the opposite alignment, then do that word
		neighbours = whichtocheck(thistile);
		for (j = 0; j < neighbours.length; j++) {
			var tileinquestion = neighbours[j];
			if ((tileinquestion != tilebefore) && (tileinquestion != tileafter)) {
				neighbours.splice(j, 1);
				j--;
			}
		}
		for (j = 0; j < neighbours.length; j++) {
			if (board[neighbours[j]].filler) {
				getthisword(thistile, !mainwordsideways);
				break;
			}
		}
	}

}

// get the actual word to be used
function getthisword(startpoint, direction) {
	var thisword = '';
	var thispoints = 0;
	var thisdw = 0;
	var thistw = 0;
	
	gap = getgap(direction);
	for (i = 0; i < 15; i++) {
		var onebefore = startpoint - ((i + 1) * gap);
		if (onebefore < 0) {
			var firstinline = onebefore + gap;
			break;
		}
		if ((direction) && ((onebefore % 15) == 14)) {
			var firstinline = onebefore + gap;
			break;
		}
		if ((!direction) && (onebefore < 0)) {
			var firstinline = onebefore + gap;
			break;
		}
		if (!board[onebefore].filler) {
			var firstinline = onebefore + gap;
			break;
		}
	}
	for (i = 0; i < 15; i++) {
		var oneafter = startpoint + ((i + 1) * gap);
		if (oneafter > 224) {
			var lastinline = oneafter - gap;
			break;
		}
		if ((direction) && ((oneafter % 15) == 0)) {
			var lastinline = oneafter - gap;
			break;
		}
		if ((!direction) && (onebefore > 224)) {
			var lastinline = oneafter - gap;
			break;
		}
		if (!board[oneafter].filler) {
			var lastinline = oneafter - gap;
			break;
		}
	}
	for (i = firstinline; i <= lastinline; i += gap) {
		var boardsquare = board[i];
		var letter = boardsquare.filler.charAt(0);
		var letterpoints = boardsquare.points;
		thispoints += letterpoints;
		if (letter == '_') {
			letter = blank[boardsquare.filler.charAt(1) - 1];
		}
		if (boardsquare.dl) {
			thispoints += letterpoints;
			boardsquare.dl = false;
		}
		if (boardsquare.tl) {
			thispoints += (2 * letterpoints);
			boardsquare.tl = false;
		}
		if (boardsquare.dw) {
			thisdw++;
			usedwbonus.push(i);
		}
		if (boardsquare.tw) {
			thistw++;
			usedwbonus.push(i);
		}
		thisword += letter;
	}
	if (thisdw) {
		thispoints *= (thisdw * 2);
	}
	if (thistw) {
		thispoints *= (thistw * 3);
	}	
	words.push(new word(thisword, thispoints));
}

// container function, giving a value if all match
function spellcheckall() {
	var wordsok = 0;
	for (i = 0; i < words.length; i++) {
		if (spellcheck(words[i].letters)) {
			wordsok++;
		}
	}
	if (wordsok != words.length) {
		words.splice(0, words.length);
		return false;
	}
	return true;
}

// complicated spellchecker
function spellcheck(thisword) {
	if (thisword == 'a') {
		return true;
	}
	if (thisword == 'i') {
		return true;
	}
	if (thisword.length == 1) {
		return false;
	}
	var check = GetXMLFile('../checkdict.php?word=' + thisword);
	if (check == 'true') {
		return true;
	}
	else {
		return false;
	}
}

// this reads the dictionary file
// dictionary files courtesy of ENABLE2K wordlist, ta!
function GetXMLFile(sourceURL)	{
	var xmlhttp = null;
	var doc = null;

	if (window.XMLHttpRequest) {
		xmlhttp = new XMLHttpRequest();
	}
	else {
		xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
	}
	if (xmlhttp) {
		xmlhttp.open('GET', sourceURL, false);
		xmlhttp.send(null);
		doc = xmlhttp.responseText;
	}
	return doc;
}
