/*
    xml.js
*/

var XML = new (function(){

    var _MSXML_DOM_PROGIDS = new Array( 'Msxml2.DOMDocument.6.0',
                                        'Msxml2.DOMDocument.4.0',
                                        'Msxml2.DOMDocument.3.0',
                                        'Msxml2.DOMDocument',
                                        'Microsoft.XMLDOM'
                                      );

    var _MSXML_XSLTEMPLATE_PROGID = new Array('Msxml2.XSLTemplate.6.0',
                                              'Msxml2.XSLTemplate.4.0',
                                              'Msxml2.XSLTemplate.3.0'
                                             );

    var _MSXML_THREADEDDOM_PROGID = new Array('Msxml2.FreeThreadedDOMDocument.6.0',
                                              'MSXML2.FreeThreadedDOMDocument.4.0', 
                                              'MSXML2.FreeThreadedDOMDocument.3.0'
                                             );


    // xmlSource - (string) The name of an XML file or embedded XML data island
    // returns (object) the root node of the XML 
    function ReturnXMLData(xmlSource){

            var oXmlDoc = null;
            switch(typeof(xmlSource)){
                    case "string":
                          if(xmlSource.indexOf(".") != -1 ){ // is it a file name?
							oXmlDoc = XML.Load(xmlSource);
                          }
                          else {                      // it must be an XML Data island
                             oXmlDso = document.getElementById(xmlSource); 
                             oXmlDoc = XML.Load(oXmlDso.XMLDocument);
                          }
                          break;
                    case "object":
							oXmlDoc = XML.Load(oXmlDso.XMLDocument);
                          break;
                    default:
                          alert('Error in \'ReturnXMLData\'. The XML input parameter is of wrong data type.');
            }

            if (!oXmlDoc)
                throw 'Error in ReturnXMLData: the XML file could not be loaded. \n Passed XML source argument: '+ XML +" ("+ typeof(XML) +").";

            return oXmlDoc;
    }


    // Create a new empty Document object
    this.getDomDocument = function(){
	    var oXmlDoc = null;

        // W3C
        if (document.implementation && document.implementation.createDocument){
            oXmlDoc = document.implementation.createDocument('','', null);

        // MSIE
        }else{

	        for (var i=0; i < _MSXML_DOM_PROGIDS.length; i++){
		        try {
			        oXmlDoc = new ActiveXObject(_MSXML_DOM_PROGIDS[i]);
			        _MSXML_DOM_PROGIDS = [_MSXML_DOM_PROGIDS[i]];
			        break;
		        } catch (e) {
			        oXmlDoc = null;
		        }
	        }

        }

        return oXmlDoc;
    };

    // getXsltTemplate()
    this.getXsltTemplate = function(){
        var oXsltTpl = null;

        for (var i=0; i < _MSXML_XSLTEMPLATE_PROGID.length; i++){
            try {
                oXsltTpl = new ActiveXObject(_MSXML_XSLTEMPLATE_PROGID[i]);
                _MSXML_XSLTEMPLATE_PROGID = [_MSXML_XSLTEMPLATE_PROGID[i]];
                break;
            } catch (e) {
                oXsltTpl = null;
            }
        }

        return oXsltTpl;
    };

    // 
    this.getThreadedDomDocument = function (){
        var oXmlDoc = null;

        for (var i=0; i < _MSXML_THREADEDDOM_PROGID.length; i++){
            try {
                oXmlDoc = new ActiveXObject(_MSXML_THREADEDDOM_PROGID[i]);
                _MSXML_THREADEDDOM_PROGID = [_MSXML_THREADEDDOM_PROGID[i]];
                break;
            } catch (e) {
                oXmlDoc = null;
            }
        }

        return oXmlDoc;	
    }

    // Synchronously load the XML document at the specified URL and
    // return it as a Document object
    this.Load = function(url){
        /* deprecated way to load XML doc !!! 2011 July 4  -- IE9 does not support it */
        /*
        var xmldoc = XML.getDomDocument();
        xmldoc.resolveExternals = true;
        xmldoc.async = false;  // load synchronously
        xmldoc.load(url);      // Load and parse !!!! DEPRECATED !! Use XMLHttpRequest instead !
        return xmldoc;         // Return the document
        */
        
        var xhr = Ajax.CreateXhrObject();
        xhr.open('GET', url, false);
        xhr.send(null);
        if (xhr.status == 200){
            return xhr.responseXML;  // Return the document
        }
        else
            alert('Failed. Reason: '+ xhr.statusText);
        delete(xhr);
    };


    /**
     * Asynchronously load and parse an XML document from the specified URL.
     * When the document is ready, pass it to the specified callback function.
     * This function returns immediately with no return value.
     */
    this.LoadAsync = function(url, callback){
        var xmldoc = XML.getDomDocument();
        // If we created the XML document using createDocument, use
        // onload to determine when it is loaded
        if (document.implementation && document.implementation.createDocument){
            xmldoc.onload = function(){ callback(xmldoc); };
        }
        // Otherwise, use onreadystatechange as with XMLHttpRequest
        else {
            xmldoc.resolveExternals = true;
            xmldoc.onreadystatechange = function(){
                if (xmldoc.readyState == 4) callback(xmldoc);
            };
        }

        xmldoc.load(url); // Now go start the download and parsing
    };


    // class
    this.Transformer = function(stylesheet){

        // Load the stylesheet if necessary.
        if (typeof stylesheet == "string")
            stylesheet = XML.Load(stylesheet);
        this.stylesheet = stylesheet;

        // In Mozilla-based browsers, create an XSLTProcessor object and
        // tell it about the stylesheet.
        if (typeof XSLTProcessor != "undefined") {
            this.processor = new XSLTProcessor();
            this.processor.importStylesheet(this.stylesheet);
        }

    };


    /**
     * This is the transform() method of the XML.Transformer class.
     * It transforms the specified xml node using the encapsulated stylesheet.
     *
     * @param  {object || string} The source XML file (XmlDocument instance or URL). 
     * @param  {object || string} the XHTML output container or null if the output should be returned
     * @param  {object} optional object holding parameters to be passed to the XSLT document
     * @return {Object || void} 
     */
    this.Transformer.prototype.Transform = function(xmlNode, targetElement, oParameters){

        if (typeof(targetElement) == "string")
            targetElement = document.getElementById(targetElement);


        var xmlNode = (typeof(xmlNode) != 'object')? ReturnXMLData(xmlNode) : xmlNode;
        var oXmlResult = null;


        if (oParameters == null){

            if (this.processor){
                oXmlResult = this.processor.transformToFragment(xmlNode, window.document);
            }else{
                try{
                    oXmlResult = xmlNode.transformNode(this.stylesheet);
                }catch(e){
                    alert(e);
                }
            }

        }else{

            if (this.processor){

                // set XSLT parameters
                for(var param in oParameters){
                    this.processor.setParameter(null, param, oParameters[param]);
                }
                oXmlResult = this.processor.transformToFragment(xmlNode, window.document);

            }else{
                var xslTemplate = XML.getXsltTemplate();

                var xslDoc = XML.getThreadedDomDocument();
                try{
                    xslDoc.setProperty("AllowXsltScript", true);
                }catch(e){
                }


                xslDoc.async=false;
                xslDoc.resolveExternals = true;
                xslDoc.load(this.stylesheet);

                xslTemplate.stylesheet = xslDoc;
                var xslProcessor = xslTemplate.createProcessor();
                xslProcessor.input = xmlNode;

                // add parameters
                for(var param in oParameters){
                    xslProcessor.addParameter(param, oParameters[param]);
                }

                xslProcessor.transform();
                oXmlResult = xslProcessor.output;               
            }

        }


        if (targetElement != null){
            if (this.processor){
                targetElement.innerHTML = "";
                targetElement.appendChild(oXmlResult);
            }else
                targetElement.innerHTML = oXmlResult;
        }else
            return oXmlResult;

    };

})();

