﻿var _url = "";
var _callback = null;
var _xmlHttp = null;
var _xmlDoc = null;
var _onSuccessMethod = null;

var _isAsync = false;

var AjaxAPI = new Object();
AjaxAPI.init = function(url, callback, onSuccessMethod, isAsync)
{
    _url = url;
    _callback = callback;
    _onSuccessMethod = onSuccessMethod;
    _isAsync = isAsync;
}

AjaxAPI.exec = function()
{
    var cback = null;
    if (!_callback)
    {
        cback = _defaultAjaxCallback;
    }
    else
    {
        cback = _callback;
    }
    
    _xmlHttp = _getXMLHTTPObject();
    if(_xmlHttp != null)
    {
        try
        {
            _xmlHttp.open("GET", _url, _isAsync);
            _xmlHttp.onreadystatechange = cback;
            _xmlHttp.send(null);
        }
        catch(ex)
        {
            return false;
        }
    }
    else
    {
        return false;
    }
    
    // success
    return true;
}

AjaxAPI.GetUrl = function()
{
    return _url;
}
AjaxAPI.GetCallback = function()
{
    return _callback;
}
AjaxAPI.GetXmlHttp = function()
{
    return _xmlHttp;
}
AjaxAPI.GetOnSuccessMethod = function()
{
    return _onSuccessMethod;
}
AjaxAPI.GetXmlDoc = function()
{
    return _xmlDoc;
}
AjaxAPI.IsAsync = function()
{
    return _isAsync;
}
AjaxAPI.SetPopulator = function(populator)
{
    _populator = populator;
}

// private 
function _getXMLHTTPObject()
{
    var obj = null;
    try
    {
        obj = new XMLHttpRequest();
    }
    catch(e)
    {
        try
        {
	        obj = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch(ex)
        {
	        obj = null;
        }
    }

    return obj;
}  
        
function _defaultAjaxCallback()
{
    if(_xmlHttp.readyState == 4)
    {
        if(_xmlHttp.status == 200)
        {
            _xmlDoc = _xmlHttp.responseXML;
            
            // on success method passed from client gets called if not null, else nothing is done
            if (_onSuccessMethod)
            {
                _onSuccessMethod();
            }
        }
        else
        {
            alert("Problem with AJAX:\n" + _xmlHttp.statusText);
        }
    }
} 

/**
* Create a new Document object. If no arguments are specified,
* the document will be empty. If a root tag is specified, the document
* will contain that single root tag. If the root tag has a namespace
* prefix, the second argument must specify the URL that identifies the
* namespace.
*/
XML = new Object();
XML.newDocument = function(rootTagName, namespaceURL) 
{
    if (!rootTagName) rootTagName = "";
    if (!namespaceURL) namespaceURL = "";
    if (document.implementation && document.implementation.createDocument) 
    {
        // This is the W3C standard way to do it
        return document.implementation.createDocument(namespaceURL, rootTagName, null);
    }
    else 
    { 
        // This is the IE way to do it
        // Create an empty document as an ActiveX object
        // If there is no root element, this is all we have to do
        var doc = new ActiveXObject("MSXML2.DOMDocument");
        // If there is a root tag, initialize the document
        if (rootTagName) 
        {
            // Look for a namespace prefix
            var prefix = "";
            var tagname = rootTagName;
            var p = rootTagName.indexOf(':');
            if (p != -1)    
            {
                prefix = rootTagName.substring(0, p);
                tagname = rootTagName.substring(p + 1);
            }
            // If we have a namespace, we must have a namespace prefix
            // If we don't have a namespace, we discard any prefix
            if (namespaceURL) 
            {
                if (!prefix) prefix = "a0"; // What Firefox uses
            }
            else 
            {
                prefix = "";
            }
            // Create the root element (with optional namespace) as a
            // string of text
            var text = "<" + (prefix ? (prefix+":") : "") + tagname + 
                (namespaceURL ?(" xmlns:" + prefix + '="' + namespaceURL + '"') : "") + "/>";
            // And parse that text into the empty document
            doc.loadXML(text);
        }
        
        return doc;
    }
}

/**
* Synchronously load the XML document at the specified URL and
* return it as a Document object
*/
XML.load = function(url) 
{
    // Create a new document with the previously defined function
    var xmldoc = XML.newDocument();
    xmldoc.async = false; // We want to load synchronously
    xmldoc.load(url); // Load and parse
    
    return xmldoc; // Return the document
}


/**
* 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.
*/
XML.loadAsync = function(url, callback) 
{
    var xmldoc = XML.newDocument();
    
    // 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.onreadystatechange = function() 
        {
            if (xmldoc.readyState == 4) 
            {
                callback(xmldoc);
            }
        }
    }
    
    // Now go start the download and parsing
    xmldoc.load(url);
}

/**
* Parse the XML document contained in the string argument and return
* a Document object that represents it.
*/
XML.parse = function(text) 
{
    if (typeof(DOMParser) != "undefined") 
    {
        // Mozilla, Firefox, and related browsers
        return (new DOMParser()).parseFromString(text, "application/xml");
    }
    else if (typeof(ActiveXObject) != "undefined") 
    {
        // Internet Explorer.
        var doc = XML.newDocument(); // Create an empty document
        doc.loadXML(text); // Parse text into it
        return doc; // Return it
    }
    else 
    {
        // As a last resort, try loading the document from a data: URL
        // This is supposed to work in Safari. Thanks to Manos Batsis and
        // his Sarissa library (sarissa.sourceforge.net) for this technique.
        var url = "data:text/xml;charset=utf-8," + encodeURIComponent(text);
        var request = new XMLHttpRequest();
        request.open("GET", url, false);
        request.send(null);
        return request.responseXML;
    }
}


// ###################### XSLT

/**
* This XML.Transformer class encapsulates an XSL stylesheet.
* If the stylesheet parameter is a URL, we load it.
* Otherwise, we assume it is an appropriate DOM Document.
*/
XML.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.
* The results of the transformation are assumed to be HTML and are used to
* replace the content of the specified element.
*/
XML.Transformer.prototype.transform = function(node, element) 
{
    // If element is specified by id, look it up.
    if (typeof(element) == "string") 
    {
        element = document.getElementById(element);
    }
    if (this.processor) 
    {
        // If we've created an XSLTProcessor (i.e., we're in Mozilla) use it.
        // Transform the node into a DOM DocumentFragment.
        var fragment = this.processor.transformToFragment(node, document);
        // Erase the existing content of element.
        element.innerHTML = "";
        // And insert the transformed nodes.
        element.appendChild(fragment);
    }
    else if ("transformNode" in node) 
    {
        // If the node has a transformNode() function (in IE), use that.
        // Note that transformNode() returns a string.
        element.innerHTML = node.transformNode(this.stylesheet);
    }
    else 
    {
        // Otherwise, we're out of luck.
        throw ("XSLT is not supported in this browser");
    }
}
    
/**
* This is an XSLT utility function that is useful when a stylesheet is
* used only once.
*/
XML.transform = function(xmldoc, stylesheet, element) 
{
    var transformer = new XML.Transformer(stylesheet);
    transformer.transform(xmldoc, element);
}

// ########################### XPATH

/**
* XML.XPathExpression is a class that encapsulates an XPath query and its
* associated namespace prefix-to-URL mapping. Once an XML.XPathExpression
* object has been created, it can be evaluated one or more times (in one
* or more contexts) using the getNode( ) or getNodes( ) methods.
*
* The first argument to this constructor is the text of the XPath expression.
*
* If the expression includes any XML namespaces, the second argument must
* be a JavaScript object that maps namespace prefixes to the URLs that define
* those namespaces. The properties of this object are the prefixes, and
* the values of those properties are the URLs.
*/
XML.XPathExpression = function(xpathText, namespaces) 
{
    this.xpathText = xpathText; // Save the text of the expression
    this.namespaces = namespaces; // And the namespace mapping
    if (document.createExpression) 
    {
        // If we're in a W3C-compliant browser, use the W3C API
        // to compile the text of the XPath query
        this.xpathExpr = document.createExpression(xpathText,
                                                    // This function is passed a
                                                    // namespace prefix and returns the URL.
                                                    function(prefix) 
                                                    {
                                                        return namespaces[prefix];
                                                    }
                                                  );
    }
    else 
    {
        // Otherwise, we assume for now that we're in IE and convert the
        // namespaces object into the textual form that IE requires.
        this.namespaceString = "";
        if (namespaces != null) 
        {
            for (var prefix in namespaces) 
            {
                // Add a space if there is already something there
                if (this.namespaceString) 
                {
                    this.namespaceString += ' ';
                }
                // And add the namespace
                this.namespaceString += 'xmlns:' + prefix + '="' +
                namespaces[prefix] + '"';
            }
        }
    }
}

/**
* This is the getNodes( ) method of XML.XPathExpression. It evaluates the
* XPath expression in the specified context. The context argument should
* be a Document or Element object. The return value is an array
* or array-like object containing the nodes that match the expression.
*/
XML.XPathExpression.prototype.getNodes = function(context) 
{
    if (this.xpathExpr) 
    {
        // If we are in a W3C-compliant browser, we compiled the
        // expression in the constructor. We now evaluate that compiled
        // expression in the specified context.
        var result = this.xpathExpr.evaluate(context,
                                // This is the result type we want
                                XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
                                null);
        // Copy the results we get into an array.
        var a = new Array(result.snapshotLength);
        for(var i = 0; i < result.snapshotLength; i++) 
        {
            a[i] = result.snapshotItem(i);
        }
        return a;
    }
    else 
    {
        // If we are not in a W3C-compliant browser, attempt to evaluate
        // the expression using the IE API.
        try 
        {
            // We need the Document object to specify namespaces
            var doc = context.ownerDocument;
            // If the context doesn't have ownerDocument, it is the Document
            if (doc == null) 
            {
                doc = context;
            }
            // This is IE-specific magic to specify prefix-to-URL mapping
            doc.setProperty("SelectionLanguage", "XPath");
            doc.setProperty("SelectionNamespaces", this.namespaceString);
            // In IE, the context must be an Element not a Document,
            // so if context is a document, use documentElement instead
            if (context == doc) 
            {
                context = doc.documentElement;
            }
            // Now use the IE method selectNodes() to evaluate the expression
            return context.selectNodes(this.xpathText);
        }
        catch(e) 
        {
            // If the IE API doesn't work, we just give up
            throw ("XPath not supported by this browser.");
        }
    }
}


/**
* This is the getNode( ) method of XML.XPathExpression. It evaluates the
* XPath expression in the specified context and returns a single matching
* node (or null if no node matches). If more than one node matches,
* this method returns the first one in the document.
* The implementation differs from getNodes( ) only in the return type.
*/
XML.XPathExpression.prototype.getNode = function(context) 
{
    if (this.xpathExpr) 
    {
        var result = this.xpathExpr.evaluate(context,
                                            // We just want the first match
                                            XPathResult.FIRST_ORDERED_NODE_TYPE,
                                            null);
        return result.singleNodeValue;
    }
    else 
    {
        try 
        {
            var doc = context.ownerDocument;
            if (doc == null) 
            {
                doc = context;
            }
            doc.setProperty("SelectionLanguage", "XPath");
            doc.setProperty("SelectionNamespaces", this.namespaceString);
            if (context == doc) 
            {
                context = doc.documentElement;
            }
            // In IE call selectSingleNode instead of selectNodes
            return context.selectSingleNode(this.xpathText);
        }
        catch(e) 
        {
            throw("XPath not supported by this browser.");
        }
    }
}

// A utility to create an XML.XPathExpression and call getNodes( ) on it
XML.getNodes = function(context, xpathExpr, namespaces) 
{
    return (new XML.XPathExpression(xpathExpr, namespaces)).getNodes(context);
}

// A utility to create an XML.XPathExpression and call getNode( ) on it
XML.getNode = function(context, xpathExpr, namespaces) 
{
    return (new XML.XPathExpression(xpathExpr, namespaces)).getNode(context);
    
    
    
}

/**
* Serialize an XML Document or Element and return it as a string.
*/
XML.serialize = function(node) 
{
    if (typeof XMLSerializer != "undefined")
    {
        return (new XMLSerializer()).serializeToString(node);
    }
    else if (node.xml) 
    {
        return node.xml;
    }
    else 
    {
        throw("XML.serialize is not supported or can't serialize " + node);
    }
}