/**
 *
 * XMLParser 
 *
 * Gamboa <gamboa AT_NO_SPAM co.sapo.pt>
 *
 * Depends: prototype.js <http://prototype.conio.net/>
 *
 * Usage: 
 * <script>
 * function doSomething(xml) 
 * {
 *      // if it is a RSS file
 *      alert(xml.rss[0]['channel'][0]['item'].length);
 * }
 *
 * new XMLParser('XMLFile.xml', {onComplete:doSomething});
 * </script>
 *
 */

XMLParser = Class.create();

Object.extend(XMLParser.prototype, 
{
    initialize: function (XMLFile, options) 
    {
        this.xmlFile = XMLFile;
        this.options = options;
        this.element = false;
        this.XMLParsed = false;

        this.getXml();
    },

    XMLHash: function ()
    {
        return this.XMLParsed;
    },
    
    asHash: function () 
    {
        if (! this._xmlHash) {
            this._xmlHash = this._nodeToHash(this.element);
        }
        return this._xmlHash;
    },

    getXml: function ()
    {
        if(this.options.onLoading) {
            this.options.onLoading();
        }
        new Ajax.Request(this.xmlFile, {method:'get', onComplete: this.parseXML.bind(this)});
    },

    parseXML: function (req) 
    {
        this.element = req.responseXML;
        this.XMLParsed = this.asHash();

        if(this.options.onComplete) {
            this.options.onComplete(this.XMLParsed);
        }
    },
    
    _nodeToHash: function (node) 
    {
        Element.cleanWhitespace(node);
        //
        // remove comments, firefox fix
        node = this._removeComments(node);

        if ((node.attributes && node.attributes.length > 0) || (node.hasChildNodes() && (node.childNodes[0].nodeType == 1 || node.childNodes[0].nodeType == 7))) {

            var localHash = {};
            if (node.attributes && node.attributes.length >= 1) {
                $A(node.attributes).each(function (attr) {
                    localHash[attr.nodeName] = [attr.nodeValue]; 
                });
            }
            if (node.hasChildNodes() && (node.childNodes[0].nodeType == 1 || node.childNodes[0].nodeType == 7)) {
                $A(node.childNodes).each(function (node) {
                    this._subNodeToHash(localHash, node); 
                }.bindAsEventListener(this));
            }
            else if (node.hasChildNodes()) {
                localHash['text'] = [this._nodeAsText(node)];
            }
            $H(localHash).each( function (pair) { 
                if (pair[1].length == 1 && typeof pair[1][0] == 'string') { 
                    localHash[pair[0]] = pair[1][0]; 
                } 
            });
            return localHash;
        } else {
            return this._nodeAsText(node);
        }
    },

    _removeComments: function(node) 
    {
        for(var i=0; i < node.childNodes.length; i++) {
            var nodeTmp = node.childNodes[i];
            if(nodeTmp.nodeType == 8) {
                Element.remove(nodeTmp);
            }
        }
        return node;
    },

    _subNodeToHash: function (hash, node) 
    {
        var key = node.tagName;
        if (hash[key]) {
            hash[key].push(this._nodeToHash(node));
        } else {
            hash[key] = [ this._nodeToHash(node) ];
        }
    },

    _nodeAsText: function (node) 
    {
        return node.textContent || node.innerText || node.text || node.childNodes[0].nodeValue || '';
    }
} 
);


