/* -----------------------------------------------------------------------------
  Last Updated On:  08/26/08
  Procedural and OO interfaces to pipe-delimited AJAX communication.
----------------------------------------------------------------------------- */

// Global vars and method for both interfaces
var resultsToMethod = '';
var resultsToMethodQueue = new Array;
resultsToMethodQueue.length = 0;
var timerID;

function processReqChange() {
// Intermediary function that waits around for a response from the server.

    if (req.readyState == 4) {
    // only if req shows "complete"
        if (req.status == 200) {
        // If status is "ok" then process the results
            response = (req.responseText) ? req.responseText : 'NO RESPONSE';
            var escapedResponse = escape(response);
            clearTimeout(timerID);
            eval(resultsToMethod + '(\'' + escapedResponse + '\');');
            processReqQueue();
        }
        else {
            resultsToMethod = '';
            alert(req.status + ": There was a problem connecting to the server.  Please try again.");
            return false;
        }
    }
}


function processReqQueue() {
// In case there is a back-up of AJAX requests waiting to process, this will
// move the queue up one process, and execute it.

    if (resultsToMethodQueue.length > 0) {

        var nextProcess = resultsToMethodQueue[0];
        for (var i = 0; i <= resultsToMethodQueue.length - 2; i++) {
            resultsToMethodQueue[i] = resultsToMethodQueue[i + 1];
        }
        resultsToMethodQueue.length--;
        resultsToMethod = '';
        eval(nextProcess + '(\'\')');

    }
    else {
        resultsToMethod = '';
    }
}


/* -----------------------------------------------------------------------------
  OO INTERFACE
----------------------------------------------------------------------------- */

function ajax(resultsToMethod) {

    // Basic vars
    this.queryString = '';
    this.resultsToMethod = resultsToMethod;
    this.option = '';
    this.requiredFieldsConditionalTestResult = 0;
    this.requiredConditionalFields = new Array;

    // Methods
    this.requiredFields = requiredFields;
    this.requiredFieldsConditional = requiredFieldsConditional;
    this.verifySave = verifySave;
    this.verifyDelete = verifyDelete;
    this.setFields = setFields;
    this.setSession = setSession;
    this.setOption = setOption;
    this.postRequest = postRequest;
    this.getRequest = getRequest;

}


function requiredFields(fieldPairs) {
/*  Given an array of character delimited name value pairs (in the format
    "HTML Element Name=>Error Message Label"), check each HTML element for
    a value.  If one exists, move on, if one doesn't, display the error
    message using the "Error Message Label."
*/

    for (var i = 0; i < fieldPairs.length; i++) {

        var keyData = fieldPairs[i].split('=>');
        var key = keyData[0];
        var label = keyData[1];

        if (document.forms[0].elements[key]) {
            switch (document.forms[0].elements[key].type) {
            case 'hidden':
                if (document.forms[0].elements[key].value == '') {
                    alert("Please respond to the '" + label + "' question before continuing.");
                    return false;
                }
                break;

            case 'text':
                if (document.forms[0].elements[key].value == '') {
                    alert("Please respond to the '" + label + "' question before continuing.");
                    return false;
                }
                break;

            case 'checkbox':
                if (document.forms[0].elements[key].checked == false) {
                    alert("Please respond to the '" + label + "' question before continuing.");
                    return false;
                }
                break;

            case 'select-one':
                if ((document.forms[0].elements[key].selectedIndex < 0) ||
                    (document.forms[0].elements[key][document.forms[0].elements[key].selectedIndex].value == '')) {
                    alert("Please respond to the '" + label + "' question before continuing.");
                    return false;
                }
                break;

            case 'select-multiple':
                if ((document.forms[0].elements[key].selectedIndex) ||
                    (document.forms[0].elements[key][document.forms[0].elements[key].selectedIndex].value == '')) {
                    alert("Please respond to the '" + label + "' question before continuing.");
                    return false;
                }
                break;

            case 'textarea':
                if (document.forms[0].elements[key].value == '') {
                    alert("Please respond to the '" + label + "' question before continuing.");
                    return false;
                }
                break;

            default:
                if (document.forms[0].elements[fields[i]][0].type == 'radio') {
                    radioSet = fields[i];
                    var radioChecked = 0;
                    for (var radioIndex = 0; radioIndex <= document.forms[0].elements[fields[i]].length - 1; radioIndex++) {
                        if (document.forms[0].elements[fields[i]][radioIndex].checked == true) {
                            radioChecked = 1;
                        }
                    }
                    if (radioChecked == 0) {
                        alert("Please respond to the '" + label + "' question before continuing.");
                        return false;
                    }
                    break;
                }
                else {
                    alert("Error in displayResults()\n" +
                        'Could not determine field type of "' + key + '.' + "\n" +
                        'Possibly two fields called ' + key);
                }
            }
        }
    }
    return true;
}


function requiredFieldsConditional(fieldPairs) {

    this.requiredConditionalFields = fieldPairs;
    for (var i = 0; i < fieldPairs.length; i++) {

        var keyData = fieldPairs[i].split('=>');
        var key = keyData[0];
        var label = keyData[1];

        if (document.forms[0].elements[key]) {
            switch (document.forms[0].elements[key].type) {
            case 'hidden':
                if (document.forms[0].elements[key].value != '') {
                    this.requiredFieldsConditionalTest = 1;
                }
                break;

            case 'text':
                if (document.forms[0].elements[key].value != '') {
                    this.requiredFieldsConditionalTest = 1;
                }
                break;

            case 'checkbox':
                if (document.forms[0].elements[key].checked == true) {
                    this.requiredFieldsConditionalTest = 1;
                }
                break;

            case 'select-one':
                if ((document.forms[0].elements[key].selectedIndex < 0) ||
                    (document.forms[0].elements[key][document.forms[0].elements[key].selectedIndex].value == '')) {
                    this.requiredFieldsConditionalTest = 0;
                }
                break;

            case 'select-multiple':
                if ((document.forms[0].elements[key].selectedIndex) ||
                    (document.forms[0].elements[key][document.forms[0].elements[key].selectedIndex].value == '')) {
                    this.requiredFieldsConditionalTest = 0;
                }
                break;

            case 'textarea':
                if (document.forms[0].elements[key].value == '') {
                    this.requiredFieldsConditionalTest = 0;
                }
                break;

            default:
                if (document.forms[0].elements[fields[i]][0].type == 'radio') {
                    radioSet = fields[i];
                    var radioChecked = 0;
                    for (var radioIndex = 0; radioIndex <= document.forms[0].elements[fields[i]].length - 1; radioIndex++) {
                        if (document.forms[0].elements[fields[i]][radioIndex].checked == true) {
                            radioChecked = 1;
                        }
                    }
                    if (radioChecked == 0) {
                        this.requiredFieldsConditionalTest = 0;
                    }
                    break;
                }
                else {
                    alert("Error in displayResults()\n" +
                        'Could not determine field type of "' + key + '.' + "\n" +
                        'Possibly two fields called ' + key);
                }
            }
        }
    }
    return true;
}


function verifySave(fieldName, fieldText) {

    if ((document.forms[0].elements[fieldName].selectedIndex > -1 &&
        document.forms[0].elements[fieldName][document.forms[0].elements[fieldName].selectedIndex].value == '') ||
        (document.forms[0].elements[fieldName].selectedIndex < 0)) {
    // Saving a new record
        if (confirm('Are you sure you want to create a new ' + fieldText +
            '?  To save this record, press the "Ok" button; otherwise, ' +
            'press "Cancel."')) {
            return true;
        }
        else {
            return false;
        }
    }
    else {
    // Something is selected

        if (confirm('Are you sure you want to edit the selected ' + fieldText +
            '?  To change this record, press the "Ok" button; otherwise, ' +
            'press "Cancel."')) {
            return true;
        }
        else {
            return false;
        }
    }
}


function verifyDelete(fieldName, fieldText) {

    if (((document.forms[0].elements[fieldName].type == 'select-one' || document.forms[0].elements[fieldName].type == 'select-multiple') &&
          document.forms[0].elements[fieldName][document.forms[0].elements[fieldName].selectedIndex].value) ||
          (document.forms[0].elements[fieldName].type == 'text' && document.forms[0].elements[fieldName].value) ||
          (document.forms[0].elements[fieldName].type == 'hidden' && document.forms[0].elements[fieldName].value)) {
        // Delete the selected record

        if (confirm('Are you sure you want to delete the selected ' + fieldText +
                    '?  To permanently delete this record, press the "Ok" button; ' +
                    'otherwise, press "Cancel."')) {
            return true;
        }
        else {
            return false;
        }
    }
    else {
    // Nothing selected
        return false;
    }
}


function setFields(fields) {

    this.queryString += '&template=bypass';
    for (var i = 0; i <= fields.length - 1; i++) {

        if (document.forms[0].elements[fields[i]]) {

            switch (document.forms[0].elements[fields[i]].type) {
            case 'text':
                this.queryString += '&' + fields[i] + '=' + escape(document.forms[0].elements[fields[i]].value);
                break;

            case 'checkbox':
                if (document.forms[0].elements[fields[i]].checked) {
                    this.queryString += '&' + fields[i] + '=' + escape(document.forms[0].elements[fields[i]].value);
                }
                break;

            case 'select-one':
                if (document.forms[0].elements[fields[i]].selectedIndex >= 0) {
                    this.queryString += '&' + fields[i] + '=' + escape(document.forms[0].elements[fields[i]][document.forms[0].elements[fields[i]].selectedIndex].value);
                }
                break;

            case 'select-multiple':
                var value = '';
                optionSet = fields[i];
                for (var optionIndex = 0; optionIndex <= document.forms[0].elements[fields[i]].length - 1; optionIndex++) {
                    if (document.forms[0].elements[fields[i]][optionIndex].selected) {
                        value += document.forms[0].elements[fields[i]][optionIndex].value + '|';
                    }
                }
                value = escape(value.substr(0, (value.length - 1)));
                this.queryString += '&' + fields[i] + '=' + escape(value);
                break;

            case 'textarea':
                this.queryString += '&' + fields[i] + '=' + escape(document.forms[0].elements[fields[i]].value);
                break;

            case 'hidden':
                this.queryString += '&' + fields[i] + '=' + escape(document.forms[0].elements[fields[i]].value);
                break;

            default:
            // This is either a radio button or a mistake
                if (document.forms[0].elements[fields[i]][0].type == 'radio') {

                    var value = '';
                    radioSet = fields[i];
                    for (var radioIndex = 0; radioIndex <= document.forms[0].elements[fields[i]].length - 1; radioIndex++) {
                        if (document.forms[0].elements[fields[i]][radioIndex].checked) {
                            value += escape(document.forms[0].elements[fields[i]][radioIndex].value);
                        }
                    }
                    this.queryString += '&' + fields[i] + '=' + escape(value);

                }
                else {

                    alert("Error in setFields()\n" +
                        'Could not read field "' + fields[i] + '" of type "' + fieldType + '"' + "\n" +
                        'Possibly two fields called ' + fields[i]);
                    return false;
                }
            }
        }
        else {
            alert("Error in setFields()\n" + 'Object not found: ' + fields[i] + "\n" +
                'Possible typo in ' + fields[i]);
            return false;
        }
    }
}


function setSession(userID, sessionID, request) {
// Set a queryString object's uid, sid, and req values

    if (userID && sessionID && request) {
        this.queryString += '&uid=' + escape(userID);
        this.queryString += '&sid=' + escape(sessionID);
        this.queryString += '&req=' + escape(request);
    }
    else {
        alert("Error:  Could not set session for queryString object.\n" +
            'userID, sessionID, and request values are required');
    }
}


function setOption(field, optionSelected, optionNotSelected) {
// Set a queryString object's option value

    if (field && optionSelected) {
        if (optionSelected && optionNotSelected) {
            if (document.forms[0].elements[field].value) {
                this.queryString += '&option=' + escape(optionSelected);
                this.option = escape(optionSelected);
            }
            else {
                this.queryString += '&option=' + escape(optionNotSelected);
                this.option = escape(optionNotSelected);
            }
        }
        else {
            this.queryString += '&option=' + escape(optionSelected);
            this.option = escape(optionSelected);
        }
    }
    else {
        alert("Error:  Could not set option for queryString object.\n" +
            'key field and at least one option are required');
    }
}


function postRequest(url) {

    if (resultsToMethod == '') {

        resultsToMethod = this.resultsToMethod;
        var xmlHttpReq = false;

        if (window.XMLHttpRequest) {
        // native XMLHttpRequest object
            req = new XMLHttpRequest();
            if (req.overrideMimeType) {
            // Non-IE only
                req.overrideMimeType('text/xml');
            }
        }
        else if (window.ActiveXObject) {
        // IE/Windows ActiveX, pre-IE 7
            req = new ActiveXObject("Microsoft.XMLHTTP");
        }

        var urlString = url + this.option + '/';
        req.open('POST', urlString, true);
        req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.onreadystatechange = processReqChange;
        req.send(this.queryString);

    }
    else {
        resultsToMethodQueue.length++;
        resultsToMethodQueue[resultsToMethodQueue.length - 1] = this.resultsToMethod;
    }
}


function getRequest(url) {

    if (resultsToMethod == '') {

        resultsToMethod = this.resultsToMethod;

        /* There is an addition to the urlString below that is hardcoded as
          the MSIEACWA parameter and is set to the current time in
          milliseconds since midnight of January 1, 1970.  This parameter
          stands for "MS Internet Explorer AJAX-Caching Workaround."  As the
          name suggests; it's there to solve a problem that all AJAX-enabled
          webapps experience with Internet Explorer.  By default (unless the
          end-user has modified IE's "Browsing history" settings) IE treats
          subsequent calls to AJAX GET requests with the same URL as something
          that can be cached.  This means that if the end-user GETS a record,
          POSTS a revision, and then GETS the same record a second time, IE
          will show them the results of the very first GET request making it
          seem like the POST was ignored--even though it wasn't.  By tacking on
          this final name/value pair, IE believes it's getting a totally unique
          request and doesn't look for cached data.
        */
        var date = new Date();
        var urlString = url + this.option + '/?' + this.queryString + '&MSIEACWA=' + date.getTime();
        var xmlHttpReq = false;
        if (window.XMLHttpRequest) {
        // branch for native XMLHttpRequest object

            req = new XMLHttpRequest();
            req.onreadystatechange = processReqChange;
            req.open("GET", urlString, true);
            req.send(null);

        }
        else if (window.ActiveXObject) {
        // branch for IE/Windows ActiveX version, pre-IE 7

            req = new ActiveXObject("Microsoft.XMLHTTP");
            if (req) {
                req.onreadystatechange = processReqChange;
                req.open("GET", urlString, true);
                req.send();
            }
        }
    }
    else {
        resultsToMethodQueue.length++;
        resultsToMethodQueue[resultsToMethodQueue.length - 1] = this.resultsToMethod;
    }
}

