/**
 * @module parse
 * @desc A parser used for testing.
 * @author Louis-Dominique Dubeau
 * @license MPL 2.0
 * @copyright 2013, 2014 Mangalam Research Center for Buddhist Languages
 */

define(/** @lends module:parse */ function (require, exports, module) {
'use strict';
var validate = require("./validate");
var sax = require("sax");
var parser = sax.parser(true, {xmlns: true});

function parse(rng_source, xml_source, mute) {
    mute = !!mute;

    var tree = validate.constructTree(rng_source);

    var walker = tree.newWalker();

    var error = false;

    function fireEvent() {
        var ev = new validate.Event(Array.prototype.slice.call(arguments));
        var ret = walker.fireEvent(ev);
        if (ret) {
            error = true;
            if (!mute)
                ret.forEach(function (x) {
                    console.log("on event " + ev);
                    console.log(x.toString());
                });
        }
    }

    var tag_stack = [];
    var text_buf = "";

    function flushTextBuf() {
        fireEvent("text", text_buf);
        text_buf = "";
    }


    parser.onopentag = function (node) {
        flushTextBuf();
        var names = Object.keys(node.attributes);
        var ns_definitions = [];
        names.sort();
        names.forEach(function (name) {
            var attr = node.attributes[name];
            if (attr.local === "" && name === "xmlns")// xmlns="..."
                ns_definitions.push(["", attr.value]);
            else if (attr.prefix === "xmlns") // xmlns:...=...
                ns_definitions.push([attr.local, attr.value]);
        });
        if (ns_definitions.length) {
            fireEvent("enterContext");
            ns_definitions.forEach(function (x) {
                fireEvent("definePrefix", x[0], x[1]);
            });
        }
        fireEvent("enterStartTag", node.uri, node.local);
        names.forEach(function (name) {
            var attr = node.attributes[name];
            // The parser handles all namespace issues
            if ((attr.local === "" && name === "xmlns") || // xmlns="..."
                (attr.prefix === "xmlns")) // xmlns:...=...
                return;
            fireEvent("attributeName", attr.uri, attr.local);
            fireEvent("attributeValue", attr.value);
        });
        fireEvent("leaveStartTag");
        tag_stack.unshift([node.uri, node.local, ns_definitions.length]);
    };

    parser.ontext = function (text) {
        text_buf += text;
    };

    parser.onclosetag = function (node) {
        flushTextBuf();
        var tag_info = tag_stack.shift();
        fireEvent("endTag", tag_info[0], tag_info[1]);
        if (tag_info[2])
            fireEvent("leaveContext");
    };

    parser.write(xml_source).close();
    return error;
}

module.exports = parse;

});

// LocalWords:  namespace xmlns attributeName attributeValue endTag
// LocalWords:  leaveStartTag enterStartTag amd utf fs LocalWords

@@ -2719,32 +2719,1316 @@
 text%22);%0A    %7D;%0A%0A
+    var entity_re = /%5E%3C!ENTITY%5Cs+(%5B%5E%5Cs%5D+)%5Cs+(%5B'%22%5D)(.*?)%5C2%5Cs*%3E%5Cs*/;%0A%0A    parser.ondoctype = function (doctype) %7B%0A        // This is an extremely primitive way to handle ENTITY%0A        // declarations in a DOCTYPE. It is unlikely to support any%0A        // kind of complicated construct. If a reminder need be given%0A        // then: THIS PARSER IS NOT MEANT TO BE A GENERAL SOLUTION TO%0A        // PARSING XML FILES!!! It supports just enough to perform%0A        // some testing.%0A        doctype = doctype%0A            .replace(/%5E.*?%5C%5B/, '')%0A            .replace(/%5C%5D.*?$/, '')%0A            .replace(/%3C!--(?:.%7C%5Cn%7C%5Cr)*?--%3E/g, '')%0A            .trim();%0A%0A        var in_entity = false;%0A%0A        while (doctype.length) %7B%0A            var match = entity_re.exec(doctype);%0A            if (match) %7B%0A                var name = match%5B1%5D;%0A                var quote = match%5B2%5D;%0A                var value = match%5B3%5D;%0A                doctype = doctype.slice(match%5B0%5D.length);%0A                if (parser.ENTITIES%5Bname%5D !== undefined)%0A                    throw new Error(%22redefining entity: %22 + name);%0A                parser.ENTITIES%5Bname%5D = value;%0A            %7D%0A            else%0A                throw new Error(%22unexpected construct in DOCTYPE: %22 + doctype);%0A        %7D%0A%0A        console.log(doctype);%0A    %7D;%0A%0A
     parser.write

Support for ENTITY declarations.