//The index of the last cell in a row or column
var LAST_CELL = 8

//The normal (no error in cell) colors for each of the input cells
var cellColors = new Array()

//Store the normal color of each cell so that we can alternate between this
//color and the "contains an error" color as the user enters and removes error
//values in the cells.
//This function should not be called until all of the input cells have been
//created.
function storeCellColors() {
    for(var row = 0; row <= LAST_CELL; row++) {
	cellColors[row] = new Array()
	for(var col = 0; col <= LAST_CELL; col++) {
	    var element = document.forms[0].elements["cell_" + row + "_" + col]
	    cellColors[row][col] = element.style.backgroundColor
	}
    }
}

//Remove whitespace from the beginning and end of a String
//This method is added to the standard String class
String.prototype.trim = function() {
    return this.replace(/^\s*|\s*$|^\s*$/g, '')
}

//Called when the user clicks the "Solve" button.
//Checks that all of the values entered by the user are valid (every cell
//should either be blank or contain a value between 1 and 9).
function checkInput(form) {
    var isOk = true
    for(var row = 0; row <= LAST_CELL; row++) {
	for(var col = 0; col <= LAST_CELL; col++) {
	    var element = form.elements["cell_" + row + "_" + col]
	    var val = element.value.trim()
	    var intVal = parseInt(val, 10)
	    if(val == ""  || (1 <= intVal && intVal <= 9)) {
		//Cell value is OK
		//Set the cell color to its normal color to show that it does
		//not contain an error
		element.style.backgroundColor = cellColors[row][col]

                //Set the cell value to what we understand it to be
		element.value = (val == "" ? val : intVal)
	    } else {
		//Cell value is not OK
		//Set the cell color to red to show that it contains an error
		element.style.backgroundColor = "#ff9999"
		isOk = false
	    }
	}
    }
    return isOk
}

//Returns all the game values entered by the user as a string of name=value
//pairs where name is the name of the form element and value is the value
//entered by the user.
function getGameValues(form) {
    var str = "";

    for(var i = 0; i < form.elements.length; i++) {
        var nextElement = form.elements[i]
        str += form.elements[i].name + "=" +
                escape(form.elements[i].value) + "&";
    }

    if(str.length > 1) {
        str = str.substr(0, (str.length - 1)); //lose the final "&" character
    }
    return str;
}

var xmlHttp = GetXmlHttpObject() //XML HTTP object

//Get the solution and dynamically load it into the solution <div> using
//the XML HTTP object (AJAX).
function getSolution(form) {
    if(xmlHttp === null) {
        alert("Browser does not support HTTP Request")
    } else if(!checkInput(form)) {
	alert("Invalid data input. All cells should contain a value " +
	      "between 1 and 9 or be blank.")
    } else {
        document.getElementById("solution").innerHTML = "Solving..." 
        var url = "solve.php5"
        xmlHttp.onreadystatechange = stateChanged
        xmlHttp.open("POST", url, true)
        xmlHttp.setRequestHeader("Content-Type",
                "application/x-www-form-urlencoded; charset=UTF-8")
        xmlHttp.send(getGameValues(form))
    }
}

//Called when the XML HTTP object state changes
function stateChanged() {
    if (xmlHttp.readyState == 4 || xmlHttp.readyState == "complete") {
        document.getElementById("solution").innerHTML = xmlHttp.responseText 
    }
}

//Get the XML HTTP object (requires different code for different browsers)
function GetXmlHttpObject() {
    var objXMLHttp = null
    if (window.XMLHttpRequest) {
        //Firefox, Opera, etc.
        objXMLHttp = new XMLHttpRequest()
    } else if (window.ActiveXObject) {
        //Internet Explorer
        objXMLHttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
    return objXMLHttp
}
