/*meta*/

Node = function(tag, style, attribs, children) {
    this.nodeName = tag;
    this.style = {};
    if (style) for (var i in style) this.style[i] = style[i];
    this.attribs = attribs || {};
    this.childNodes = children || [];
};

Node.dontClose = { area: 1, base: 1, basefont: 1, br: 1, col: 1, frame: 1,
    hr: 1, img: 1, input: 1, isindex: 1, link: 1, meta: 1, param: 1 };

Node.styles = { flt: "float" };

Node.prototype = {
/*meta*/
    var attribs = { abbr: 0, acceptCharset: "accept-charset", accept: 0,
        accessKey: 0, action: 0, align: 0, alt: 0, archive: 0, axis: 0,
        border: 0, cellPadding: 0, cellSpacing: 0, ch: "char", chOff: "charoff",
        charset: 0, checked: 0, cite: 0, className: "class", classid: 0,
        codeBase: 0, codeType: 0, cols: 0, colSpan: 0, content: 0, coords: 0,
        data: 0, dateTime: 0, declare: 0, defer: 0, dir: 0, disabled: 0,
        enctype: 0, htmlFor: "for", frame: 0, frameBorder: 0, headers: 0,
        height: 0, href: 0, hreflang: 0, httpEquiv: "http-equiv", id: 0,
        isMap: 0, label: 0, lang: 0, longDesc: 0, marginHeight: 0,
        marginWidth: 0, maxLength: 0, media: 0, method: 0, multiple: 0, name: 0,
        noHref: 0, noResize: 0, profile: 0, readOnly: 0, rel: 0, rev: 0,
        rows: 0, rowSpan: 0,    rules: 0, scheme: 0, scope: 0, scrolling: 0,
        selected: 0, shape: 0, size: 0, span: 0, src: 0, standby: 0, summary: 0,
        tabIndex: 0, target: 0, title: 0, type: 0, useMap: 0, vAlign: 0,
        value: 0, valueType: 0, width: 0 };
    var result = [];
    for (var i in attribs) {
        var attrib = attribs[i] || i.toLowerCase();
        result.push(format(/*src*/
            get %1$s() { return this.attribs["%2$s"]; },
            set %1$s(value) { this.attribs["%2$s"] = value; },
        /*end*/, i, attrib));
    }
    return result.join("");
/*end*/
    writeHTML: function(w, indent) {
        if (indent != undefined) w.write(indent);
        w.write("<" + this.nodeName);
        if (this.style) {
            var hasStyle = false;
            for (var i in this.style) {
                if (!hasStyle) {
                    w.write(" style=\"");
                    hasStyle = true;
                }
                var styleName = i in Node.styles ? Node.styles[i]
                    : i.replace(/[A-Z]/g, function(c) {
                        return "-" + String.fromCharCode(c.charCodeAt(0) + 32);
                    });
                w.write(format("%s:%s;", styleName, this.style[i]));
            }
            if (hasStyle) w.write("\"");
        }
        if (this.attribs) for (var i in this.attribs) {
            w.write(format(" %s=\"%s\"", i, escapeHTML(this.attribs[i])));
        }
        if (indent == undefined) w.write(">"); else w.writeln(">");
        for (var i = 0; i < this.childNodes.length; i++) {
            this.childNodes[i].writeHTML(w, indent == undefined ? undefined
                                                                : indent + " ");
        }
        if (!(this.nodeName in Node.dontClose)) {
            var endtag = format("</%s>", this.nodeName);
            if (indent == undefined) {
                w.writeln(endtag);
            } else {
                w.write(indent);
                w.writeln(endtag);
            }
        }
    },
    cloneNode: function(recursive) {
        var children = [];
        if (recursive) {
            for (var i = 0; i < this.childNodes.length; i++) {
                children.push(this.childNodes[i].cloneNode(true));
            }
        }
        return newnode(this.nodeName, this.style, this.attribs, children);
    },
    appendChild: function(node) { this.childNodes.push(node); },
    get firstChild() { return this.childNodes[0]; }
};

newnode = function(tag, style, attribs, children) {
    return new Node(tag, style, attribs, children);
};

TextNode = function(text) {
    this.data = text;
};

TextNode.prototype = {
    writeHTML: function(w, indent) {
        var text = escapeHTML(this.data);
        if (indent == undefined) {
            w.write(text);
        } else {
            w.write(indent);
            w.writeln(text);
        }
    },
    cloneNode: function(recursive) { return newtext(this.data); }
};

newtext = function(text) { return new TextNode(text); }

Module = function(name, prefix, suffix) {
    this.name = name;
    this.prefix = prefix;
    this.suffix = suffix;
    this.js = new Writer(format("%s/%s.js", args.dest, name));
    this.templateNode = newnode("div", { display: "none" });
    this.templates = this.templateNode.childNodes;
};

Module.prototype = {
    addTemplate: function(node) {
        this.templateNode.appendChild(node);
        return format("meta.templates[%d]", this.templates.length - 1);
    },
    close: function() {
        if (this.prefix || this.suffix || this.body) {
            this.html = new Writer(format("%s/%s.html", args.dest, this.name));
            this.html.write(this.prefix || "");
            this.body.getNode().writeHTML(this.html);
            this.html.write(format(/*src*/
                <script type="text/javascript" src="%s.js"></script>
            /*end*/, this.name));
            this.templateNode.writeHTML(this.html);
            this.html.write(this.suffix || "");
            this.html.close();
        }
        this.js.close();
    }
};

buildModule = function(name, prefix, suffix) {
    var module = new Module(name, prefix, suffix);
    module.js.write(process(name, module));
    module.close();
};

/*end*/