﻿/*****************************************************************************************
   
Copyright (c) Microsoft Corporation. All rights reserved.

****************************************************************************************/

//  --------------------------------------------------------------------------------------
//  MiscellaneousHelpers.js
//  --------------------------------------------------------------------------------------

var g_AtomNamespaceURI = "http://www/w3/org/2005/Atom";

function AttachEvent(i_Element, i_EventType, i_EventHandler) {
    if (i_Element.addEventListener != null) {
        i_Element.addEventListener
            (
            i_EventType,
            i_EventHandler,
            false
            );
    }
    else if (i_Element.attachEvent != null) {
        i_Element.attachEvent
            (
            'on' + i_EventType,
            i_EventHandler
            );
    }
    else {
        alert('Unable to attach events!');
    }
}

function DetachEvent(i_Element, i_EventType, i_EventHandler) {
    if (i_Element.removeEventListener != null) {
        i_Element.removeEventListener
            (
            i_EventType,
            i_EventHandler,
            false
            );
    }
    else if (i_Element.detachEvent != null) {
        i_Element.detachEvent
            (
            'on' + i_EventType,
            i_EventHandler
            );
    }
    else {
        alert('Unable to detach events!');
    }
}

function ConvertDateToRFC3339DateTime(i_Date) {
    var CurrentDateTime = null;
    if (i_Date != null)
        CurrentDateTime = new Date(i_Date);
    else
        CurrentDateTime = new Date();

    var Year = CurrentDateTime.getYear();
    if (Year < 70)
        Year += 2000;
    else if (Year < 1900)
        Year += 1900;

    var Month = CurrentDateTime.getMonth() + 1;
    if (Month <= 9)
        Month = "0" + Month;

    var Day = CurrentDateTime.getDate();
    if (Day <= 9)
        Day = "0" + Day;

    var HourUTC = CurrentDateTime.getUTCHours();
    if (HourUTC <= 9)
        HourUTC = "0" + HourUTC;

    var MinuteUTC = CurrentDateTime.getUTCMinutes();
    if (MinuteUTC <= 9)
        MinuteUTC = "0" + MinuteUTC;

    var Second = CurrentDateTime.getSeconds();
    if (Second <= 9)
        Second = "0" + Second;

    var RFC3339DateTime = Year + "-" + Month + "-" + Day + "T" + HourUTC + ":" + MinuteUTC + ":" + Second + "Z";
    return RFC3339DateTime;
}

function ConvertRFC3339DateTimeToDate(i_RFC3339DateTime) {
    i_RFC3339DateTime = i_RFC3339DateTime.toLowerCase();
    var DateTimeParts = i_RFC3339DateTime.split("t");

    var DateParts = DateTimeParts[0].split("-");
    var Year = new Number(DateParts[0]);
    var Month = new Number(DateParts[1]) - 1;
    var Day = new Number(DateParts[2]);

    var TimeParts = DateTimeParts[1].split(":");
    var Hours = new Number(TimeParts[0]);
    var Minutes = new Number(TimeParts[1]);
    var Seconds = TimeParts[2];
    Seconds = new Number(Seconds.substr(0, Seconds.indexOf("z")));

    var MillisecondsSince1970 = Date.UTC
        (
        Year,
        Month,
        Day,
        Hours,
        Minutes,
        Seconds
        );

    return new Date(MillisecondsSince1970);
}

function StopEventBubbling(i_Event) {
    if (i_Event == null)
        throw "i_Event can't be null!";

    if (i_Event.stopPropagation) {
        //  W3C method
        i_Event.stopPropagation();
    }
    else {
        //  IE method
        i_Event.cancelBubble = true;
    }
}

function GetBooleanAttributeValue(i_XMLDOMElement, i_AttributeName) {
    var AttributeValue = i_XMLDOMElement.getAttribute(i_AttributeName);
    return parseBool(AttributeValue);
}

function parseBool(i_Value) {
    if (isNaN(parseInt(i_Value))) {
        i_Value = i_Value + "";
        if (i_Value.toLowerCase() == "true")
            return true;

        return false;
    }

    i_Value = i_Value + 0;

    return Boolean(i_Value);
}

function GetSourceElementFromEvent(i_Event) {
    if (i_Event == null)
        i_Event = window.event;

    var SourceElement = null;
    if (i_Event.target != null)
        SourceElement = i_Event.target;
    else if (i_Event.srcElement != null)
        SourceElement = i_Event.srcElement;

    return SourceElement;
}

function XMLEncode(i_String) {
    i_String = i_String.replace("&", "&amp;");
    i_String = i_String.replace(">", "&gt;");
    i_String = i_String.replace("<", "&lt;");
    i_String = i_String.replace("\"", "&quot;");
    i_String = i_String.replace("'", "&#39;");

    return i_String;
}

function XMLDecode(i_String) {
    i_String = i_String.replace("&amp;", "&");
    i_String = i_String.replace("&gt;", ">");
    i_String = i_String.replace("&lt;", "<");
    i_String = i_String.replace("&quot;", "\"");
    i_String = i_String.replace("&#39;", "'");

    return i_String;
}

function CreateXMLDOMDocument() {
    var XMLDOMDocument = null;

    if (IsFirefox()) {
        XMLDOMDocument = document.implementation.createDocument
            (
            "",
            "",
            null
            );
    }
    else {
        XMLDOMDocument = new ActiveXObject("Microsoft.XMLDOM");
    }

    return XMLDOMDocument;
}

function LoadXML(i_SourceLocation, i_ThrowOnFailure) {
    var XMLDOMDocument = CreateXMLDOMDocument();

    XMLDOMDocument.async = false;
    if (!XMLDOMDocument.load(i_SourceLocation))
        XMLDOMDocument = null;

    if ((XMLDOMDocument == null) && i_ThrowOnFailure)
        throw "unable to load xml!";

    return XMLDOMDocument;
}

function ParseXML(i_XML, i_ThrowOnFailure) {
    var XMLDOMDocument = null;

    if (IsFirefox()) {
        var Parser = new DOMParser();
        XMLDOMDocument = Parser.parseFromString
            (
            i_XML,
            "text/xml"
            );

        if (XMLDOMDocument.documentElement.nodeName == 'parsererror')
            XMLDOMDocument = null;
    }
    else {
        XMLDOMDocument = new ActiveXObject("Microsoft.XMLDOM");
        XMLDOMDocument.async = false;
        if (!XMLDOMDocument.loadXML(i_XML))
            XMLDOMDocument = null;
    }

    if ((XMLDOMDocument == null) && i_ThrowOnFailure)
        throw "unable to load xml!";

    return XMLDOMDocument;
}

function SelectSingleNode(i_XMLDOMElement, i_XPathExpression, i_Namespaces, i_ThrowOnFailure) {
    var Node = null;

    if (IsFirefox()) {
        var NamespaceResolver = null;
        var Dictionary = null;

        if (i_Namespaces != null) {
            Dictionary = new Object();

            for (var Index = 0; Index < i_Namespaces.length; ++Index) {
                var Namespace = i_Namespaces[Index];
                var NamespaceParts = Namespace.split("=");
                var NamespacePrefix = NamespaceParts[0].split(":")[1];
                var NamespaceURI = NamespaceParts[1].replace(/'/g, "");

                Dictionary[NamespacePrefix] = NamespaceURI;
            }

            NamespaceResolver = function nsResolver(i_Prefix) {
                return Dictionary[i_Prefix] || null;
            }
        }

        var Result = i_XMLDOMElement.ownerDocument.evaluate
            (
            i_XPathExpression,
            i_XMLDOMElement,
            NamespaceResolver,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
            );

        if (Result != null)
            Node = Result.singleNodeValue;
    }
    else {
        if (i_Namespaces != null) {
            var SelectionNamespaces = i_XMLDOMElement.ownerDocument.getProperty("SelectionNamespaces");
            if (SelectionNamespaces == null)
                SelectionNamespaces = "";

            for (var Index = 0; Index < i_Namespaces.length; ++Index) {
                var Namespace = i_Namespaces[Index];
                if (SelectionNamespaces.indexOf(Namespace) == -1)
                    SelectionNamespaces += Namespace + " ";
            }

            i_XMLDOMElement.ownerDocument.setProperty
                (
                "SelectionNamespaces",
                SelectionNamespaces
                );
        }

        Node = i_XMLDOMElement.selectSingleNode(i_XPathExpression);
    }

    if ((Node == null) && i_ThrowOnFailure)
        throw "SelectSingleNode failed!";

    return Node;
}

function SelectNodes(i_XMLDOMElement, i_XPathExpression, i_Namespaces, i_ThrowIfEmpty) {
    var Nodes = new Array();

    if (IsFirefox()) {
        var NamespaceResolver = null;
        var Dictionary = null;

        if (i_Namespaces != null) {
            Dictionary = new Object();

            for (var Index = 0; Index < i_Namespaces.length; ++Index) {
                var Namespace = i_Namespaces[Index];
                var NamespaceParts = Namespace.split("=");
                var NamespacePrefix = NamespaceParts[0].split(":")[1];
                var NamespaceURI = NamespaceParts[1].replace(/'/g, "");

                Dictionary[NamespacePrefix] = NamespaceURI;
            }

            NamespaceResolver = function nsResolver(i_Prefix) {
                return Dictionary[i_Prefix] || null;
            }
        }

        var Result = i_XMLDOMElement.ownerDocument.evaluate
            (
            i_XPathExpression,
            i_XMLDOMElement,
            NamespaceResolver,
            XPathResult.ORDERED_NODE_ITERATOR_TYPE,
            null
            );

        if (Result != null) {
            var Node = Result.iterateNext();
            while (Node) {
                Nodes.push(Node);
                Node = Result.iterateNext();
            }
        }
    }
    else {
        if (i_Namespaces != null) {
            var SelectionNamespaces = i_XMLDOMElement.ownerDocument.getProperty("SelectionNamespaces");
            if (SelectionNamespaces == null)
                SelectionNamespaces = "";

            for (var Index = 0; Index < i_Namespaces.length; ++Index) {
                var Namespace = i_Namespaces[Index];
                if (SelectionNamespaces.indexOf(Namespace) == -1)
                    SelectionNamespaces += Namespace + " ";
            }

            i_XMLDOMElement.ownerDocument.setProperty
                (
                "SelectionNamespaces",
                SelectionNamespaces
                );
        }

        Nodes = i_XMLDOMElement.selectNodes(i_XPathExpression);
    }

    if ((Nodes.length == 0) && i_ThrowIfEmpty)
        throw "SelectNodes failed!";

    return Nodes;
}

function ImportNode(i_XMLDOMDocument, i_XMLDOMNode, i_IncludeChildren) {
    var ImportedNode = null
    if (IsFirefox()) {
        ImportedNode = i_XMLDOMDocument.importNode
            (
            i_XMLDOMNode,
            i_IncludeChildren
            );
    }
    else {
        switch (i_XMLDOMNode.nodeType) {
            case 1:  // ELEMENT_NODE
                {
                    ImportedNode = i_XMLDOMDocument.createElement(i_XMLDOMNode.nodeName);

                    if (i_XMLDOMNode.attributes && (i_XMLDOMNode.attributes.length > 0)) {
                        for (var Index = 0; Index < i_XMLDOMNode.attributes.length; ++Index) {
                            ImportedNode.setAttribute
                            (
                            i_XMLDOMNode.attributes[Index].nodeName,
                            i_XMLDOMNode.getAttribute(i_XMLDOMNode.attributes[Index].nodeName)
                            );
                        }
                    }

                    if (i_IncludeChildren && (i_XMLDOMNode.childNodes != null) && (i_XMLDOMNode.childNodes.length > 0)) {
                        for (var Index = 0; Index < i_XMLDOMNode.childNodes.length; ++Index) {
                            var ChildImportedNode = ImportNode
                                (
                                i_XMLDOMDocument,
                                i_XMLDOMNode.childNodes[Index],
                                i_IncludeChildren
                                )

                            ImportedNode.appendChild(ChildImportedNode);
                        }
                    }

                    break;
                }

            case 3:  // TEXT_NODE 
            case 4:  // CDATA_SECTION_NODE
            case 8:  // COMMENT_NODE
                {
                    ImportedNode = i_XMLDOMDocument.createTextNode(i_XMLDOMNode.nodeValue);
                    break;
                }

            default:
                {
                    throw "Unhandled node type!";
                }
        }
    }

    return ImportedNode;
}

function GetXML(i_DOMNode) {
    if (IsFirefox()) {
        var Serializer = new XMLSerializer();
        return Serializer.serializeToString(i_DOMNode);
    }

    return i_DOMNode.xml;
}

function GetTextForXMLDOMNode(i_XMLDOMNode) {
    if (IsFirefox())
        return i_XMLDOMNode.textContent;

    return i_XMLDOMNode.text;
}

function SetTextForXMLDOMNode(i_XMLDOMNode, i_Value) {
    if (IsFirefox())
        i_XMLDOMNode.textContent = i_Value;
    else
        i_XMLDOMNode.text = i_Value;
}

function GetTextForHTMLDOMNode(i_HTMLDOMNode, i_Value) {
    if (IsFirefox())
        return i_HTMLDOMNode.innerHTML;

    return i_HTMLDOMNode.innerText;
}

function SetTextForHTMLDOMNode(i_HTMLDOMNode, i_Value) {
    if (IsFirefox())
        i_HTMLDOMNode.innerHTML = i_Value;
    else
        i_HTMLDOMNode.innerText = i_Value;
}

function CreateXMLDOMElement(i_DOMDocument, i_ElementName, i_NamespaceURI) {
    var XMLDOMElement = null;

    if (IsFirefox()) {
        XMLDOMElement = i_DOMDocument.createElementNS
            (
            i_NamespaceURI,
            i_ElementName
            );
    }
    else {
        XMLDOMElement = i_DOMDocument.createNode
            (
            1, // NODE_ELEMENT
            i_ElementName,
            i_NamespaceURI
            );
    }

    return XMLDOMElement;
}

function GetXMLDOMElement(i_ParentXMLDOMElement, i_ElementName, i_NamespaceDeclarations, i_CreateIfNotFound, i_NamespaceURI) {
    var XMLDOMElement = SelectSingleNode
        (
        i_ParentXMLDOMElement,
        i_ElementName,
        i_NamespaceDeclarations,
        false
        );

    if ((XMLDOMElement == null) && i_CreateIfNotFound) {
        XMLDOMElement = CreateXMLDOMElement
            (
            i_ParentXMLDOMElement.ownerDocument,
            i_ElementName,
            i_NamespaceURI
            );
    }

    return XMLDOMElement;
}

function IsFirefox() {
    return (navigator.userAgent.toLowerCase().indexOf("firefox") != -1);
}

function IsNullOrEmpty(i_String) {
    return ((i_String == null) || (i_String == ""));
}

function IsRSSFeed(i_XMLDOMDocument) {
    return (i_XMLDOMDocument.documentElement.baseName == "rss");
}

function IsAtomFeed(i_XMLDOMDocument) {
    return (i_XMLDOMDocument.documentElement.baseName == "atom");
}

function GetItemContainerXMLElement(i_XMLDOMDocument) {
    var NamespaceDeclarations = new Array();

    //  Remove all items
    if (IsRSSFeed(i_XMLDOMDocument))
        ItemContainerXPathPart = "//rss/channel";
    else if (IsAtomFeed(i_XMLDOMDocument)) {
        NamespaceDeclarations[0] = "xmlns:atom='" + g_AtomNamespaceURI + "'";
        ItemContainerXPathPart = "//feed";
    }
    else
        throw "Unknown document type!";

    var ItemContainerXmlElement = SelectSingleNode
        (
        i_XMLDOMDocument.documentElement,
        ItemContainerXPathPart,
        NamespaceDeclarations,
        true
        );

    return ItemContainerXmlElement;
}

function CreateEmptyFeedXMLDOMDocument(i_XMLDOMDocument) {
    var ItemContainerXmlElement = GetItemContainerXMLElement(i_XMLDOMDocument);

    var ParentNode = null;
    if (IsRSSFeed(i_XMLDOMDocument))
        ParentNode = ItemContainerXmlElement.parentNode;
    else
        ParentNode = i_XMLDOMDocument;

    var ClonedItemContainerXmlElement = ItemContainerXmlElement.cloneNode(false);
    ParentNode.removeChild(ItemContainerXmlElement);
    ParentNode.appendChild(ClonedItemContainerXmlElement);

    return i_XMLDOMDocument;
}


function CreateXMLHTTPObject(i_Verb, i_URL, i_Asynchronous) {
    var XMLHTTPObject = null;

    if (IsFirefox())
        XMLHTTPObject = new XMLHttpRequest();
    else
        XMLHTTPObject = new ActiveXObject("Microsoft.XMLHTTP");

    XMLHTTPObject.open
        (
        i_Verb,
        i_URL,
        i_Asynchronous
        );

    return XMLHTTPObject;
}

function PopulateNamespacesForXMLElement(i_Namespaces, i_XMLDOMElement) {
    for (var Index = 0; Index < i_XMLDOMElement.childNodes.length; ++Index) {
        var ChildNode = i_XMLDOMElement.childNodes[Index];
        if (ChildNode.nodeType != 1)
            continue;

        for (var Index2 = 0; Index2 < ChildNode.attributes.length; ++Index2) {
            var Attribute = ChildNode.attributes[Index2];
            if (Attribute.name.indexOf("xmlns:") == -1)
                continue;

            var NamespacePrefix = "";
            var NamespaceURI = "";

            if (Attribute.name.indexOf("xmlns:") != -1)
                NamespacePrefix = Attribute.name.substring(Attribute.name.indexOf(":") + 1);

            NamespaceValue = Attribute.value;

            if (!IsNullOrEmpty(NamespaceValue)) {
                if (i_Namespaces[NamespacePrefix] == null)
                    i_Namespaces[NamespacePrefix] = NamespaceValue;
                else if (i_Namespaces[NamespacePrefix] != NamespaceValue)
                    throw "Different values for same namespace prefix of '" + NamespacePrefix + "'";
            }
        }

        PopulateNamespacesForXMLElement(i_Namespaces, ChildNode);
    }
}

function GetNamespacesForXMLDOMDocument(i_XMLDOMDocument) {
    var Namespaces = new Object();

    PopulateNamespacesForXMLElement(Namespaces, i_XMLDOMDocument.documentElement);

    return Namespaces;
}

function GetMappedXMLNamespacePrefix(i_Namespaces, i_PreferredNamespacePrefix, i_NamespaceURI) {
    var MappedNamespacePrefix = i_PreferredNamespacePrefix;

    for (var key in i_Namespaces) {
        var NamespaceURI = i_Namespaces[key];

        if (NamespaceURI != i_NamespaceURI)
            continue;

        if (key == i_PreferredNamespacePrefix)
            break;

        //  Check for default namespace
        if (IsNullOrEmpty(key)) {
            //  See if prefix used
            if (i_Namespaces[i_PreferredNamespacePrefix] != null) {
                //  See if prefix is mapped to namespace uri
                if (i_Namespaces[i_PreferredNamespacePrefix] != i_NamespaceURI) {
                    //  Create a new prefix
                    MappedNamespacePrefix = i_PreferredNamespacePrefix + new Date().getTime() + Math.floor(Math.random() * 1001);
                }
            }

            break;
        }
    }

    //  Add namespace with mapped prefix
    if (i_Namespaces[MappedNamespacePrefix] == null)
        i_Namespaces[MappedNamespacePrefix] = i_NamespaceURI;

    return MappedNamespacePrefix;
}

function CreateXMLDOMElementHierarchy(i_XMLDOMDocument, i_ParentXMLDOMElement, i_ElementNames, i_NamespaceURIs, i_NamespacePrefixes, i_NamespaceDeclarations, i_AlwaysCreateLastElement) {
    if (i_ElementNames.length != i_NamespaceURIs.length)
        throw "ElementNames length not same as NamespaceURIs length!";

    var XMLDOMElement = null;
    var ParentXMLDOMElement = i_ParentXMLDOMElement;

    for (var Index = 0; Index < i_ElementNames.length; ++Index) {
        var ElementName = i_ElementNames[Index];
        var NamespaceURI = i_NamespaceURIs[Index];
        var NamespacePrefix = i_NamespacePrefixes[Index];

        var ForceElementCreation = (i_AlwaysCreateLastElement && (Index == i_ElementNames.Length - 1));

        if (!IsNullOrEmpty(NamespacePrefix))
            ElementName = NamespacePrefix + ":" + ElementName;

        if (!ForceElementCreation) {
            //  See if node already exists
            XMLDOMElement = SelectSingleNode
                (
                i_ParentXMLDOMElement,
                ElementName,
                i_NamespaceDeclarations
                );

            ForceElementCreation = (XMLDOMElement == null);
        }

        //  Determine if we should create new node
        if (ForceElementCreation) {
            //  Create and append new node
            XMLDOMElement = CreateXMLDOMElement
                (
                i_XMLDOMDocument,
                ElementName,
                NamespaceURI
                );

            ParentXMLDOMElement.appendChild(XMLDOMElement);
        }

        ParentXMLDOMElement = XMLDOMElement;
    }

    return XMLDOMElement;
}

