/* -----------------------------------------------------------------------------
 Version:           2.0
 Summary:			Library to provide basic user interface functions including:
                    * OnLoad Functions (if any in use)
                    * Parsing of Ajax messages sent between UI and Django
                    * Opening of secondary windows
                    * Generalized clearing of input fields
                    * The tab system
                    * The typeahead boxes (called Lookahead boxes here)
 Last Update:		08-24-09
----------------------------------------------------------------------------- */

/* -----------------------------------------------------------------------------
  ONLOAD FUNCTIONS
----------------------------------------------------------------------------- */

function pageInit(initWrapper, initUserId, initSessionId, initCurrentRequest) {

    // Create tabs
    displayMenuHeaders();   // Write options in menu bar at top of screen
    // createTabs();        // Convert markup in tabs div to actual tabs (this is hardcoded in OASIS)

}

/* -----------------------------------------------------------------------------
  MESSAGE SYSTEM
  The following functions support the sysMsg('Message Text') function which
  displays a short system message for 1.5 centered in the user's browser.
  It should be used to let the user know when events happen that might not
  have made an immediate visible difference.  Saving your work, for example.
----------------------------------------------------------------------------- */

// Global vars
var systemMessages = new Array();
var messageTimeout;

function sysMsg(msg) {
/* This what actually gets called by the interface programmer to display the
  message.  the systemMessages arrary holds a queue of all the messages
  waiting to be displayed.  If there are currently no messages in the queue,
  then the new messages is pushed in at index 0 and displayed; otherwise,
  the new message is added to the end of the queue and it will displayed
  when it's turn comes up.
*/

    if (msg) {

        systemMessages.length++;
        var index = systemMessages.length - 1;
        systemMessages[index] = msg;

        if (systemMessages.length == 1) {
            displayMsg();
        }
    }
}


function displayMsg() {
/* This is where the message is actually displayed.  This function grabs
  whatever message is next in the queue (systemMessages[0]) and then it
  displays the message and sets nextMsg() to run in 1.5 seconds.
*/

    // Get the browser dimensions (IE and Netscape-based browsers do this differently)
    var x = 0;
    var y = 0;
    
    var browser = navigator.appName;
    if (browser == 'Netscape') {
        x = (window.innerWidth / 2) - 100;
        y = (window.innerHeight / 2) - 50;
        if (document.body.scrollTop) {
            y += document.body.scrollTop;
        }
    }
    else {
        x = ( document.documentElement.clientWidth ? document.documentElement.clientWidth/2 : document.body.clientWidth/2 ) -100;
        y = ( document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) -50;
        if (document.documentElement && document.documentElement.scrollTop) {
            // IE 6+
            y += document.documentElement.scrollTop;
        }
        else if (document.body.scrollTop) {
            // IE 5-
            y += document.body.scrollTop;
        }
    }

    // Display the message
    var object = document.getElementById('messages');
    object.style.left = x;
    object.style.top = y;
    document.getElementById('msgContent').innerHTML = '<p class="popup" align="center">' + systemMessages[0] + '</p>';
    var ieHack = document.getElementById('messages_ie_hack');
    ieHack.style.left = x+5;
    ieHack.style.top = y+3;
    ieHack.style.visibility = 'visible';
    object.style.visibility = 'visible';

    // Set up nextMsg() to run in 1.5 seconds
    messageTimeout = setTimeout("nextMsg()", 1500);

}


function nextMsg() {
/* This function kills the currently displayed message and updates the
  queue.  If any messages are left in the queue after the update, then
  displayMsg() is called again to display the next message.
*/

    clearTimeout(messageTimeout);
    var object = document.getElementById('messages');
    object.style.visibility = 'hidden';
    var ieHack = document.getElementById('messages_ie_hack');
    ieHack.style.visibility = 'hidden';

    for (var i = 0; i <= systemMessages.length - 1; i++) {
        systemMessages[i] = systemMessages[i + 1];
    }
    systemMessages.length--;

    if (systemMessages.length > 0) {
        displayMsg();
    }
}


/* -----------------------------------------------------------------------------
  LAUNCH WINDOW
----------------------------------------------------------------------------- */
function launch(url) {
/* This function launches a second window with smaller dimensions on top of
  the parent window.  It can be used to allow the user to navigate to a
  different part of the site while keeping the first window open.
*/

    if (url) {

        // Determine the window dimensions
        var screenWidth = null;
        var screenHeight = null;
        if (window.innerWidth) {
            screenWidth = window.innerWidth;
            screenHeight = window.innerHeight;
        }
        if (document.body.clientWidth) {
            screenWidth = document.body.clientWidth;
            screenHeight = document.body.clientHeight;
        }
        window.open(url,'secondRate','width=850,height=' + screenHeight + ',directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes,left=' + (screenWidth - 860) + ',top=3,screenX=' + (screenWidth - 860) + ',screenY=3');

    }
}


/* -----------------------------------------------------------------------------
  CLEARING OPTIONS
----------------------------------------------------------------------------- */
function clearFields(fields) {
/* Accepts an array of field names and clears the value of each field.
   In the case of radio buttons and checkboxes, it unchecks them.
   In the case of select boxes, it unselects everything.
   In all other cases, it sets the value to ''
*/

    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':
                document.forms[0].elements[fields[i]].value = '';
                break;

            case 'checkbox':
                document.forms[0].elements[fields[i]].checked = false;
                break;

            case 'select-one':
                document.forms[0].elements[fields[i]].selectedIndex = -1;
                break;

            case 'select-multiple':
                document.forms[0].elements[fields[i]].selectedIndex = -1;
                break;

            case 'textarea':
                document.forms[0].elements[fields[i]].value = '';
                break;

            case 'hidden':
                document.forms[0].elements[fields[i]].value = '';
                break;

            default:
                if (document.forms[0].elements[fields[i]][0].type == 'radio') {
                    radioSet = fields[i];
                    for (var radioIndex = 0; radioIndex <= document.forms[0].elements[fields[i]].length - 1; radioIndex++) {
                        document.forms[0].elements[fields[i]][radioIndex].checked = false;
                    }
                }
                else {
                    alert("Error in clearFields()\n" +
                        'Could not clear field "' + fields[i] + '" of type "' + fieldType + '"' + "\n" +
                        'Possibly two fields called ' + fields[i]);
                }
            }
        }
        else {
            // Possible id (div, span, etc.)
            if (document.getElementById(fields[i])) {
                document.getElementById(fields[i]).innerHTML = '';
            }
            else {
                alert("Error in clearFields()\n" + 'Object not found: ' + fields[i] + "\n" +
                    'Possible typo in ' + fields[i]);
            }
        }
    }
}


function clearSelect(fields) {
/* Accepts an array of field names of select boxes.  Checks that each field_name
  corresponds to a select box and then wipes out all options for that box.
*/

    for (var i = 0; i <= fields.length - 1; i++) {
        if (document.forms[0].elements[fields[i]]) {
            var fieldType = document.forms[0].elements[fields[i]].type;
            if (fieldType == 'select-one' || fieldType == 'select-multiple') {
                document.forms[0].elements[fields[i]].length = 0;
            }
        }
    }
}


/* -----------------------------------------------------------------------------
  PARSING AJAX RESPONSES
----------------------------------------------------------------------------- */
function selectedClear(keyFieldName, methodOptionOne, methodOptionTwo) {
/* Accepts a keyFieldName and if there's a value associated with that field
  call methodOptionOne, otherwise call methodOptionTwo.
*/

    if (keyFieldName, methodOptionOne, methodOptionTwo) {
        if (document.forms[0].elements[keyFieldName]) {
            if (((document.forms[0].elements[keyFieldName].selectedIndex > -1) &&
                (document.forms[0].elements[keyFieldName][document.forms[0].elements[keyFieldName].selectedIndex].value)) ||
                document.forms[0].elements[keyFieldName].value) {

                eval(methodOptionTwo);
                eval(methodOptionOne);

            }
            else {
                eval(methodOptionTwo);
            }
        }
        else {
            alert("Error in selectedClear()\n" +
                    'keyField not found.' + "\n" +
                    'Possible typo in name "' + keyFieldName + '".');
        }
    }
    else {
        alert("Error in selectedClear()\n" +
                'Too few arguments passed to function.' + "\n" +
                'Double-check for keyfield name and two options.');
    }
}


function displayResults(resultsData) {
/* Reads a string sent from an AJAX request and tries to parse it into name/value
  pairs inserting the values throughout the form.
*/

    resultsData = unescape(resultsData);
    var results = resultsData.split('|');

    // Check to see if this is just an AJAX unit test, if so, just display the
    // response and return.
    if (results[0].substring(0, 8) == 'UNITTEST') {
        alert(results[0]);
        return true;
    }

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

        var resultsPair = results[i].split('=>');
        var key = resultsPair[0];
        var value = resultsPair[1];

        if (document.forms[0].elements[key]) {
            switch (document.forms[0].elements[key].type) {
            case 'text':
                clearFields([key]);
                document.forms[0].elements[key].value = value;
                break;

            case 'checkbox':
                clearFields([key]);
                document.forms[0].elements[key].checked = eval(value);
                break;

            case 'select-one':
                /* Here, you can either select an existing option or populate an
                  empty select box.  If the current length of the box is 0,
                  assume we're populating a box; otherwise, assume we're just
                  selecting an already existing option.
                */
                document.forms[0].elements[key].selectedIndex = -1;
                if (document.forms[0].elements[key].length <= 0) {
                // Populate an empty box

                    if (value) {
                        var valueData = value.split('[:]');
                        document.forms[0].elements[key].length = 0;
                        for (var dataIndex = 0; dataIndex < valueData.length; dataIndex++) {
                            var dataPair = valueData[dataIndex].split('::');
                            var optionValue = dataPair[0];
                            var optionText = dataPair[1];

                            document.forms[0].elements[key].length++;
                            document.forms[0].elements[key][dataIndex].value = optionValue;
                            document.forms[0].elements[key][dataIndex].text = optionText;
                        }
                    }
                }
                else {
                // Just selecting an option

                    for (var boxIndex = 0; boxIndex < document.forms[0].elements[key].length; boxIndex++) {
                        if (document.forms[0].elements[key][boxIndex].value == value) {
                            document.forms[0].elements[key].selectedIndex = boxIndex;
                        }
                    }
                }
                break;

            case 'select-multiple':
                /* Here, you can either select an existing option or populate an
                  empty select box.  If the current length of the box is 0,
                  assume we're populating a box; otherwise, assume we're just
                  selecting an already existing option.
                */
                document.forms[0].elements[key].selectedIndex = -1;
                if (document.forms[0].elements[key].length <= 0) {
                // Populate an empty box

                    var valueData = value.split('[:]');
                    if (valueData) {
                        document.forms[0].elements[key].length = 0;
                        for (var dataIndex = 0; dataIndex < valueData.length; dataIndex++) {
                            var dataPair = valueData[dataIndex].split('::');
                            var optionValue = dataPair[0];
                            var optionText = dataPair[1];

                            document.forms[0].elements[key].length++;
                            document.forms[0].elements[key][dataIndex].value = optionValue;
                            document.forms[0].elements[key][dataIndex].text = optionText;
                        }
                    }
                }
                else {
                // Just selecting an option

                    var valueData = value.split('::');
                    for (var boxIndex = 0; boxIndex < document.forms[0].elements[key].length; boxIndex++) {
                        for (var dataIndex = 0; dataIndex < valueData.length; dataIndex++) {
                            if (document.forms[0].elements[key][boxIndex].value == valueData[dataIndex]) {
                                document.forms[0].elements[key][boxIndex].selected = true;
                            }
                        }
                    }
                }
                break;

            case 'textarea':
                clearFields([key]);
                document.forms[0].elements[key].value = value;
                break;

            case 'hidden':
                clearFields([key]);
                document.forms[0].elements[key].value = value;
                break;

            default:
                if (document.forms[0].elements[key][0].type == 'radio') {
                    radioSet = key;
                    clearFields([radioSet]);
                    for (var radioIndex = 0; radioIndex <= document.forms[0].elements[key].length - 1; radioIndex++) {
                        if (document.forms[0].elements[key][radioIndex].value == value) {
                            document.forms[0].elements[key][radioIndex].checked = true;
                        }
                    }
                }
                else {
                    alert("Error in displayResults()\n" +
                        'Could not determine field type of "' + key + '.' + "\n" +
                        'Possibly two fields called ' + key);
                }
            }
        }
        else {
            // Possible id (div, span, etc.)
            if (document.getElementById(key)) {
                document.getElementById(key).innerHTML = value;
            }
            else if (key == 'reply') {
            // Ignore these entries
                continue;
            }
            else {
                if (key != 'NO RESPONSE') {
                    alert("Error in displayResults()\n" +
                        'Could not find field "' + key + '.  "' + "\n" +
                        'Double-check variable name in Python method.');
                }
            }
        }
    }
}


function processResponse(response, reloadOnSave, preReloadMethod) {
/* Read a string sent from an AJAX request and do success or failure functions.*/

    response = unescape(response);

    // Check to see if this is just an AJAX unit test, if so, just display the
    // response and return.
    if (response.substring(0, 8) == 'UNITTEST') {
        alert(response);
        return true;
    }

    // This was not a test, so process the data.
    var responseData = response.split('|');
    var replyData = responseData[0].split('=>');
    var reply = replyData[1];

    if (reply == 'added' || reply == 'edited' || reply == 'deleted') {

        if (responseData[1]) {
        // This response says to update some field in the form, so never reload.
            if (reloadOnSave == 0) sysMsg('.:  Your update has been saved  :.');
                if (preReloadMethod) {
                    eval(preReloadMethod);
                }
            return responseData[1];
        }
        else {
        // Reload or send message
            if (reloadOnSave == 1) {
                if (preReloadMethod) {
                    eval(preReloadMethod);
                }
                location.reload();
            }
            else {
                sysMsg('Update Saved');
            }
        }
    }
    else {
        alert("Sorry!  There was a problem with that update.  Please try again.");
        return false;
    }
}


function displayOption(keyFieldInput, keyfieldText) {
/* Create a new option or update an existing option in a select box */

    // Parse the input
    var keyfieldData = keyFieldInput.split('=>');
    var keyfieldName = keyfieldData[0];
    var keyfieldValue = keyfieldData[1];

    // Do the inserting
    var updatedOption = 0;
    if (keyfieldData && keyfieldName && keyfieldValue && document.forms[0].elements[keyfieldName]) {

        for (var i = 0; i <= document.forms[0].elements[keyfieldName].length - 1; i++) {
            if (document.forms[0].elements[keyfieldName][i].value == keyfieldValue) {
            // Update an existing option
                document.forms[0].elements[keyfieldName][i].value = keyfieldValue;
                document.forms[0].elements[keyfieldName][i].text = keyfieldText;
                updatedOption = 1;
            }
        }

        if (updatedOption == 0) {
        // Add a new option
            document.forms[0].elements[keyfieldName].length++;
            document.forms[0].elements[keyfieldName][document.forms[0].elements[keyfieldName].length - 1].value = keyfieldValue;
            document.forms[0].elements[keyfieldName][document.forms[0].elements[keyfieldName].length - 1].text = keyfieldText;
            document.forms[0].elements[keyfieldName].selectedIndex = document.forms[0].elements[keyfieldName].length - 1;
        }
    }
    else {
        alert('Sorry!  There was a problem displaying the new information, ' +
            'but your data was saved.  Please reload this page to see the ' +
            'new data. If this problem persists, please contact the system ' +
            'administrator.');
    }
}


function deleteOption(keyFieldInput) {
/* Remove an option from a select box */

    // Parse the input
    var keyfieldData = keyFieldInput.split('=>');
    var keyfieldName = keyfieldData[0];
    var keyfieldValue = keyfieldData[1];

    // Do the deleting
    var deletedIndex = -1;
    if (keyfieldData && keyfieldName && keyfieldValue && document.forms[0].elements[keyfieldName]) {

        for (var i = 0; i < document.forms[0].elements[keyfieldName].length - 1; i++) {
            if (document.forms[0].elements[keyfieldName][i].value == keyfieldValue) {
                deletedIndex = i;
            }
            if (deletedIndex > -1) {
                document.forms[0].elements[keyfieldName][i].value = document.forms[0].elements[keyfieldName][i+1].value;
                document.forms[0].elements[keyfieldName][i].text = document.forms[0].elements[keyfieldName][i+1].text;
            }
        }
        document.forms[0].elements[keyfieldName].length--;

    }
    else {
        alert('Sorry!  There was a problem displaying the updated screen, ' +
            'but your data was deleted.  Please reload this page to see the ' +
            'updates. If this problem persists, please contact the system ' +
            'administrator.');
    }
}


/* -----------------------------------------------------------------------------
  TAB MENUBAR
----------------------------------------------------------------------------- */
tabOptions = new Array;

function createTabs() {

    if (document.getElementById('tabs')) {

        var tabData = document.getElementById('tabs').innerHTML;
        var tabArray = tabData.split('|');
        var tabBar = '<table cellpadding="0" cellspacing="0" width="100%">' + "\n" +
            '<tr>' + "\n";
        for (var i = 0; i < tabArray.length; i++) {

            var keyValueData = tabArray[i].split('=');
            var tabID = keyValueData[0];
            var tabLabel = keyValueData[1];
            tabOptions[i] = tabID;

            if (i == 0) {
                tabBar += '<td id="' + tabID +'_tab" class="form_tab" style="border-bottom-width: 0px; border-right-width: 1px;" align="center"><a class="form_tab" href="javascript:;" onClick="displayTab(\'' + tabID + '\')" onFocus="if (this.blur) this.blur();">' + tabLabel + '</a></td>' + "\n";
            }
            else {
                tabBar += '<td id="' + tabID +'_tab" class="form_tab" align="center"><a class="form_tab" href="javascript:;" onClick="displayTab(\'' + tabID + '\')" onFocus="if (this.blur) this.blur();">' + tabLabel + '</a></td>' + "\n";
            }
        }
        tabBar += '<td class="form_tab" style="border-top-width:  0px;">&nbsp;</td>' + "\n" +
            '</tr>' + "\n" + '</table>' + "\n";

        document.getElementById('tabs').innerHTML = tabBar;
        var tabObj = document.getElementById('tabs');
        tabObj.style.display = 'block';
    }
}


function displayTab(tabName, baseURL, requiredValue, requiredAction) {
// Display the <div> assigned to the tab in the display.

    /* Check required value first. (A required value is a field on the screen
        that must be filled out for the user to continue onto the tab they
        selected.)
    */
    if (requiredValue) {
        if (! document.forms[0].elements[requiredValue].value) {
            alert('Please ' + requiredAction + ' before entering this tab.');
            return false;
        }
    }

    var divElements = document.getElementsByTagName("div");
    for (i = 0; i < divElements.length; i++) {
        if (divElements[i].id.length > 0) {
            if (divElements[i].id.substring(divElements[i].id.length - 4, divElements[i].id.length) == '_tab') {
                if (tabName + '_tab' == divElements[i].id) {
                    // Display a tab's content
                    var content = document.getElementById(tabName);
                    content.style.display = 'block';
                    var tab = document.getElementById(tabName + '_tab');
                    var tabContent = document.getElementById(tabName + '_tab_content');
                    tab.innerHTML = 
                        '<div class="left_selected_tab_corner" style="background-image: url(\'' + baseURL + 'left_selected_tab_corner.gif\');"></div>' + 
                        '<div id="' + tabName + '_tab_content" class="selected_tab_content">' + tabContent.innerHTML + '</div>' + 
                        '<div class="right_selected_tab_corner" style="background-image: url(\'' + baseURL + 'right_selected_tab_corner.gif\');"></div>';
                }
                else {
                    // Hide a tab's content
                    var content = document.getElementById(divElements[i].id.substring(0, divElements[i].id.length - 4));
                    content.style.display = 'none';
                    var tab = document.getElementById(divElements[i].id);
                    var tabContent = document.getElementById(divElements[i].id.substring(0, divElements[i].id.length - 4) + '_tab_content');
                    tab.innerHTML = 
                        '<div class="left_unselected_tab_corner" style="background-image: url(\'' + baseURL + 'left_unselected_tab_corner.gif\');"></div>' + 
                        '<div id="' + divElements[i].id.substring(0, divElements[i].id.length - 4) + '_tab_content" class="unselected_tab_content">' + tabContent.innerHTML + '</div>' + 
                        '<div class="right_unselected_tab_corner" style="background-image: url(\'' + baseURL + 'right_unselected_tab_corner.gif\');"></div>';
                }
            }
        }
    }
}

/* -----------------------------------------------------------------------------
  LOOKAHEAD BOXES
----------------------------------------------------------------------------- */

lookAheadBoxes = new Array;
lookAheadData = new Array;
var lookAheadDisplayedList = '';

/* The next three classes are basically a workaround for IE's inability to
 efficiently concatenate strings.  They are used in displayAllLookAheadOptions()
 and lookUp()*/
function StringBuffer() {
    this.buffer = [];
}

StringBuffer.prototype.append = function append(string) {
    this.buffer.push(string);
    return this;
}

StringBuffer.prototype.toString = function toString() {
    return this.buffer.join("");
}
/* end IE workaround */


function hideLookAhead() {
/* Close the open lookahead box */

    if (lookAheadDisplayedList) {
        document.getElementById(lookAheadDisplayedList + '_data').style.display = 'none';
        document.getElementById(lookAheadDisplayedList + '_iehack').style.display = 'none';
    }
}


function displayAllLookAheadOptions(event, typedValue, lookAheadId, action) {
/* Display all the options associated with the selected lookAhead */

    var lookAheadInput = document.getElementById(lookAheadId + '_input');
    var optionsDisplay = document.getElementById(lookAheadId + '_data');
    var optionsValue = document.getElementById(lookAheadId + '_value').value;
    var ieHack = document.getElementById(lookAheadId + '_iehack');

    // If anything related to this lookahed is already displayed, hide it; otherwise, display the options
    if (optionsDisplay.style.display != 'block') {

        // Display all options.

        // Close any other open display lists and set lookAheadDisplayList to this one
        hideLookAhead();
        lookAheadDisplayedList = lookAheadId;

        // Populate and display the data fields
        lookAheadDataValues = lookAheadData[lookAheadId].split('|');
        var buffer = new StringBuffer();
        var selectedOptionIndex = 0;

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

            keyValue = lookAheadDataValues[i].split('=>');
            var style = ((i == 0 && ! lookAheadInput.value) || (keyValue[0] == optionsValue)) ? 'style="background-color: #cccccc;" ' : '';
            buffer.append(
                '<span class="lookahead_option" ' + style +
                'onMouseOver="selectLookAheadOption(this, \'' + escape(keyValue[0]) + '\', \'' + lookAheadId + '\')" ' +
                'onMouseOut="deselectLookAheadOption(this)" ' +
                'onClick="selectedOption(\'' + lookAheadId + '\', \'' +  escape(keyValue[1]) + '\', \'' + escape(keyValue[0]) + '\', \'' + action + '\')">' +
                keyValue[1] + '</span><br />\n');

            if (keyValue[0] == optionsValue) {
                selectedOptionIndex = i;
            }
        }

        optionsDisplay.innerHTML = buffer.toString();
        optionsDisplay.style.display = 'block';
        optionsDisplay.scrollTop = 0;
        optionsDisplay.scrollTop = selectedOptionIndex * 16;

        // IE workaround for a bug in displaying divs over select boxes
        if (window.ActiveXObject) {
            ieHack.style.width = optionsDisplay.offsetWidth;
            ieHack.style.height = optionsDisplay.offsetHeight;
            ieHack.style.top = optionsDisplay.style.top;
            ieHack.style.left = optionsDisplay.style.left;
            ieHack.style.zIndex = 9999;
            ieHack.style.display = 'block';
        }
    }
    else {

        optionsDisplay.style.display = 'none';
        ieHack.style.display = 'none';
        lookAheadDisplayedList = '';
    }
}


function selectLookAheadOption(optionId, optionValue, lookAheadId) {
/* Highlight an option in a lookahead box */

    optionId.style.background = '#cccccc';
    document.getElementById(lookAheadId + '_value').value = optionValue;

}


function deselectLookAheadOption(optionId) {
/* Unhighlight an option in a lookahead box */

    optionId.style.background = '#eeeeee';

}


function selectedOption(lookAheadId, displayText, optionValue, action) {
/* What to do if an option is clicked on in a lookahead box */

    document.getElementById(lookAheadId + '_input').value = unescape(displayText);
    document.getElementById(lookAheadId + '_value').value = unescape(optionValue);
    document.getElementById(lookAheadId + '_data').style.display = 'none';
    document.getElementById(lookAheadId + '_iehack').style.display = 'none';
    eval(action + '(\'\')');

}


function lookUp(e, typedValue, lookAheadId, action) {
/* Typeahead suggest for a lookahead box */

    var optionsDisplay = document.getElementById(lookAheadId + '_data');
    var ieHack = document.getElementById(lookAheadId + '_iehack');

    // Parse the passed input and create a letters/index hash for this searchIn value
    var firstLetter = typedValue.substring(0,1).toLowerCase();
    searchInData = lookAheadBoxes[lookAheadId].split('|');
    letters = new Array;
    for (var i = 0; i < searchInData.length; i++) {
        letterData = searchInData[i].split('=>');
        letters[letterData[0]] = letterData[1];
    }

    // Set the index to start the search at
    var index = 0;
    index = letters[firstLetter];

    // Do the search
    var displayStart = 0;
    displayRecords = new Array;
    lookAheadDataValues = lookAheadData[lookAheadId].split('|');
    for (var i = index; i < lookAheadDataValues.length; i++) {

        keyValue = lookAheadDataValues[i].split('=>');
        var autoComplete = escape(keyValue[1]);
        var regex = eval("/^" + escape(typedValue) + "/i");
        if (autoComplete.match(regex)) {
            if (displayStart == 0) {
                displayStart = i;
            }
            displayRecords.length++;
            displayRecords[displayRecords.length - 1] = i;
        }
        else {
            if (displayStart != 0) {
                break;
            }
        }
    }

    // If there were matches, display them, if not, don't
    if (displayRecords.length > 0) {

        var buffer = new StringBuffer();
        for (var i = 0; i < displayRecords.length; i++) {

            var id = displayRecords[i];
            keyValue = lookAheadDataValues[id].split('=>');
            var style = (i == 0) ? 'style="background-color: #cccccc;" ' : '';
            buffer.append(
                '<span class="lookahead_option" ' + style +
                'onMouseOver="selectLookAheadOption(this, \'' + escape(keyValue[0]) + '\', \'' + lookAheadId + '\')" ' +
                'onMouseOut="deselectLookAheadOption(this)" ' +
                'onClick="selectedOption(\'' + lookAheadId + '\', \'' +  escape(keyValue[1]) + '\', \'' + escape(keyValue[0]) + '\', \'' + action + '\')">' +
                keyValue[1] + '</span><br />\n');
        }
        optionsDisplay.innerHTML = buffer.toString();
        optionsDisplay.scrollTop = 0;
        optionsDisplay.style.display = 'block';

        // IE workaround for a bug in displaying divs over select boxes
        if (window.ActiveXObject) {
            ieHack.style.width = optionsDisplay.offsetWidth;
            ieHack.style.height = optionsDisplay.offsetHeight;
            ieHack.style.top = optionsDisplay.style.top;
            ieHack.style.left = optionsDisplay.style.left;
            ieHack.style.zIndex = 9999;
            ieHack.style.display = 'block';
        }

        // If the enter key was pressed, set the lookahead_value to the value of
        // the selected option and set the lookahead_input to the value of
        // the selection option text.
        var intKey = -1;
        if (window.event) {
            intKey = event.keyCode;
        }
        else {
            intKey = e.which;
        }

        if (intKey == 13) {
        // Set the value to the currently selected item
            keyValue = lookAheadDataValues[displayRecords[0]].split('=>');
            selectedOption(lookAheadId, escape(keyValue[1]), keyValue[0], action);
        }
    }
    else {
    // No matches, so display nothing

        optionsDisplay.style.display = 'none';
        ieHack.style.display = 'none';
        lookAheadDisplayedList = '';
        
        // If the enter key was pressed, set the lookahead_value to the value of
        // the selected option and set the lookahead_input to the value of
        // the selection option text.
        var intKey = -1;
        if (window.event) {
            intKey = event.keyCode;
        }
        else {
            intKey = e.which;
        }
        
        if (intKey == 13) {
        // Set the value to the currently selected item
            selectedOption(lookAheadId, '', '', action);
        }
    }
}


function displayLookAheadOption(keyFieldInput, optionText) {
/* Create a new option or update an existing option in a lookahead combo box */

    // Parse the input
    var keyfieldData = keyFieldInput.split('=>');
    var lookAheadId = keyfieldData[0];
    var optionValue = keyfieldData[1];
    var lookAheadInputField = document.getElementById(lookAheadId + '_input');
    var lookAheadValue = document.getElementById(lookAheadId + '_value');

    // Display/add the data
    if (keyfieldData && lookAheadId && optionValue && lookAheadInputField) {

        // Set the input field text and lookahead value to the new data
        lookAheadInputField.value = optionText;
        lookAheadValue.value = optionValue;

        // Loop through lookAheadData[lookAheadId] and update the record for
        // the selected option if this is an edit
        lookAheadDataValues = lookAheadData[lookAheadId].split('|');
        var buffer = new StringBuffer();
        var updatedOption = 0;
        buffer.append('=>- START NEW RECORD -');
        for (var i = 1; i < lookAheadDataValues.length; i++) {

            keyValue = lookAheadDataValues[i].split('=>');
            var recordValue = keyValue[0];
            var recordKey = keyValue[1];
            if (recordValue == optionValue) {
            // Update an existing record
                recordKey = optionText;
                updatedOption = 1;
            }
            buffer.append('|' + recordValue + '=>' + recordKey);
        }

        // Otherwise, add a new record
        if (updatedOption == 0) {
            buffer.append('|' + optionValue + '=>' + optionText);
        }

        // Finally, update lookAheadData
        lookAheadData[lookAheadId] = buffer.toString();
    }
    else {
        alert('Sorry!  There was a problem displaying the new information, ' +
            'but your data was saved.  Please reload this page to see the ' +
            'new data. If this problem persists, please contact the system ' +
            'administrator.');
    }
}


function deleteLookAheadOption(keyFieldInput) {
/* Remove an option from a lookAhead combo box */

    // Parse the input
    var keyfieldData = keyFieldInput.split('=>');
    var lookAheadId = keyfieldData[0];
    var optionValue = keyfieldData[1];
    var lookAheadInputField = document.getElementById(lookAheadId + '_input');
    var lookAheadValue = document.getElementById(lookAheadId + '_value');

    // Do the deleting
    if (keyfieldData && lookAheadId && optionValue && lookAheadInputField) {

        lookAheadDataValues = lookAheadData[lookAheadId].split('|');
        var buffer = new StringBuffer();
        buffer.append('=>- START NEW RECORD -');
        for (var i = 1; i < lookAheadDataValues.length; i++) {

            keyValue = lookAheadDataValues[i].split('=>');
            var recordValue = keyValue[0];
            var recordKey = keyValue[1];
            if (recordValue != optionValue) {
            // Keep this option
                buffer.append('|' + recordValue + '=>' + recordKey);
            }
        }

        // Finally, update lookAheadData
        lookAheadData[lookAheadId] = buffer.toString();
    }
    else {
        alert('Sorry!  There was a problem displaying the updated screen, ' +
            'but your data was deleted.  Please reload this page to see the ' +
            'updates. If this problem persists, please contact the system ' +
            'administrator.');
    }
}


function shortCircuitLookAhead(input) {
/* Sometimes you want a lookahead box to be nothing more than a fancy
   substitute for a standard HTML select box.  In that case, you need to
   short circuit it's function call when someone selects an option.  That is,
   selecting an option shouldn't trigger an ajax call to look something up,
   it should simply set the display text and selected value to the selected
   option and return.  If that's what you're trying to do, set the javascript
   function for your lookahed to shortCircuitLookAhead. */

    return false;
}


function updateLookAhead(lookAheadID, response, optionText, openerLookAheadMethod) {
/* Function to parse the results of data sent from one page to another.
   This is used in the case of populating lookAhead boxes with data
   that was just entered into another form at a different address. */
 
    // Parse the response
    response = unescape(response);
    var responseData = response.split('|');
    var replyData = responseData[0].split('=>');
    var reply = replyData[1];
    var fieldData = responseData[1].split('=>');

    // Only continue processing if reply = 'added'
    if (reply == 'added') {

        lookAheadData[lookAheadID] += '|' + reply + '=>' + optionText;
        var lookAheadIDDataField = lookAheadID + '_value';
        var lookAheadIDInputField = lookAheadID + '_input';
        document.forms[0].elements[lookAheadIDDataField].value = fieldData[1];
        document.forms[0].elements[lookAheadIDInputField].value = optionText;
        
        if (openerLookAheadMethod != 'undefined' && openerLookAheadMethod != '') {
        // If the end result of the LookAhead update was to trigger the method
        // tied to it, then trigger that now.
            eval(openerLookAheadMethod + "('')");
        }
    }
}

        

/* -----------------------------------------------------------------------------
  MISC FUNCTIONS
----------------------------------------------------------------------------- */

