/**
 * Author:       Matthew Hearn
 * Date:         3/4/10
 * File:         splitit.js
 * Description:  Handles AJAX response from splitter
 *               and contains other various splitter page functions.
 */

var request;   // AJAX response

/**
 * Places "Answer" back in answer text box.
 *
 * Input:   The text box
 * Ouptut:  Nothing
 */

function blurAnswerBox(textBox)
{
    // If the box is empty, put "Answer" back in
    
    if (textBox.value == "")
    {
        textBox.value = "Answer";
        textBox.setAttribute("style", "color: gray;");
    }
}

/**
 * Cleans the given string of potentially dangerous characters.
 *
 * Input:   toClean - the string to clean
 * Ouptut:  The cleaned string
 */

function clean(toClean)
{
    toClean = toClean.replace("#", "");
    toClean = toClean.replace("&", "");
    toClean = toClean.replace("!", "");
    toClean = toClean.replace("\\", "");
    toClean = toClean.replace("/", "");
    toClean = toClean.replace("\n", "");
    toClean = toClean.replace("\r", "");
    toClean = toClean.replace("\t", "");
    toClean = toClean.replace("`", "");
    toClean = toClean.replace(";", "");
    toClean = toClean.replace("|", "");
    toClean = toClean.replace("(", "");
    toClean = toClean.replace(")", "");
    toClean = toClean.replace("[", "");
    toClean = toClean.replace("]", "");
    toClean = toClean.replace("{", "");
    toClean = toClean.replace("}", "");
    toClean = toClean.replace("*", "");
    toClean = toClean.replace("?", "");
    toClean = toClean.replace("<", "");
    toClean = toClean.replace(">", "");
    toClean = toClean.replace("^", "");
    toClean = toClean.replace("~", "");

    return toClean;
}

/**
 * Clears the given div (removes all children).
 *
 * Input:  toClear - the div to clear
 * Output:  The cleared div
 */

function clearDiv(toClear)
{
    if (toClear.hasChildNodes())
        while (toClear.childNodes.length > 0)
            toClear.removeChild(toClear.firstChild);

    return toClear;
}

/**
 * Fixes identifer by removing spaces and dashes and replacing
 * them with underscores so the splitter can properly parse them.
 *
 * Input:   id - the identifier
 * Output:  the fixed identifier
 */

function fixIdentifier(id)
{
    id = id.replace(/[ \-]/g, "_");
    return id;
}

/**
 * Removes "Answer" back in answer text box.
 *
 * Input:   The text box
 * Ouptut:  Nothing
 */

function focusAnswerBox(textBox)
{
    textBox.value = "";
    textBox.setAttribute("style", "color: black;");
}

/**
 * Checks if the given string is a number.
 *
 * Input:  num - the string to check
 * Output:  True if the string is a number
 */

function isNumber(num)
{
    return num.match(/^[0-9]+$/);
}

/**
 * Purpose:  Checks if the id field is filled in.
 * Input:    (nothing)
 * Output:   True if the id field is filled in
 */

function isSplitFieldComplete()
{
    var inputField = document.getElementById("input_field");
    var nField = document.getElementById("n_field");

    var idFieldValue = inputField.value.replace(/^\s+|\s+$/, "");
    idFieldValue = clean(idFieldValue);

    var nFieldValue = nField.value.replace(/^\s+|\s+$/, "");
    nFieldValue = clean(nFieldValue);

    // Check to see if the split type is gentest before spitting
    // out the error message

    var splitTypes = document.getElementsByName("split_type");
    var splitType = "";

    for (var i = 0; i < splitTypes.length; i++)
    {
        if (splitTypes[i].checked)
            splitType = splitTypes[i].value;
    }

    if (idFieldValue == "")
    {
        alert("Please enter a valid identifier!");
        return false;
    }
    else if (!isValidId(idFieldValue))
    {
        alert("The given identifer has invalid characters.");
        return false;
    }
    else if (nFieldValue == "")
    {
        // If conservative, number of splits == -1 as a flag

        if (splitType === "gentest")
        {
            alert("Please enter a value for top number of splits"
                  + "greater than 0 and less than 100!");
            return false;
        }
    }
    else if (parseInt(nFieldValue) < 0 || parseInt(nFieldValue) > 100)
    {
        if (splitType === "gentest")
        {
            alert("Please enter a value for top number of splits"
                  + "greater than 0 and less than 100!");
            return false;
        }
    }

    return true;
}

/**
 * Checks that the given string is a valid identifier.
 *
 * Input:   id - the identifier
 * Output:  True if id is a valid identifier
 */

function isValidId(id)
{
    return id.match(/^[ 0-9a-zA-Z\$_-]+$/);
}

/**
 * Gets the data with AJAX.
 */

function split()
{
    if (!isSplitFieldComplete())
        return false;

    document.getElementById("thank_you").innerHTML = "";

    var rand = parseInt(Math.random() * 99999999999);

    var toSplit = document.getElementById("input_field").value;
    toSplit = toSplit.replace(/^\s+|\s+$/, "");

    toSplit = fixIdentifier(toSplit);

    var langRadioButtons = document.getElementsByName("language");
    var lang = "";

    // Get the selected language
    
    for (var i = 0; i < langRadioButtons.length; i++)
    {
        if (langRadioButtons[i].checked)
            lang = langRadioButtons[i].value;
    }

    var nField = document.getElementById("n_field");
    var n = nField.value;

    // Find checked split type

    var splitTypes = document.getElementsByName("split_type");
    var splitType = "";

    for (var i = 0; i < splitTypes.length; i++)
    {
        if (splitTypes[i].checked)
            splitType = splitTypes[i].value;
    }

    // If conservative, number of splits == -1 as a flag

    if (splitType === "conservative")
        n = -1;

    // Add the loading text

    var outputDiv = document.getElementById("output_div");
    var loadingGif = document.createElement("img");
    var loadingDiv = document.createElement("div");

    loadingGif.setAttribute("src", "images/loading.gif");
    loadingGif.setAttribute("alt", "Loading...  Please wait.");

    loadingDiv.setAttribute("class", "loading");
    loadingDiv.appendChild(loadingGif);

    outputDiv = clearDiv(outputDiv);
    outputDiv.appendChild(loadingDiv);

    // Send the request

    var url = "cgi/splitit.cgi?id=" + toSplit + "&lang=" + lang + "&n=" + n + "&rand=" + rand;

    request = new XMLHttpRequest();
    request.open("GET", url, true);
    request.onreadystatechange = responseAjaxSplit;
    request.send(null);

    return true;
}

/**
 * Handles AJAX response after split.
 */

function responseAjaxSplit()
{
    if (request.readyState == 4)
    {
        if (request.status == 200)
            updateSplit(request.responseText);
    }
}

/**
 * Handles AJAX response after submitting correct splits.
 */

function responseAjaxCorrections()
{
    if (request.readyState == 4)
        updateCorrections();
}

/**
 * Updates the screen after changes have been submitted.
 */

function updateCorrections()
{
    document.getElementById("thank_you").innerHTML = "Thank you!";
    document.getElementById("submit_correct").disabled = true;
}

/**
 * Updates split text area.
 */

function updateSplit(split)
{
    split = split.replace(/^\s+|\s+$/, "")
    processResults(split);
}

/**
 * Processes the enter key function.
 *
 * Input:   e - the event
 * Output:  true if the form is filled out
 */

function processKey(e)
{
    if (e == null)
        e = window.event;
    if (e.keyCode == 13)
        return split();
}

/**
 * Processes the output from the splitter.
 *
 * Input:   split - the splitter data
 * Output:  None
 */

function processResults(split)
{
    if (split === "")
        return false;

    var outputDiv = document.getElementById("output_div");

    // Clear the output window

    outputDiv = clearDiv(outputDiv);

    var splits = [];
    splits = split.split("\n");

    // Add the newly founds splits to the output window

    var hardWordNum = 1;

    var currOutputCol = document.createElement("div");
    currOutputCol.setAttribute("id", "hard_word" + hardWordNum);
    currOutputCol.setAttribute("class", "output_column");

    outputDiv.appendChild(currOutputCol);

    // Create the split windows for each hard word and append them
    // to the output window

    var isNewHardWord = true;   // True if starting new hard word

    for (var i in splits)
    {
        var currSplit = splits[i].split("\t");
        var item = document.createElement("input");

        // If we're at a new hard word, create a new window

        if (currSplit[0] != hardWordNum)
        {
            hardWordNum = parseFloat(currSplit[0]);
            currOutputCol = document.createElement("div");
            currOutputCol.setAttribute("id", "hard_word" + hardWordNum);
            currOutputCol.setAttribute("class", "output_column");
            outputDiv.appendChild(currOutputCol);
            isNewHardWord = true;
        }

        item.setAttribute("type", "radio");
        item.setAttribute("name", "splits" + hardWordNum);

        if (!isNewHardWord)
            item.setAttribute("value", currSplit[1]);
        else
        {
            item.setAttribute("checked", "checked");
            item.setAttribute("value", "custom" + hardWordNum);
        }

        var splitText = document.createTextNode(currSplit[1]);
        var br = document.createElement("br");

        currOutputCol.appendChild(item);

        // If this is not a new hard word, just keep adding
        // the splits.
        // If it is, then make the first a text box.

        if (!isNewHardWord)
            currOutputCol.appendChild(splitText);
        else
        {
            var customTextBox = document.createElement("input");
            customTextBox.setAttribute("id", "custom" + hardWordNum);
            customTextBox.setAttribute("name", "custom" + hardWordNum);
            customTextBox.setAttribute("value", "Answer");
            customTextBox.setAttribute("size", "10");
            customTextBox.setAttribute("onfocus", "focusAnswerBox(this);");
            customTextBox.setAttribute("onblur", "blurAnswerBox(this);");
            customTextBox.setAttribute("style", "color: gray;");

            currOutputCol.appendChild(customTextBox);
            currOutputCol.appendChild(document.createElement("br"));

            item = document.createElement("input");
            item.setAttribute("type", "radio");
            item.setAttribute("name", "splits" + hardWordNum);
            item.setAttribute("value", currSplit[1]);
            currOutputCol.appendChild(item);
            currOutputCol.appendChild(splitText);
        }

        currOutputCol.appendChild(br);

        isNewHardWord = false;
    }

    if (hardWordNum > 1)
    {
        document.getElementById("is_are").innerHTML = "are";
        document.getElementById("s").innerHTML = "s";
    }
    else
    {
        document.getElementById("is_are").innerHTML = "is";
        document.getElementById("s").innerHTML = "";
    }

    document.getElementById("num_hard_words").innerHTML = hardWordNum;
    document.getElementById("submit_correct").disabled = false;
}

/**
 * Send the selected changes to the data file.
 */

function sendChanges()
{
    if (!isSplitFieldComplete())
        return false;

    var outputDiv = document.getElementById("output_div");

    var rand = parseInt(Math.random() * 99999999999);

    var toSplit = document.getElementById("input_field").value;
    toSplit = toSplit.replace(/^\s+|\s+$/, "");

    var langRadioButtons = document.getElementsByName("language");
    var lang = "";

    // Get the selected language
    
    for (var i = 0; i < langRadioButtons.length; i++)
    {
        if (langRadioButtons[i].checked)
            lang = langRadioButtons[i].value;
    }

    var nField = document.getElementById("n_field");
    var n = nField.value;

    // Find checked split type

    var splitTypes = document.getElementsByName("split_type");
    var splitType = "";

    for (var i = 0; i < splitTypes.length; i++)
    {
        if (splitTypes[i].checked)
            splitType = splitTypes[i].value;
    }

    // If conservative, number of splits == -1 as a flag

    if (splitType === "conservative")
        n = -1;

    var url = "cgi/send-corrections.cgi?id=" + toSplit + "&lang=" + lang + "&n=" + n + "&split_type=" + splitType;

    // Check that a correction has been checked off for
    // each hard word

    // For each hard word...

    var hardWordDivs = document.getElementById("output_div").childNodes;

    for (var i in hardWordDivs)
    {
        // For each split...

        var splits = hardWordDivs[i].childNodes;
        
        for (var j in splits)
        {
            if (splits[j].checked)
            {
                var toAdd = "";
                if (j == 0) // If the text box is selected
                    toAdd = clean(splits[j + 1].value);
                else
                    toAdd = splits[j].value;

                url += "&" + hardWordDivs[i].id + "=" + toAdd;
                break;
            }
        }
    }

    // Send the data

    url += "&rand=" + rand;

    request = new XMLHttpRequest();
    request.open("GET", url, true);
    request.onreadystatechange = responseAjaxCorrections;
    request.send(null);

    return true;
}

