/* ***** 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 ***** */

/**
 * scripts.uiscripts.Chat
 *
 *
 */
ML.load("xml/xmldombuilder.js");
ML.load("utils/misc.js");
ML.load("crypto/sha1.js");

function EditorHandler()
{
    this.bundle = getStringBundle("chrome://jim/locale/jim.properties");
}

EditorHandler.prototype =
{
    setEmotsVisibility: function(visible)
    {
        this.output.showEmots = visible;
    },

    sendMessage: function()
    {
        var editor = this.editorElement.getEditor(this.editorElement.contentWindow);
        var html = simplifyHTMLDOM(editor.rootElement);
        var txt = "", i, user;

        if (html.firstChild.firstChildElement) {
            var body = DB.createElement("jaber:client", "body").
                addText(domToTextEx(html));
            
            jabberService.core.messageTag(this.contact, "chat", [html, body], null, this.thread);
        } else
            jabberService.core.message(this.contact, "chat", domToTextEx(html), null, this.thread);

        editor.selectAll();
        editor.deleteSelection(0);

        this.output.add(jabberService.core.iq.auth.user, 
            new Date(), html.firstChild.childNodes, null, this.iconstyle, "this-user");
    },
    
    setSubject: function()
    {
        jabberService.core.message(this.contact, "chat", null,
            document.getElementById("subject").value, this.thread);
        this.subject = document.getElementById("subject").value;
        this.output.add(jabberService.core.iq.auth.user, 
            new Date(), null,
            this.bundle.formatStringFromName(
                "chat.set-subject", [this.subject], 1),
            null, "this-user");
    },

    onLoad: function()
    {
        var _this = this;
        var info;

        this.editorElement = document.getElementById("content-frame");
        this.editorElement.webNavigation.loadURI("about:blank", 0, null, null, null);
        this.editorElement.makeEditable("html", true);
        this.editorElement.addEventListener("keypress", { 
            handleEvent: function (event) { _this.onEditorKeyPress(event); } }, true);

        this.output = document.getElementById("output");

        this.editorElement.commandManager.addCommandObserver(
            {
                observe: function(subject, topic, data)    {
                    if (topic == "cmd_bold")
                        window.updateCommands("style");
                }
            }, "cmd_bold");

        window.contact = this.contact = window.arguments[0];

        this.onPresence();

        var res = jabberService.core.highlevel.users.
            getResourceIDByLongJID(window.arguments[0]);

        if (res)
            res = jabberService.localRDF.getResource(res).
                getTarget("iconstyle-name", JIM_NAMESPACE_URI+"rdf/iconstyles#");

        this.iconstyle = (res && res.value) || 
            jabberService.core.highlevel.iconstyles.defaultstyle;

        if (window.arguments[1])
            this.onMessage(window.arguments[1]);
        else {
            window.thread = this.thread = sha1(
                jabberService.core.uid +
                this.contact +
                dateToISO8601Timestamp(new Date()));
        }

        jabberService.core.addObserver(this);

        document.getElementsByTagName('editor')[0].
            contentWindow.focus()

        this.sendOnEnter = true;
    },

    onUnload: function()
    {
        jabberService.core.removeObserver(this);
    },

    onPresence: function(tag)
    {
        var info = jabberService.core.highlevel.users.getResourceIDByLongJID(this.contact);

        if (info)
            info = jabberService.core.highlevel.users.getInfoByResourceID(info);
        else
            info = jabberService.core.highlevel.users.getInfoByUserID(
                jabberService.core.highlevel.users.getUserIDByLongJID(this.contact));

        window.title = jabberService.core.highlevel.users.
            toLocalizedName("editorTitle", this.contact) +
            " ("+info.showTextual+")";
    },

    onMessage: function(tag)
    {
        var body, user, time, thread, subject, from;

        const NS = "http://www.w3.org/TR/xhtml-basic";

        from = tag.getAttribute("from");
        thread = tag.getElementsByTagNameNS("jabber:client", "thread").item(0);
        subject = tag.getElementsByTagNameNS("jabber:client", "subject").item(0);
        time = tag.getElementsByTagNameNS("jabber:x:delay", "x").item(0);

        if (thread)
            thread = domToText(thread);

        if (thread && !this.thread)
            window.thread = this.thread = thread;

        if ((thread && thread != this.thread) || (!thread && from != this.contact))
            return;

        if (this.contact != from) {
            this.contact = from;
            this.onPresence();
        }

        if (time)
            time = utcStringToDate(time.getAttribute("stamp"));
        else
            time = new Date();

        body = tag.getElementsByTagNameNS(NS, "body").item(0)
        user = jabberService.core.highlevel.users.toLocalizedName("chat", tag.getAttribute("from"));
        
        if (subject)
            subject = domToText(subject);
        
        if (subject && this.subject != subject) {
            this.subject = document.getElementById("subject").value = subject;
            this.output.add(user, time, null,
                this.bundle.formatStringFromName(
                    "chat.set-subject", [this.subject], 1));
        }

        if (body) {
            this.output.add(user, time, 
                simplifyHTMLDOM(body).firstChild.childNodes, null, this.iconstyle, "");
        } else {
            tag = tag.getElementsByTagNameNS("jabber:client", "body").item(0);
            this.output.add(user, time, tag ? tag.firstChild : null, null, this.iconstyle, "");
        }
        window.getAttention();
    },

    onPopupSmile: function()
    {
        var popupdoc = document.getElementById("smile-popup");

        if (!popupdoc.generated) {
            popupdoc.generated = true;
            var txt = "", i;
            var icons = jabberService.core.highlevel.iconstyles.
                getIcons(this.iconstyle);
            var el = document.createElementNS("http://www.w3.org/1999/xhtml", "div");

            txt = "<table><tr>";
            for (i = 0; i < icons.length; i++) {
                if (((i%8) == 0) && i != 0)
                    txt += "</tr><tr>";
                txt += "<td><img src='"+icons[i].graphics[0].url+"' title='"+icons[i].texts[0].text+"'/></td>";
            }
            txt+="</tr></table>"

            el.innerHTML = txt;
            popupdoc.appendChild(el);
        }
    },

    onInsertSmile: function(event)
    {
        var editor = this.editorElement.getEditor(this.editorElement.contentWindow);

        editor instanceof Components.interfaces.nsIHTMLEditor;
        if (!(event.target instanceof HTMLImageElement))
            return true;
        editor.insertHTML(encodeEntity(event.target.getAttribute('title')));

        document.getElementById("smile-popup").hidePopup();
        document.getElementsByTagName('editor')[0].
            contentWindow.focus()
        return false;
    },

    onButtonCommand: function(command, id)
    {
        var controller = top.document.commandDispatcher.getControllerForCommand(command);
        if ( controller && controller.isCommandEnabled(command))
            controller.doCommand(command);
        var node = document.getElementById(id);

        if (node.getAttribute("state") == "false")
            node.setAttribute("state", "true");
        else
            node.setAttribute("state", "false");

        node.checked = node.getAttribute("state") != "false";
    },

    goDoCommand: function(command)
    {
        var controller = top.document.commandDispatcher.getControllerForCommand(command);
        if (controller && controller.isCommandEnabled(command))
            controller.doCommand(command);
    },

    onUpdateCommands: function(commandsTag)
    {
        var commands = commandsTag.getElementsByTagName("command");
        var i;
        var controller, params;

        params = Components.classes["@mozilla.org/embedcomp/command-params;1"].
            createInstance(Components.interfaces.nsICommandParams);

        if (!params)
            return;

        for (i = 0; i < commands.length; i++)
            if (commands[i].hasAttribute("state")) {
                var command = commands[i].getAttribute("id");
                controller = top.document.commandDispatcher.getControllerForCommand(command);

                if (controller instanceof Components.interfaces.nsICommandController) {
                    controller.getCommandStateWithParams(command, params);

                    if (params.getBooleanValue("state_all"))
                        commands[i].setAttribute("state", "true");
                    else
                        commands[i].setAttribute("state", "false");
                }
            }
    },

    onUpdateButton: function(button, command)
    {
        var com = top.document.getElementById(command);

        button.checked = com.getAttribute("state") == "true";
    },
    
    onSubjectKeyPress: function(event)
    {
        if (event.keyCode == KeyEvent.DOM_VK_RETURN) {
            this.setSubject();
            document.getElementsByTagName('editor')[0].
                contentWindow.focus()
        }
    },

    onEditorKeyPress: function(event)
    {
        if (event.keyCode == KeyEvent.DOM_VK_TAB)
            event.preventDefault();
        if (event.keyCode == KeyEvent.DOM_VK_RETURN && !event.shiftKey && this.sendOnEnter) {
            this.sendMessage();
            event.preventBubble();
        }
    }
}

function domToTextEx(dom)
{
    var i, t = ""
    if (dom.nodeType == dom.ELEMENT_NODE) {
        switch (dom.nodeName.toLowerCase()) {
        case "br":
            return "\n";
        default:
            for (i = 0; i < dom.childNodes.length; i++)
                t+=domToTextEx(dom.childNodes[i]);
            return t;
        }
    } else
        return dom.nodeValue;
}


function simplifyHTMLDOM(dom)
{
    const NS = "http://www.w3.org/TR/xhtml-basic";
    var body;

    dom = __simplifyHTMLDOM(dom, DB.createElement(NS, "html"));

    body = dom.firstChild;

    while (body.lastChild)
        if (body.lastChild.nodeName == "br")
            body.removeChild(body.lastChild);
        else
            body = body.lastChild;
    return dom;
}

function __simplifyHTMLDOM(dom, root)
{
    const NS = "http://www.w3.org/TR/xhtml-basic";

    var i, tag, name, style;

    if (dom.nodeType == dom.ELEMENT_NODE) {
        switch (name = dom.nodeName.toLowerCase()) {
        case "img":
            tag = DB.createElement(NS, "img");
            for (i = 0; i < dom.attributes.length; i++)
                if (dom.attributes[i].nodeName in ["align", "alt", "height", "src", "width"])
                    tag.setAttribute(dom.attributes[i].nodeName, dom.attributes[i].nodeValue);
            root.addDOM(tag);
            break;

        case "a":
            tag = DB.createElement(NS, "a");
            for (i = 0; i < dom.attributes.length; i++)
                if (dom.attributes[i].nodeName == "style")
                    tag.setAttribute("style", simplifyStyle(dom.attributes[i].nodeValue));
                else if (dom.attributes[i].nodeName == "href")
                    tag.setAttribute(dom.attributes[i].nodeName, dom.attributes[i].nodeValue);
            root.addDOM(tag);

            for (i = 0; i < dom.childNodes.length; i++)
                __simplifyHTMLDOM(dom.childNodes[i], tag);
            break;

        case "blockquote":
		case "body":
		case "div":
		case "h1":
		case "li":
		case "ol":
		case "p":
		case "pre":
		case "q":
		case "span":
		case "ul":
		case "body":
            tag = DB.createElement(NS, name);
            for (i = 0; i < dom.attributes.length; i++)
                if (dom.attributes[i].nodeName == "style")
                    tag.setAttribute("style", simplifyStyle(dom.attributes[i].nodeValue));
            root.addDOM(tag);

            for (i = 0; i < dom.childNodes.length; i++)
                __simplifyHTMLDOM(dom.childNodes[i], tag);
            break;

        case "u":
            tag = DB.createElement(NS, "span");
            tag.setAttribute("style", "text-decoration: underline;");
            root.addDOM(tag);

            for (i = 0; i < dom.childNodes.length; i++)
                __simplifyHTMLDOM(dom.childNodes[i], tag);
            break;

        case "b":
        case "i":
		case "strong":
		case "br":
		case "cite":
		case "em":
            if (name == "b")
                name = "strong";
            else if (name == "i")
                name = "em";

            tag = DB.createElement(NS, name);
            root.addDOM(tag);

            for (i = 0; i < dom.childNodes.length; i++)
                __simplifyHTMLDOM(dom.childNodes[i], tag);
            break;

        default:
            for (i = 0; i < dom.childNodes.length; i++)
                __simplifyHTMLDOM(dom.childNodes[i], root);
            break;
        }
    } else
        root.addText(dom.nodeValue);
    return root;
}

function simplifyStyle(style)
{
    var stylePairs, stylePair, i, res = "";

    style = style.replace(/^\s+/, "").replace(/(?:\s*;)?\s+$/, "");

    stylePairs =  style.split(/\s*;\s*/);

    for (i = 0; i < stylePairs.length; i++) {
        stylePair = stylePairs[i].split(/\s*:\s*/);

        switch (stylePair[0]) {
        case "color":
        case "font-family":
        case "font-size":
        case "font-style":
        case "font-weight":
        case "text-align":
        case "text-decoration":
            res += stylePair[0]+": "+stylePair[1]+";";
        }
    }
    return res;
}

var editorHandler = new EditorHandler();