/**
 *$Id: xml.js 86 2008-10-31 17:45:30Z aanpilogov $
 *
 * Работа с XML документами
 */
PuskFramework.xml = new function()
{
    var pf = PuskFramework;

    /**
     * Создание XML документа
     * @return {Document}
     */
    this.createDocument = function(root, ns)
    {
        root = root || '';
        ns = ns || null;
        if (window.ActiveXObject)
        {
            var nsStr = ns ? ' xmlns="'+ns+'"' : '';
            var xmlDocument = new ActiveXObject("Msxml2.DOMDocument.3.0");
            xmlDocument.async = false;
            if (root != '')
                xmlDocument.loadXML('<'+root+nsStr+'/>');
        } else {
            var xmlDocument = document.implementation.createDocument(ns, root, null);
        }
        return xmlDocument;
    };

    /**
    * Создает элемент и заполняет его указанным контентом или элементом
    */
    this.createElement = function(name, attr, value)
    {
        if (!name) throw {"message":"PuskFramework.xml.createElement: No element name"};
        value = value || false;
        if (attr && (typeof attr.xmlns != 'undefined') && (typeof this._doc.createElementNS == 'function'))
        {
            var elem = this._doc.createElementNS(attr.xmlns, name);
        }
        else
        {
        var elem = this._doc.createElement(name);
        }

        if (attr) { this.setAttributes(elem, attr); }

        if (typeof value == 'string')
        {
            elem.appendChild(this._doc.createTextNode(value));
        }
        else if(value.tagName)
        {
            elem.appendChild(value);
        }
        else if(pf.$type(value) == 'array')
        {
            for(var i = 0; i < value.length; i++) elem.appendChild(value[i]);
        }
        return elem;
    };

    /**
     * Парсит текст как XML документ
     *
     * @param {String} txt xml текст
     * @return {Object}
     */
    this.parse = function(txt)
    {
        if (!txt) return pf.xml.createDocument();
        if (window.ActiveXObject)
        {
            var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async = false;
            xmlDoc.validateOnParse = false;
            xmlDoc.loadXML(txt);
        }
        else
        {
            var parser = new DOMParser();
            var xmlDoc = parser.parseFromString(txt,"text/xml");
        }
        return xmlDoc;
    };

    /**
     * Сериализация узла документа в строку
     *
     * @param {Object} node узел
     * @return {String}
     */
    this.serialize = function(node)
    {
        if (!node) return false;
        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;
    };

    /**
    * Задать атрибуты узлу. Пакетом...
    */
    this.setAttributes = function(node, attributes)
    {
        if (node && node.nodeType == 1)
            for (var n in attributes)
            {
                if (attributes[n] != '')
                {
                    if (attributes[n] == null) attributes[n] = '';
                        node.setAttribute(n, attributes[n].toString ? attributes[n].toString() : attributes[n]);
                }
            }
    };

    /**
     * Преобразование фрагмента в документ
     *
     * @param {Object} fragment фрагмент
     * @param {Object} params параметры
     * @return {Document}
     */
    this.fragment2document = function(fragment, params)
    {
        var xmlDocument = pf.xml.createDocument('document');
        if (!fragment) return xmlDocument;
        params = params || {};
        
        var xmlRoot = xmlDocument.documentElement;
        if (params.id) xmlRoot.setAttribute('xhrId', params.id);
        if (params.instance) xmlRoot.setAttribute('instance', params.instance);

        for (var i=0, len = fragment.childNodes.length; i<len; i++)
        {
            xmlRoot.appendChild( fragment.childNodes[i].cloneNode(true) );
        }

        return xmlDocument;
    };

    this.get = function(elem, tagName, NS)
    {
        if (pf.$type(elem) != "element") throw pf.$exGen('pf.xml.get(): ' + 'typeof(elem) argument is ' + pf.$type(elem) + ', "element" expected');
        //if (!elem) return document.getElementsByTagName(null);
    
        if (NS && NS != '')
        {
            if (typeof elem.getElementsByTagNameNS == 'function')
                return elem.getElementsByTagNameNS(NS, tagName);
            else
            {
                elem.ownerDocument.setProperty('SelectionLanguage', 'XPath');
                return elem.selectNodes("*[local-name()='"+tagName+"' and namespace-uri()='"+NS+"']");
            }
        }
        else
        {
            return elem.getElementsByTagName(tagName);
        }
    };

    this.ns = function(elem)
    {
        //if (!elem) return null;
        if (pf.$type(elem) != "element") throw pf.$exGen('pf.xml.ns(): ' + 'typeof(elem) argument is ' + pf.$type(elem) + ', "element" expected');
        return (elem.namespaceURI || elem.getAttribute('xmlns') || null);
    };

    this.tag = function(elem)
    {
        //if (!elem) return null;
        if (pf.$type(elem) != "element") throw pf.$exGen('pf.xml.tag(): ' + 'typeof(elem) argument is ' + pf.$type(elem) + ', "element" expected');
        return (elem.localName || elem.nodeName || elem.tagName || null);
    };

    this._doc = this.createDocument('dummy');
    if (pf.browsCap.isSafari)
    {
        function _safariFix()
        {
            var _appendChild = Element.prototype.appendChild;
            Element.prototype.appendChild = function(elem)
            {
                if (this.ownerDocument == elem.ownerDocument)
                    return _appendChild.call(this, elem);
                return _appendChild.call(this, this.ownerDocument.adoptNode(elem));
            }
        }
        _safariFix();
    };
};

