// Module ui/save-html
// Saves content to HTML when asked to

define(
    ["jquery", "core/utils"],
    function ($, utils) {
        var msg, doc, conf;
        var cleanup = function (rootEl) {
            $(".removeOnSave", rootEl).remove();
            utils.removeReSpec(rootEl);
        };
        return {
            show:   function (ui, _conf, _doc, _msg) {
                msg = _msg, doc = _doc, conf = _conf;
                if (!conf.diffTool) conf.diffTool = "http://www5.aptest.com/standards/htmldiff/htmldiff.pl";
                var supportsDownload = $("<a href='foo' download='x'>A</a>")[0].download === "x"
                ,   self = this
                ;
                var $div = $("<div></div>")
                ,   buttonCSS = {
                        background:     "#eee"
                    ,   border:         "1px solid #000"
                    ,   borderRadius:   "5px"
                    ,   padding:        "5px"
                    ,   margin:         "5px"
                    ,   display:        "block"
                    ,   width:          "100%"
                    ,   color:          "#000"
                    ,   textDecoration: "none"
                    ,   textAlign:      "center"
                    ,   fontSize:       "inherit"
                    }
                ,   addButton = function (title, content, fileName, popupContent) {
                        if (supportsDownload) {
                            $("<a></a>")
                                .appendTo($div)
                                .text(title)
                                .css(buttonCSS)
                                .attr({
                                    href:   "data:text/html;charset=utf-8," + encodeURIComponent(content)
                                ,   download:   fileName
                                })
                                .click(function () {
                                    ui.closeModal();
                                })
                                ;
                        }
                        else {
                            $("<button></button>")
                                .appendTo($div)
                                .text(title)
                                .css(buttonCSS)
                                .click(function () {
                                    popupContent();
                                    ui.closeModal();
                                })
                                ;
                        }
                        
                    }
                ;
                addButton("Save as HTML", self.toString(), "Overview.html", function () { self.toHTMLSource(); });
                addButton("Save as XHTML5", self.toXML(5), "Overview.xhtml", function () { self.toXHTMLSource(5); });
                addButton("Save as XHTML 1.0", self.toXML(1), "Overview.xhtml", function () { self.toXHTMLSource(1); });
                if (conf.diffTool && (conf.previousDiffURI || conf.previousURI)) {
                    $("<button>Diff</button>")
                        .appendTo($div)
                        .css(buttonCSS)
                        .click(function () {
                            self.toDiffHTML();
                            ui.closeModal();
                        })
                        ;
                }
                ui.freshModal("Save Snapshot", $div);
            }
            // convert the document to a string (HTML)
        ,   toString:    function () {
                respecEvents.pub("save", "toString")
                var str = "<!DOCTYPE html"
                ,   dt = doc.doctype;
                if (dt && dt.publicId) str += " PUBLIC '" + dt.publicId + "' '" + dt.systemId + "'";
                str += ">\n<html";
                var ats = doc.documentElement.attributes;
                for (var i = 0; i < ats.length; i++) {
                    var an = ats[i].name;
                    if (an === "xmlns" || an === "xml:lang") continue;
                    str += " " + an + "=\"" + utils.xmlEscape(ats[i].value) + "\"";
                }
                str += ">\n";
                var rootEl = doc.documentElement.cloneNode(true);
                cleanup(rootEl);
                str += rootEl.innerHTML;
                str += "</html>";
                return str;
            }
            // convert the document to XML, pass 5 as mode for XHTML5
        ,   toXML:        function (mode) {
                respecEvents.pub("save", "toXML" + mode)
                var rootEl = doc.documentElement.cloneNode(true);
                cleanup(rootEl);
                if (mode !== 5) {
                    // not doing xhtml5 so rip out the html5 stuff
                    $.each("section figcaption figure aside".split(" "), function (i, item) {
                        $(item, rootEl).renameElement("div").addClass(item);
                    });
                    $("time", rootEl).renameElement("span").addClass("time").removeAttr('datetime');
                    $("[role]", rootEl).removeAttr('role') ;
                    $("[aria-level]", rootEl).removeAttr('aria-level') ;
                    $("style:not([type])", rootEl).attr("type", "text/css");
                    $("script:not([type])", rootEl).attr("type", "text/javascript");
                }
                var str = "<!DOCTYPE html"
                ,   dt = doc.doctype;
                if (dt && dt.publicId) str += " PUBLIC '" + dt.publicId + "' '" + dt.systemId + "'";
                else if (mode !== 5) {
                    if (conf.doRDFa) {
                        // use the standard RDFa 1.1 doctype
                        str += " PUBLIC '-//W3C//DTD XHTML+RDFa 1.1//EN' 'http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd'";
                    } else {
                        str += " PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'";
                    }
                }
                str += ">\n<html";
                var ats = doc.documentElement.attributes
                ,   hasxmlns = false;
                for (var i = 0; i < ats.length; i++) {
                    var an = ats[i].name;
                    if (an === "xmlns") hasxmlns = true;
                    str += " " + an + "=\"" + utils.xmlEscape(ats[i].value) + "\"";
                }
                if (!hasxmlns) str += ' xmlns="http://www.w3.org/1999/xhtml"';
                str += ">\n";
                // walk the entire DOM tree grabbing nodes and emitting them - possibly modifying them
                // if they need the funny closing tag
                var selfClosing = {};
                "br img input area base basefont col isindex link meta param hr".split(" ").forEach(function (n) {
                    selfClosing[n] = true;
                });
                var noEsc = [false];
                var dumpNode = function (node) {
                    var out = "";
                    // if the node is the document node.. process the children
                    if (node.nodeType === 9 || (node.nodeType === 1 && node.nodeName.toLowerCase() == "html")) {
                        for (var i = 0; i < node.childNodes.length; i++) out += dumpNode(node.childNodes[i]);
                    }
                    // element
                    else if (1 === node.nodeType) {
                        var ename = node.nodeName.toLowerCase() ;
                        out += "<" + ename ;
                        for (var i = 0; i < node.attributes.length; i++) {
                            var atn = node.attributes[i];
                            if (/^\d+$/.test(atn.name)) continue;
                            out += " " + atn.name + "=\"" + utils.xmlEscape(atn.value) + "\"";
                        }
                        if (selfClosing[ename]) out += " />";
                        else {
                            out += ">";
                            noEsc.push(ename === "style" || ename === "script");
                            for (var i = 0; i < node.childNodes.length; i++) out += dumpNode(node.childNodes[i]);
                            noEsc.pop();
                            out += "</" + ename + ">";
                        }
                    }
                    // comments
                    else if (8 === node.nodeType) {
                        out += "\n<!--" + node.nodeValue + "-->\n";
                    }
                    // text or cdata
                    else if (3 === node.nodeType || 4 === node.nodeType) {
                        out += noEsc[noEsc.length - 1] ? node.nodeValue : utils.xmlEscape(node.nodeValue);
                    }
                    // we don't handle other types
                    else {
                        msg.pub("warning", "Cannot handle serialising nodes of type: " + node.nodeType);
                    }
                    return out;
                };
                str += dumpNode(rootEl) + "</html>";
                return str;
            }
            // create a diff marked version against the previousURI
            // strategy - open a window in which there is a form with the
            // data needed for diff marking - submit the form so that the response populates
            // page with the diff marked version
        ,   toDiffHTML:  function () {
                respecEvents.pub("save", "toDiffHTML")
                var base = window.location.href.replace(/\/[^\/]*$/, "/")
                ,   str = "<!DOCTYPE html>\n<html>\n" +
                          "<head><title>Diff form</title></head>\n" +
                          "<body><form name='form' method='POST' action='" + conf.diffTool + "'>\n" +
                          "<input type='hidden' name='base' value='" + base + "'>\n";
                if (conf.previousDiffURI) {
                    str += "<input type='hidden' name='oldfile' value='" + conf.previousDiffURI + "'>\n";
                }
                else {
                    str += "<input type='hidden' name='oldfile' value='" + conf.previousURI + "'>\n";
                }
                str += '<input type="hidden" name="newcontent" value="' + utils.xmlEscape(this.toString()) + '">\n' +
                       '<p>Submitting, please wait...</p>' +
                       "</form></body></html>\n";
                var x = window.open();
                x.document.write(str);
                x.document.close();
                x.document.form.submit();
            },
            // popup the generated HTML content
            // toHTML:    function () {
            //     var x = window.open();
            //     x.document.write(this.toString());
            //     x.document.close();
            // },
            // popup the generated source
            toHTMLSource:    function () {
                var x = window.open();
                x.document.write("<pre>" + utils.xmlEscape(this.toString()) + "</pre>");
                x.document.close();
            },
            // popup the generated XHTML content
            // toXHTML:    function (mode) {
            //     var x = window.open();
            //     x.document.write(this.toXML(mode)) ;
            //     x.document.close();
            // },
            // popup the generated XHTML source
            toXHTMLSource:    function (mode) {
                var x = window.open();
                x.document.write("<pre>" + utils.xmlEscape(this.toXML(mode)) + "</pre>");
                x.document.close();
            }
        };
    }
);