/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is JIM.
 *
 * The Initial Developer of the Original Code is
 * Pawel Chmielowski <prefiks@o2.pl>
 *
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Pawel Chmielowski <prefiks@o2.pl>
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * xml.XMLDOMParser
 *
 *
 */
ML.load("xml/xmlparser.js");
ML.load("xml/xmldomutils.js");
ML.load("xml/xmldombuilder.js");

function XMLDOMParser()
{
    this.parser = new XMLParser();
    this.parser.addObserver(this);
    
    this.currNode = document.implementation.createDocument(null, null, null);
    this.DB = new XMLDOMBuilder(this.currNode);

    this.currNode.__processChild = this.processChild = true;
    this.currNode.__namespaceURIs = this.namespaceURIs = {};
    this.nameSpaces = [];
    this.processingMode = [];
}

XMLDOMParser.prototype =
{
    setHandler: function(handler)
    {
        this.handler = handler;
    },

    reset: function()
    {
        this.nameSpaces = [];
        this.processingMode = [];
        this.namespaceURIs = {};
        this.processChild = true;
        this.parser.reset();

        while (this.DB.doc.hasChildNodes())
            this.DB.doc.removeChild(this.DB.doc.firstChild);
        this.currNode = this.DB.doc;

        if (this.handler.onReset)
            this.handler.onReset();
    },

    parse: function(string)
    {
        if (this.handler == null)
            throw "XMLDOMParser:No handler";

        this.parser.parse(string);
    },

    parseFully: function(string)
    {
        var v, i;
        var dp = new DOMParser();
        string = this.parser.convertToUnicodeSpec(string);

        v = dp.parseFromString(string, "text/xml").firstChild;
        while (v && v.nodeType != v.ELEMENT_NODE)
            v = v.nextSibling;

        return v;
    },

    parseFullyString: function(string)
    {
        var v, i;
        var dp = new DOMParser();

        v = dp.parseFromString(string, "text/xml").firstChild;
        while (v && v.nodeType != v.ELEMENT_NODE)
            v = v.nextSibling;

        return v;
    },

    onStartDocument: function(data)
    {
        while (this.DB.doc.hasChildNodes())
            this.DB.doc.removeChild(this.DB.doc.firstChild);
        this.currNode = this.DB.doc;

        this.namespaceURIs = {};
        this.tags = [];
    },

    onEndDocument: function(data)
    {
    },

    onStartTag: function(tn, attribs)
    {
        var data, ns, tag, i, j, mode, oldNS;

        for (i in attribs) {
            if ((data = i.match(/^xmlns(?::(.*))?$/)) && this.namespaceURIs[data[1]] != attribs[i]) {
                if (!oldNS) {
                    oldNS = this.namespaceURIs;
                    this.namespaceURIs = {}
                    for (j in oldNS)
                        this.namespaceURIs[j] = oldNS[j];
                }
                this.namespaceURIs[data[1] || ""] = attribs[i];
            }
        }

        data = tn.match(/^([^:]*):/);
        ns = this.namespaceURIs[data ? data[1] : ""];

        tag = this.DB.createElement(ns, tn);
        tag.__namespaceURIs = oldNS || this.namespaceURIs;

        this.nameSpaces.push(oldNS || this.namespaceURIs);

        for (i in attribs)
            if (i.search(/^xmlns(?:$|:)/) >= 0)
                tag.setAttributeNS("http://www.w3.org/2000/xmlns/", i, attribs[i]);
            else
                tag.setAttribute(i, attribs[i]);

        this.currNode.addDOM = Element.prototype.addDOM;

        if (this.currNode.nodeType == this.currNode.ELEMENT_NODE)
            this.currNode.addDOM(tag);
        else
            this.currNode.appendChild(tag);

        this.processingMode.push(this.processChild);

        if (this.processChild) {
            this.processChild = tag.__processChild = !this.handler.onStartTag(tag);
        }

        this.currNode = tag;
    },

    onEndTag: function(tn)
    {
        var v = this.currNode;
        var currPC = this.processChild;
        this.processChild = this.processingMode.pop();

        this.currNode = v.parentNode;
        this.namespaceURIs = this.nameSpaces.pop();

        if (currPC) {
            if (this.handler.onEndTag)
                this.handler.onEndTag(v);
            this.currNode.removeChild(v);
        } else if (this.processChild) {
            if (this.handler.onCompleteTag)
                this.handler.onCompleteTag(v);
            this.currNode.removeChild(v);
        }
    },

    onData: function(data)
    {
        this.currNode.appendChild(this.DB.createText(data));
    },
}