/*
*******************************************************************************

    FiForms -- A collection of PHP classes designed 
    to facilitate rapid development of web-database software

    Copyright (C) 2003 - 2007  Daniel McFeeters

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


    The original author of this library can be contacted at the following 
    address:

    Daniel McFeeters
    312 Bill Neal Rd.
    Whitley City, KY 42653-4209
    email:databases [at] fiforms [dot] org
    http://www.fiforms.org/


iInput class
Project Started May 4, 2003
*******************************************************************************
backgroundloader.js

Javascript functions for loading data into FiForms forms asynchronously.

loadXMLDataset_* Functions originally based on code from the following site:
http://developer.apple.com/internet/webcontent/xmlhttpreq.html


*******************************************************************************
*/


var xmlDatasetReq;
var selectElementDepends = new Array();  // array for element dependencies so 
                           // refreshes happen in a logical order

var selectElementRowSrc = new Array();   // arrey of expressions for determining
                           // URI to retreive SELECT option items
var bkgHere = true;

var initiation = true;

var ajaxWaiting = false;

var updateQueue = new Array();

var currentlyLoadingXML = false;


/* *************** UNTANGLE THE SPAGHETTI ***************

Here's an overview of functions in this file, and how they relate

Custom Datatypes
  function SrcQueue(elementID,url);
  function Depend(prntElementID,dependantElementID);
  function SrcExpr(elementID,rowSrcExp,external,autoOverwrite,updateAll);

The following functions are called to setup sources and depenencies

  function bkload_pageSetup();
    -> Sets all onchange events to bkgSelectChange
    -> Calls function loadTopSelects();

Event-triggered functions:
  function bkgSelectChange(e);
    -> Calls function reloadSelectDepends(elementID,initialLoad);
       |
       \-> Calls function reloadSelectRows(elementID,initialLoad);
           |
           \-> Calls function loadXMLDataset(url,elementID); 
               |
               \-> Calls function checkQueue(cont)
               |
               \-> Triggers function loadXMLDataset_process();
                   |
                   \-> Calls function queueItem(elementID,url);
                   |
                   \-> Calls function
                             loadXMLDataset_fillSelect(xml_data,response_params);
                   |
                   \-> Calls function checkQueue(cont);

function grabItem(elementID);
function grabFirstItem();
function setSelectDepends(dependantElementID,prntElementID);
function setSelectElementRowSrc(elementID,rowSrcExp,autoOverwrite,updateAll);
function setSelectElementRowFunction(elementID,rowSrcExp,autoOverwrite);




function getParam(xml_doc,param_name);



   ****************************************************** */


/* ********************
    Custom Datatypes
   ******************** */

function SrcQueue(elementID,url,method,params)
{
    this.elementID = elementID;
    this.url = url;
    this.method = method;
    this.params = params;
    this.done = false;
} // function SrcQueue

function Depend(prntElementID,dependantElementID)
{
    this.prnt = prntElementID;
    this.dependant = dependantElementID;
} // function Depend

function SrcExpr(elementID,rowSrcExp,external,autoOverwrite,updateAll)
{
    this.element = elementID;
    this.expression = rowSrcExp;
    this.external = external;
    this.autoOverwrite = autoOverwrite;
    this.updateAll = updateAll;
} // function SrcExpr

function queueItem(elementID,url,method,params)
{
    for(i = 0; i < updateQueue.length; i++)
    {
        if(updateQueue[i] && updateQueue[i].elementID == elementID)
        {
            updateQueue[i].url = url;
            updateQueue[i].method = method;
            updateQueue[i].params = params;
            updateQueue[i].done = false;
            return;
        } // if match
    } // for i
    i++;
    updateQueue[i] = new SrcQueue(elementID,url,method,params);
}

function grabItem(elementID)
{
    for(i = 0; i < updateQueue.length; i++)
    {
        if(updateQueue[i].elementID == elementID)
        {
            updateQueue[i].done = true;
            return(updateQueue[i]);
        } // if match
    } // for i
    return false;
}

function grabFirstItem()
{
    for(i = 0; i < updateQueue.length; i++)
    {
        if(updateQueue[i] && !updateQueue[i].done)
        {
            updateQueue[i].done = true;
            return(updateQueue[i]);
        } // if match
    } // for i
    return false;
}


function setSelectDepends(dependantElementID,prntElementID)
{
    // Flags the dependantElement so that its contents will be refreshed whenever
    // the value of the prntElement changes
    selectElementDepends[selectElementDepends.length] = 
        new Depend(prntElementID,dependantElementID)

}

function setSelectElementRowSrc(elementID,rowSrcExp,autoOverwrite,updateAll)
{
    selectElementRowSrc[selectElementRowSrc.length] = 
        new SrcExpr(elementID,rowSrcExp,true,autoOverwrite,updateAll);
}

function setSelectElementRowFunction(elementID,rowSrcExp,autoOverwrite)
{
    selectElementRowSrc[selectElementRowSrc.length] = 
        new SrcExpr(elementID,rowSrcExp,false,autoOverwrite,false);
}

function reloadSelectRows(elementID,initialLoad)
{
    for(z = 0; z < selectElementRowSrc.length; z++)
    // loop over array selectElementRowSrc
    {
        if(selectElementRowSrc[z].element == elementID)
        // if the element matches the one we're looking for...
        {
            url = false;
            if(initialLoad == true && !selectElementRowSrc[z].autoOverwrite)
            // skip updating, if the page has just loaded and we don't
            // want to automatically overwrite data on page load
            {
                continue;
            }
            try {
            url = eval(selectElementRowSrc[z].expression);
            }
            catch(err)
            {
            }
            if(url && url.length > 1)
            {
                // get rid of html entities in url
                url = url.replace(/&amp;/g,"&");
            }
            if(selectElementRowSrc[z].external && url)
            // data needs to be loaded from the server
            {
                if(initialLoad == true)
                // flag this as an initial load
                {
                    url = url+'&ajax_load_state=initial';
                }
                if(selectElementRowSrc[z].updateAll)
                // flag to update all fields matching result
                {
                    url = url+'&ajax_update_mode=all';
                }
                if(dynSel = findDynSel(elementID))
                // add parameters for dynamic select box
                {
                    url = url+'&ajax_select_style=dynamic';
                    if(initialLoad == true || !dynSel.open)
                    {
                        url = url+'&ajax_dynamic_search=';
                        url = url+'&ajax_key_value='+escape(document.getElementById(elementID).value);
                    }
                    else
                    {
                        if((dynSel.last && dynSel.last == document.getElementById(elementID+"_display").value))
                        {
                            return;
                        }
                        dynSel.last = document.getElementById(elementID+"_display").value;
                        url = url+'&ajax_dynamic_search='+escape(document.getElementById(elementID+"_display").value);
                                url = url+'&ajax_key_value=';
                }
                }
            loadXMLDataset(url,elementID);
            }
            else
            {
                document.getElementById(elementID).value = url;
            }
        }
    }
}  // function reloadSelectRows

function reloadSelectDepends(elementID,initialLoad)
{
    for(elementCount = 0; elementCount < selectElementDepends.length; elementCount++)
    {
        if(selectElementDepends[elementCount].prnt == elementID)
        {
            reloadSelectRows(selectElementDepends[elementCount].dependant,initialLoad);
        }
    }
}

function bkgSelectChange(e)
{
     if(window.event)
     {
         if(window.event.target)
         {
           n = window.event.target.getAttribute('name');
         }
         else if(window.event.srcElement)
         {
           n = window.event.srcElement.getAttribute('name');
         }
     }
     else if(e.currentTarget)
     {
         n = e.currentTarget.name;
     }
     if (n)
         reloadSelectDepends(n,initiation);
}

function bkload_pageSetup()
{
    // Look for all input boxes and sets onchange event to bkgSelectChange
    dropdowns = document.getElementsByTagName('select');
    for (var i = 0; i < dropdowns.length; i++)
    {
        if(!dropdowns[i].onchange)
        {
           dropdowns[i].onchange = bkgSelectChange;
	}
        if(!dropdowns[i].onblur)
        {
           dropdowns[i].onblur = rememberLastInput;
        }
    }
    dropdowns = document.getElementsByTagName('input');
    for (var i = 0; i < dropdowns.length; i++)
    {
        if(!dropdowns[i].onchange)
        {
           dropdowns[i].onchange = bkgSelectChange;
        }
        if(!dropdowns[i].onblur)
        {
           dropdowns[i].onblur = rememberLastInput;
        }
    }
    loadTopSelects();
    initiation = false;
}

function loadTopSelects()
{
    topSelect = false;
    for(elementNo = 0; elementNo < selectElementRowSrc.length; elementNo++)
    {
        topSelect = true;
        for(elementCount = 0; elementCount < selectElementDepends.length; elementCount++)
        {
            if(selectElementDepends[elementCount].dependant == selectElementRowSrc[elementNo].element)
            // this is a match!
            {
                //check to see if there is an AJAX row source for the master element
                masterHasSource = false
                for(testNo = 0; selectElementRowSrc.length != undefined && testNo < selectElementRowSrc.length; testNo++)
                {
                    if(selectElementRowSrc[testNo].element == selectElementDepends[elementCount].prnt)
                    {
                        masterHasSource = true;
                    }
                }
                if(masterHasSource)
                {
                    topSelect = false;
                }
            }  // if match
        }  // loop over selectElementDepends
        if(topSelect)
        {
            reloadSelectRows(selectElementRowSrc[elementNo].element,true);
        }
    }  // for loop (over selectElementRowSrc
}  // function loadTopSelects

function timeoutListLoad()
{
    currentlyLoadingXML = false;
    window.status = '';
    checkQueue(false);
}

function loadXMLDataset(url,elementID,method,params)
{
    if(method == null)
    {
        method = "GET";
    }
    if(currentlyLoadingXML)
    {
        queueItem(elementID,url,method,params);
        window.setTimeout('checkQueue(false);',1000);
        return false;
    }
    currentlyLoadingXML = window.setTimeout('timeoutListLoad();',4000);
    window.status = "Loading Lists from Server. Please Wait...";
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) 
    {
        xmlDatasetReq = new XMLHttpRequest();
    }
    else if (window.ActiveXObject)  // branch for IE/Windows ActiveX version
    {
        xmlDatasetReq = new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (xmlDatasetReq)
    {
        xmlDatasetReq.onreadystatechange = loadXMLDataset_process;
        xmlDatasetReq.open(method, url, true);
        if(method == 'POST')
        {
            xmlDatasetReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            xmlDatasetReq.setRequestHeader("Content-length", params.length);
            xmlDatasetReq.setRequestHeader("Connection", "close");
        }
        xmlDatasetReq.send(params);
    }
    return true;
}

function loadXMLDataset_fillSelect(xml_data,response_params)
// Fill the select box with data from xml. Called upon completed of xmlhttprequest.
{
    var cell = new Array();
    var ctext = new Array();
    // find name of dataset in xml document to use
    datasetname = getParam(xml_data,'ajax_select_dataset');

    // get all datasets in document
    datasets = xml_data.getElementsByTagName('dataset');
    options = false; // initialize variable to set of rows to fill options

    // set options to the dataset used to fill the options
    if(datasetname)
    // datasetname is specified, so we need to hunt for the appropriate 
    // dataset in the output
    {
        i = 0;
        while(datasets[i])
        {
            if(datasets[i].getAttribute('name') == datasetname)
            {
                options = datasets[i].getElementsByTagName('row');
            }
        }
    }
    else
    // otherwise, take the first one
    {
        if(datasets[0])
	{
            options = datasets[0].getElementsByTagName('row');
	}
    }

    // bail if there are no options
    if(!options)
    {
        return false;
    }
    // get the select style from the xml from the server
    ajaxSelectStyle = getParam(xml_data,'ajax_select_style');
    // find the select element in the document
    if(ajaxSelectStyle == 'dynamic')
    {
        ajaxSelectId = getParam(xml_data,'ajax_select_id');
        selinput = document.getElementById(ajaxSelectId);
        originalValue = selinput.value;
        displaybox = document.getElementById(ajaxSelectId+'_display');
        selbox = document.getElementById(ajaxSelectId+'_selectionarea');
        if(getParam(xml_data,'ajax_load_state') == 'initial')
        {
            selbox.style.display = "none";
        }
        valueField = getParam(xml_data,'ajax_select_value_field');
        seltable = document.createElement('table');
    }
    else
    {
        selbox = document.getElementById(getParam(xml_data,'ajax_select_id'));
        originalValue = selbox.value;
        valueField = getParam(xml_data,'ajax_select_value_field');
    }
    displayField = getParam(xml_data,'ajax_select_display_field');
    // This 3-way 'if' contains the logic for updating a single input, a select
    // box, or a dynamic input
    if(selbox.tagName.toLowerCase() == 'input')
    {
        row = options[0].getElementsByTagName('field');
        if(valueField)
        {
            // A specific field has been specified, so we have to find this field in the result
            j = 0;
            while(row[j])
            {
                if(row[j].getAttribute('name') == valueField)
                {
                    valueText = row[j].firstChild.data;
                }
                j++;
            }
            selbox.setAttribute('value',valueText);
        }
        else
        {
            // just take the value of the first column
            if(row[0] && row[0].firstChild)
            {
                datavalue = row[0].firstChild.data;
                selbox.value = datavalue;
            }
        }
        if(getParam(xml_data,'ajax_update_mode') == 'all')
        {
            // loop through the forst row, filling all form fields that match field names
            j = 0;
            while(row[j])
            {
                    fieldName = row[j].getAttribute('name');
                    if(FiFormData[fieldName])
                {
                    if(row[j].firstChild)
                    {
                            FiFormData[fieldName].value = row[j].firstChild.data;
                    }
                    else
                    {
                        FiFormData[fieldName].value = "";
                    }
                }
                j++;
            }
        }
    }
    else
    {
        while(selbox.hasChildNodes())
        {
                selbox.removeChild(selbox.firstChild);
        }
        i = 0;
            displayText = ' ';
            valueText = ' ';
        while(i < options.length) 
        {
            row = options[i].getElementsByTagName('field');
            if(valueField && displayField)
            {
                j = 0;
                while(row[j])
                {
                    if(row[j].getAttribute('name') == valueField)
                    {
                            valueText = row[j].firstChild.data;
                    }
                    j++;
                }
                j = 0;
                while(row[j])
                {
                    if(row[j].getAttribute('name') == displayField)
                    {
                            displayText = row[j].firstChild.data;
                    }
                    j++;
                }
            }
            else if(row[1] && row[1].firstChild)
            {
                if(row[0].firstChild)
                {
                    valueText = row[0].firstChild.data;
                }
                else
                {
                    valueText = "";
                }
                displayText = row[1].firstChild.data;
            }
            else
            {
                if(row[0].firstChild)
                {
                    valueText = row[0].firstChild.data;
                }
                else
                {
                    valueText = '';
                }
                displayText = valueText;
            }
            if(ajaxSelectStyle == 'dynamic')
            {
                //window.alert('making rows');
                tr = document.createElement('tr');
                td = document.createElement('td');
                tdtext = document.createTextNode(displayText);
                td.appendChild(tdtext);
                tr.style.cursor = "default";
                tr.setAttribute("onmousedown","clickDynRow(this,'"+ajaxSelectId+"');");
                td.setAttribute("title",valueText);
                if(valueText == originalValue)
                {
                    td.setAttribute('id',ajaxSelectId+'_selected');
                    td.setAttribute('class','selected');
                }
                else
                {
                    td.setAttribute('class','unselected');
                }
                tr.appendChild(td);
                // Display the remaining available columns
                col = 2;
                while(row[col])
                {
                    cell[col] = document.createElement('td');
                    if(row[col].firstChild)
                    {
                        ctext[col] =  document.createTextNode(row[col].firstChild.data);
                        cell[col].setAttribute('class',(valueText == originalValue) ? "selected" : "unselected");
                        cell[col].appendChild(ctext[col]);
                    }
                    tr.appendChild(cell[col]);
                    col++;
                }
                seltable.appendChild(tr);
            }
            else
            {
                option = document.createElement('option');
                opttext = document.createTextNode(displayText);
                option.appendChild(opttext);
                option.setAttribute('value',valueText);
                if(valueText == originalValue)
                {
                    option.setAttribute('selected','selected');
                }
                selbox.appendChild(option);
            }
            i++;
        }
    }
    if(ajaxSelectStyle == 'dynamic')
    {
        if(getParam(xml_data,'ajax_key_value'))
        {
            document.getElementById(ajaxSelectId+'_display').value = seltable.firstChild.firstChild.firstChild.nodeValue;
        }
        seltable.setAttribute("onkeyup","return dynSelectNav(event,'"+ajaxSelectId+"');");
        selbox.appendChild(seltable);
        selectedOption = document.getElementById(ajaxSelectId+'_selected');
        if(!selectedOption)
        {
            seltable.firstChild.firstChild.setAttribute("id",ajaxSelectId+'_selected');
            selCell = seltable.firstChild.firstChild;
            while(selCell)
            {
                selCell.setAttribute("class",'selected');
                selCell = selCell.nextSibling;
            }
            selectedOption = seltable.firstChild.firstChild;
        } // if not selectedOption
        if(selectedOption)
        {
            selectedOptionPos = selectedOption.offsetTop;
            selbox.scrollTop = selectedOptionPos;
        }
    } // if dynamic
    reloadSelectDepends(getParam(xml_data,'ajax_select_id'),(getParam(xml_data,'ajax_load_state') == 'initial'));
    window.status = "";
    return true;
}  // function loadXMLDataset_fillSelect

function getParam(xml_doc,param_name)
{
    params = xml_doc.getElementsByTagName('param');
    counter = 0;
    while(params[counter])
    {
        if(params[counter].getAttribute('name') == param_name)
            return(params[counter].getAttribute('value'));
        counter++;
    }
    return(false);
}

function doAction(response)
{
    // Process any requested action
}

function loadXMLDataset_process() 
{
    var response_params;
    // only if xmlDatasetReq shows "complete"

    if (xmlDatasetReq && xmlDatasetReq.readyState == 4) 
    {
        // only if "OK"
        if ((xmlDatasetReq.status == 200 || xmlDatasetReq.status == 304) && xmlDatasetReq.responseXML) 
        {
            response = xmlDatasetReq.responseXML.documentElement;
            
            if(response.nodeName == 'div')
            {
                drawWin(response);
            }
            if(response.nodeName == 'action')
            {
                doAction(response);
            }
            else if(response.nodeName == 'report')
            {
                if(getParam(response,'ajax_operation') == "fill_select")
                {
                    if(loadXMLDataset_fillSelect(response))
                    {
                        //window.status = 'Select Box Update Successful.';
                    }
                    else
                    {
                        //window.status = 'Select Box Update Failed.';
                    }
                    window.setTimeout('window.status = ""',1000);
                }
                else
                {
                    //window.status = "I don't know what to do with this: " + getParam(response,'ajax_operation');
                }
            }
           else
           {
                //window.status = "Unknown Response Element: " + response.nodeName;
           }
        } 
        else
        {
            //window.status = "There was a problem retrieving the XML data: " + xmlDatasetReq.status + ": " + xmlDatasetReq.statusText;
        }
	window.clearTimeout(currentlyLoadingXML);
        currentlyLoadingXML = false;
    }
    checkQueue(false);
}  // function loadXMLDataset_process


function checkQueue(shouldContinue)
{
    if(currentlyLoadingXML)
    {
        if(shouldContinue == false)
	{
	    window.setTimeout('checkQueue(false);',500);
	}
    }
    else
    {
        nextItem = grabFirstItem();
        if(nextItem)
        {
            loadXMLDataset(nextItem.url,nextItem.elementID,nextItem.method,nextItem.params);
            window.setTimeout('checkQueue(false);',500);
        }
    }
    if(shouldContinue == true)
    {
         window.setTimeout('checkQueue(true);',1500);
    }
} // checkQueue

checkQueue(true);

