// =========================================================================
//
// xmlIO.js - api for the xmlIO functions
//
// version 3.1 
//
// =========================================================================
//
// Copyright (C) 2002 - 2003 David Joham (djoham@yahoo.com)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser 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

//NOTE: parts of this code were inspired by the book JavaScript Unleashed by R. Allen Wyke, Richard Wagner

//NOTE: parts of this code were inspired by http://developer.apple.com/internet/javascript/iframe.html


//NOTE: Part of this code was written on Feb 1, 2003 after I had learned of the destruction of the space shuttle Columbia.
//      My heart goes out to the families of the seven brave astronauts: 
//      Colonel Rick Husband, Lieutenant Colonel Michael Anderson, Commander Laurel Clark, Captain David Brown, 
//      Commander William McCool, Dr. Kalpana Chawla, and Colonel Ilan Ramon of the Israeli air force. 
//		May they rest in peace.

//		Hail Mary, full of grace. The Lord is with thee. 
//		Blessed art thou amongst women, and blessed is the fruit of thy womb, Jesus.
// 		Holy Mary, Mother of God, pray for us sinners,
//		now and at the hour of our death.
//		Amen
//
//		In memory of STS-107
// modified by D.Perry 2004-8-9



var _xmlIOProxyGetLastLoadStatus = "";
var _xmlIOLoadLocalDataCallbackFunction = "";
var _xmlIOLoadlocalDataIFrameID = "";
var _xmlIOLoadLocalDataLastLoadStatus = "";
var _xmlIOLoadLocalDataRetryCount = 0;
var _xmlIOLoadlocalDataIFrameIDLoaded = false;
var _xmlIOLoadlocalDataIFrameNSmode = false;

var isIE = false;
var isIEMac = false;

/************************************************************************************************************
*************************************************************************************************************
*************************************************************************************************************
                        LOADING XML VIA LOCAL FILE ACCESS
         (files on the same web server or files on the local hard drive)
*************************************************************************************************************
*************************************************************************************************************
*************************************************************************************************************/

function xmlIOLoadLocalData(dataURL, callbackFunction) {
	//alert( "GET "+dataURL);
	//window.status = dataURL;
    /********************************************************************************
    Function: xmlIOLoadLocalData

    Author: djoham@yahoo.com

    Description:
            Loads up an IFRAME in the background with its src being dataURL
            then goes through an enourmous amount of stupid gymnastics to make
            sure it gets that data back to the calling javascript
    ********************************************************************************/
document.body.style.cursor = "wait";
    _xmlIOLoadLocalDataCallbackFunction = callbackFunction;
    _xmlIOLoadLocalDataLastLoadStatus = "Starting xmlIOLoadLocalData";
    var _xmlIOLoadLocalDataRetryCount = 0;

    //create the IFrame and start the loading process
    var dataFrame;
    var xmlIOLoadlocalDataIFrameID;
    try {
        try {
            dataFrame = document.createElement("iframe");
            //dataFrame.src has to be here for konq 3.0x to work properly
            dataFrame.src = dataURL;
            dataFrame.id = new Date().valueOf();
            dataFrame.name = dataFrame.id;
            dataFrame.style.position = "absolute";
            dataFrame.style.left = "-2000px";
			xmlIOLoadlocalDataIFrameID = dataFrame.id;
            _xmlIOLoadlocalDataIFrameID = xmlIOLoadlocalDataIFrameID;
            document.body.appendChild(dataFrame);
        }
        catch (e) {
            _xmlIOLoadLocalDataLastLoadStatus = "ERROR: xmlIOLoadLocalData cannot be used in this browser";
        }
        if (!document.readyState) {
            //try to do the onload (mozilla goes here)
            _xmlIOLoadlocalDataIFrameIDLoaded = false;
            _xmlIOLoadlocalDataIFrameNSmode = true;
            dataFrame.onload = __loadLocalIFrameXMLloaded;
            window.setTimeout("__readyStateChecker("+xmlIOLoadlocalDataIFrameID+",'"+callbackFunction+"')", 250);
        }
        else {
        _xmlIOLoadlocalDataIFrameIDLoaded = false;
        _xmlIOLoadlocalDataIFrameNSmode = false;
            //else send it to the readystatechecker (everybody elses goes here)
            window.setTimeout("__readyStateChecker("+xmlIOLoadlocalDataIFrameID+",'"+callbackFunction+"')", 250);
        }
    }
    catch (badFailure) {
        _xmlIOLoadLocalDataLastLoadStatus = badFailure;
    }

    _xmlIOLoadLocalDataLastLoadStatus = "Ending xmlIOLoadLocalData";


} // end function xmlIOLoadLocalData


function __loadLocalIFrameXMLloaded(){
	_xmlIOLoadlocalDataIFrameIDLoaded = true;
}

function __readyStateChecker(xmlIOLoadlocalDataIFrameID,callbackFunction) {
    /********************************************************************************
    Function: __readyStateChecker

    Author: djoham@yahoo.com

    Description:
            checks the readState of the IFrame document. Tries again and again
            for 10 seconds before it gives up and sends control to the function
            that returns the XML back to the callback function

    *********************************************************************************/

    var dataFrame;
    var dataFrameLoaded=false;

    _xmlIOLoadLocalDataLastLoadStatus = "Starting __readyStateChecker";

    try {
        //(konq, Opera and Moz go here)
        dataFrame = document.getElementById(_xmlIOLoadlocalDataIFrameID).contentDocument.readyState;
    }
    catch (imIE) {
		isIE = true;
        try {
            //(IE win or mac)
            dataFrame = document.getElementById(_xmlIOLoadlocalDataIFrameID).contentWindow.document.readyState;
        }
        catch (imIEMac) {
			isIEMac = true;
            try {
                //mac IE goes here - mac ie readystate doesn't seem to work,
                //so I just check for an empty innerHTML.
                //try for 10 seconds
                if (_xmlIOLoadLocalDataRetryCount < 41) {
                    if (__trim(window.frames[_xmlIOLoadlocalDataIFrameID].document.body.innerHTML, true, true) == "") {
                        _xmlIOLoadLocalDataRetryCount++;
                        _xmlIOLoadLocalDataLastLoadStatus = "Calling __readyStateChecker again";
                        window.setTimeout("__readyStateChecker("+xmlIOLoadlocalDataIFrameID+",'"+callbackFunction+"')", 250);
                        return;
                    }
                    else {
                        //we have data - assume we have it all and call the IFrame XML getter
                        _xmlIOLoadLocalDataLastLoadStatus = "Calling __loadLocalIFrameXML";
                        __loadLocalIFrameXML(xmlIOLoadlocalDataIFrameID,callbackFunction);
                        return;
                    }
                }
                else {
                    //maybe the document is supposed to be empty?
                    _xmlIOLoadLocalDataLastLoadStatus = "__readyStateChecker TimeOut - calling __loadLocalIFrameXML anyway";
                    __loadLocalIFrameXML(xmlIOLoadlocalDataIFrameID,callbackFunction);
                }
                return;
            }
            catch (badFailure) {
                //punt
                _xmlIOLoadLocalDataLastLoadStatus = "__readStateChecker unrecoverable error: " + badFailure;
                return;
            }
        }
    }
   
    if( _xmlIOLoadlocalDataIFrameNSmode ){
		if( _xmlIOLoadlocalDataIFrameIDLoaded ){
			dataFrameLoaded = true;
			dataFrame ="complete";
		}
    }else{
		if( dataFrame.toLowerCase() == "complete" ){
			dataFrameLoaded = true;
		}
    }
    
    
    if( !( dataFrameLoaded ) ) {
        //try for 10 seconds
        if (_xmlIOLoadLocalDataRetryCount > 40 ) {
            //giving up and calling the local IFrame XML getter
            _xmlIOLoadLocalDataLastLoadStatus = "__readyStateChecker TimeOut - calling __loadLocalIFrameXML anyway";
            __loadLocalIFrameXML(xmlIOLoadlocalDataIFrameID,callbackFunction);
        }
        else {
            //try again
            _xmlIOLoadLocalDataRetryCount++;
            _xmlIOLoadLocalDataLastLoadStatus = "Calling __readyStateChecker again";
            window.setTimeout("__readyStateChecker("+xmlIOLoadlocalDataIFrameID+",'"+callbackFunction+"')", 250);
        }
    }
    else {
        _xmlIOLoadLocalDataLastLoadStatus = "Calling __loadLocalIFrameXML";
        __loadLocalIFrameXML(xmlIOLoadlocalDataIFrameID,callbackFunction);
    }

} // end function __readyStateChecker


function __loadLocalIFrameXML(xmlIOLoadlocalDataIFrameID,callbackFunction) {
    /********************************************************************************
    Function: __loadLocalIFrameXML

    Author: djoham@yahoo.com

    Description:
            Gets the XML from the IFrame created in xmlIOLoadLocalData,
            unescapes it and then sends it to the callback function

    *********************************************************************************/

    xmlIOLoadlocalDataIFrameID=_xmlIOLoadlocalDataIFrameID;
    callbackFunction=_xmlIOLoadLocalDataCallbackFunction;
    
    _xmlIOLoadLocalDataLastLoadStatus = "Starting __loadLocalIFrameXML";

    var xmlString = "";

    try {
        var dataFrame = document.getElementById(_xmlIOLoadlocalDataIFrameID);
        try {
            //(Konqueror, Opera and Mozilla get this)
            xmlString = dataFrame.contentDocument.body.innerHTML;
        }
        catch (imIE) {
            try {
                xmlString = dataFrame.contentWindow.document.body.innerHTML;
            }
            catch (imIEMac) {
                xmlString = window.frames[_xmlIOLoadlocalDataIFrameID].document.body.innerHTML;
            }
        }
        try {
            document.body.removeChild(dataFrame);
        }
        catch (badFailure) {
            _xmlIOLoadLocalDataLastLoadStatus = "__loadLocalIFrameXML unrecoverable error(1): " + badFailure;
        }
    }
    catch (badFailure2) {
        _xmlIOLoadLocalDataLastLoadStatus = "__loadLocalIFrameXML unrecoverable error(2): " + badFailure2;
    }

    try {
        //The xmlString is escaped. use the XML for <SCRIPT>'s unescape function.
        //Put the catch in here to make sure the programmer has included it
        xmlString = xmlUnescapeHTMLToXML(xmlString)
    }
    catch (e) {
        alert(e);
        _xmlIOLoadLocalDataLastLoadStatus = "__loadLocalIFrameXML unrecoverable error: The function xmlUnescapeHTMLToXML was not found. Did you include xmlEscape.js (from the jsTools directory) in your HTML file?";
    }

    try {

        eval(callbackFunction + "(xmlString)");
        _xmlIOLoadLocalDataLastLoadStatus = "__loadLocalIFrameXML successfully called callback function";
    }
    catch (e) {
    	_xmlIOLoadLocalDataLastLoadStatus = "__loadLocalIFrameXML unrecoverable error: Is your callback function correct?";
    }
   document.body.style.cursor = "default";

}

function xmlIOLoadLocalGetLastLoadStatus() {

    return _xmlIOLoadLocalDataLastLoadStatus;

} //end function xmlIOLoadLocalGetLastLoadStatus


function __trim(trimString, leftTrim, rightTrim) {
	var whitespace = "\n\r\t ";

	if (__isEmpty(trimString)) {
        return "";
    }

    // the general focus here is on minimal method calls - hence only one
    // substring is done to complete the trim.

    if (leftTrim == null) {
        leftTrim = true;
    }

    if (rightTrim == null) {
        rightTrim = true;
    }

    var left=0;
    var right=0;
    var i=0;
    var k=0;

    // modified to properly handle strings that are all whitespace
    if (leftTrim == true) {
        while ((i<trimString.length) && (whitespace.indexOf(trimString.charAt(i++))!=-1)) {
            left++;
        }
    }
    if (rightTrim == true) {
        k=trimString.length-1;
        while((k>=left) && (whitespace.indexOf(trimString.charAt(k--))!=-1)) {
            right++;
        }
    }
    return trimString.substring(left, trimString.length - right);
} // end function _trim



function __isEmpty(str) {
    return (str==null) || (str.length==0);

} // end function __isEmpty



function xmlEscapeXMLToHTML(xmlData) {
    var gt; 

    var str = xmlData;

    //replace < with «
    gt = -1;
    while (str.indexOf("<", gt + 1) > -1) {
        var gt = str.indexOf("<", gt + 1);
        var newStr = str.substr(0, gt);
        newStr += "«";
        newStr = newStr + str.substr(gt + 1, str.length);
        str = newStr;
    }

    //replace > with »
    gt = -1;
    while (str.indexOf(">", gt + 1) > -1) {
        var gt = str.indexOf(">", gt + 1);
        var newStr = str.substr(0, gt);
        newStr += "»";
        newStr = newStr + str.substr(gt + 1, str.length);
        str = newStr;
    }

    //replace & with §
    gt = -1;
    while (str.indexOf("&", gt + 1) > -1) {
        var gt = str.indexOf("&", gt + 1);
        var newStr = str.substr(0, gt);
        newStr += "§";
        newStr = newStr + str.substr(gt + 1, str.length);
        str = newStr;
    }

    return str

}  // end function xmlEscapeXMLToHTML


function xmlUnescapeHTMLToXML(xmlData)  {
    var str = xmlData;

    var gt;

    //replace « with <
    gt = -1;
    while (str.indexOf("«", gt + 1) > -1) {
        var gt = str.indexOf("«", gt + 1);
        var newStr = str.substr(0, gt);
        newStr += "<";
        newStr = newStr + str.substr(gt + 1, str.length);
        str = newStr;
    }


    //replace » with >
    gt = -1;
    while (str.indexOf("»", gt + 1) > -1) {
        var gt = str.indexOf("»", gt + 1);
        var newStr = str.substr(0, gt);
        newStr += ">";
        newStr = newStr + str.substr(gt + 1, str.length);
        str = newStr;
    }

    //replace § with &
    gt = -1;
    while (str.indexOf("§", gt + 1) > -1) {
        var gt = str.indexOf("§", gt + 1);
        var newStr = str.substr(0, gt);
        newStr += "&";
        newStr = newStr + str.substr(gt + 1, str.length);
        str = newStr;
    }

    //replace § with &
    gt = -1;
    while (str.indexOf("&amp;", gt + 1) > -1) {
        var gt = str.indexOf("&amp;", gt + 1);
        var newStr = str.substr(0, gt);
        newStr += "&";
        newStr = newStr + str.substr(gt + 5, str.length);
        str = newStr;
    }

    return str

}// end function xmlUnescapeHTMLToXML

