/**
 * 
 * All content on this website (including text, images, source
 * code and any other original works), unless otherwise noted,
 * is licensed under a Creative Commons License.
 * 
 * http://creativecommons.org/licenses/by-nc-sa/2.5/
 * 
 * Copyright (C) 2004-2011 Open-Xchange, Inc.
 * Mail: info@open-xchange.com 
 * 
 * @author Matthias Biggeleben <matthias.biggeleben@open-xchange.com>
 * 
 */

/*jslint bitwise: false, nomen: false, onevar: false, plusplus: false, regexp: false, 
white: false, browser: true, devel: true, evil: true, forin: true, undef: true, 
eqeqeq: true, immed: true */

/*global jQuery, ox, formatDate, AjaxRoot, session, window, Join, registerView, newfrag,
triggerEvent, menulastviews, config, internalCache, _, ngettext */

// Mail thread view

(function ($) {
    
    "use strict";
    
    // get mail stylesheet
    var mailStylesheet = "";
    $.get(ox.gui.themePath + "css/iframe.css", function (data) {
        // store css
        mailStylesheet = data;
    });
    
    /**
     * "global" vars
     */
    
    // dom nodes
    var dom = {};
    // thread meta data
    var threads = {};
    // mails IDs
    var mailIDs = [];
    // address hash
    var addresses = {};
    // map addresses to contact id
    var addressMap = {};
    // constants
    var MINUTE = 60 * 1000, HOUR = MINUTE * 60, DAY = HOUR * 24, WEEK = DAY * 7;
    // current folder
    var currentFolder;
    // current view
    var currentView = "thread";
    
    /**
     * Functions
     */
    var getAllMails, getSubset, searchContacts, drawContacts, getTime;
    var serializeAddresses, removeAddress, createButton;
    var fnOpenMail, fnCloseMail, drawDetailMail, hideDetailMail;
    var collapseThread, expandThread, drawMail, drawMails, sendMail;
    var repaint, paint, showQuickReply, hideQuickReply, setEditMode;
    var showContactDetails;
    
    /**
     * Create button
     */
    createButton = function (options) {
        
        // options
        var opt = $.extend({
            title: "",
            click: $.noop,
            data: {}
        }, options || {});
        
        // css
        var css = {
            fontSize: "10px",
            borderRadius: "5px",
            backgroundColor: "#f5f5f5",
            border: "1px solid #ccc",
            cursor: "pointer",
            color: "black",
            lineHeight: "10px",
            padding: "5px 1em 5px 1em",
            whiteSpace: "nowrap",
            display: "inline-block"
        };
        
        var cssOver = {
            borderColor: "#888"
        };
        
        var cssOut = {
            borderColor: "#ccc"
        };
        
        if (ox.browser.Gecko) {
            css.MozBorderRadius = "5px";
            css.backgroundImage = "-moz-linear-gradient(center top, #ffffff, #efefef)";
            cssOver.MozBoxShadow = "0px 0px 4px #aaa";
            cssOut.MozBoxShadow = "none";
        } else if (ox.browser.WebKit) {
            css.webkitBorderRadius = "5px";
            css.backgroundImage = "-webkit-gradient(linear, 0% 0%, 0% 100%, from(white), to(#EFEFEF))";
            cssOver.webkitBoxShadow = "0px 0px 4px #aaa";
            cssOut.webkitBoxShadow = "none";
        }
        
        // create button
        return $("<button/>").text(
            opt.title
        ).bind(
            "click", opt.data, opt.click
        ).css(
            css
        ).hover(
            function () { $(this).css(cssOver); },
            function () { $(this).css(cssOut); }
        );
    };
    
    /**
     * Mail template
     */
    
    // cell indexes
    var PORTRAIT = 0, FROM = 1, DATE = 2, SUBJECT = 3, BUTTON = 4;
    var TO = 5, CC = 6, ATTACHMENTS = 7, CONTACT = 8, REPLY = 9, IFRAME = 10;
    
    var getCells = function (node) {
        return node.find("tbody").first().children().children();
    };
    
    // template
    var mailTemplate = (function () {
        
        var tbody = $("<tbody/>").append(
            $("<tr/>").append(
                $("<td/>", {
                    rowSpan: "6"
                }).css({
                    verticalAlign: "top"
                }).append(
                    $("<img/>", {
                        src: ox.gui.themePath + "img/dummy.gif",
                        alt: ""
                    }).css({
                        display: "none",
                        width: "70px",
                        margin: "4px 14px 10px 0px",
                        border: "1px solid #fff"
                    })
                ).append(
                    $("<img/>", {
                        src: ox.gui.themePath + "img/dummy.gif",
                        alt: ""
                    }).css({
                        display: "none",
                        width: "86px",
                        height: "1px"
                    })
                )
            ).append(
                // from
                $("<td/>").css({
                    fontWeight: "normal"
                })
            ).append(
                // received timestamp
                $("<td/>").css({
                    width: "300px",
                    verticalAlign: "middle",
                    color: "#888",
                    textAlign: "right",
                    whiteSpace: "nowrap"
                }).text("")
            )
        ).append(
            $("<tr/>").append(
                // subject
                $("<td/>").css({
                    verticalAlign: "middle",
                    width: "100%"
                }).text("")
            ).append(
                // quick reply button
                $("<td/>", { rowSpan: 2 }).css({
                    verticalAlign: "middle",
                    textAlign: "right",
                    whiteSpace: "nowrap",
                    padding: "5px 0px 5px 5px"
                })
            )
        ).append(
            $("<tr/>").append(
                // to
                $("<td/>", { colSpan: "1" })
            ).css("display", "none")
        ).append(
            $("<tr/>").append(
                // cc
                $("<td/>", { colSpan: "2" })
            ).css("display", "none")
        ).append(
            $("<tr/>").append(
                // attachments
                $("<td/>", { colSpan: "2" }).css("paddingTop", "0.5em")
            ).css("display", "none")
        ).append(
            $("<tr/>").append(
                // contact preview
                $("<td/>", { colSpan: "2" }).css({
                    padding: "10px 0px 0px 0px"
                })
            ).css("display", "none")
        ).append(
            $("<tr/>").append(
                // quick reply
                $("<td/>", { colSpan: "2" }).css({
                    padding: "10px 0px 0px 0px"
                })
            ).css("display", "none")
        ).append(
            $("<tr/>").append(
                // mail content
                $("<td/>", { colSpan: "2" })
            ).css("display", "none")
        );
            
        return $("<div/>").css({
            position: "relative",
            border: "1px solid #bbb",
            backgroundColor: "white",
            padding: "5px 20px 5px 10px",
            MozBorderRadius: "10px",
            webkitBorderRadius: "10px",
            borderRadius: "10px",
            margin: "2px 5px 0px 10px",
            marginLeft: "10px",
            cursor: "pointer"
        }).append(
            // flag
            $("<div/>").addClass("ox-mail-flag").css({
                position: "absolute",
                top: "0px",
                right: "0px",
                bottom: "0px",
                width: "9px",
                borderLeft: "1px solid #ccc",
                MozBorderRadius: "0px 10px 10px 0px",
                webkitBorderRadius: "0px 10px 10px 0px",
                borderRadius: "0px 10px 10px 0px",
                backgroundColor: "#efefef"
            })
        ).append(
            // table
            $("<table/>", {
                border: "0",
                cellPadding: "0",
                cellSpacing: "0"
            }).css({
                width: "100%",
                fontSize: "9pt",
                lineHeight: "12pt"
            }).append(
                tbody
            )
        );
        
    }());
    
    /**
     * Get all mails in given folder
     */
    getAllMails = function (folder, cont) {
        // get "all"
        ox.api.mail.all(folder, {
            params: {
                columns: "600,601,611",
                sort: "thread"
            },
            success: function (data) {
                cont(data);
            }
        });
    };
    
    // get subset
    getSubset = function (offset) {
        var num = currentView !== "unread" ? offset + 100 : Infinity;
        var max = Math.max(0, mailIDs.length - offset);
        var i = offset, $i = Math.min(max, num), mail, tmp = [];
        for (; i < $i; i++) {
            mail = mailIDs[i];
            tmp.push({ folder: mail.folder_id, id: mail.id });
        }
        return tmp;
    };
    
    /**
     * Draw contact details
     */
    
    var contactFields = {
        email1: "E-Mail",
        email2: "E-Mail",
        email3: "E-Mail",
        telephone_business1: "Phone (business)",
        telephone_business2: "Phone (business)",
        fax_business: "Fax (business)",
        telephone_home1: "Phone (private)",
        telephone_home2: "Phone (private)",
        cellular_telephone1: "Mobile",
        cellular_telephone2: "Mobile",
        instant_messenger1: "IM (business)",
        instant_messenger2: "IM (private)",
        note: "Note"
    };
    var contactCallTo = {
        telephone_business1: true,
        telephone_business2: true,
        telephone_home1: true,
        telephone_home2: true,
        cellular_telephone1: true,
        cellular_telephone2: true
    };
    
    var drawContactDetails = function (node, contact, e) {
        
        var inset = "20px", shadow = "0px 0px 25px black";
        
        // create underlay
        var underlay = $("<div/>").css({
            position: "absolute",
            top: "0px",
            left: "0px",
            right: "0px",
            bottom: "0px",
            zIndex: 65000,
            opacity: 0.01,
            backgroundColor: "white"
        });
        
        // create container
        var container = $("<div/>").css({
            position: "absolute",
            top: "0px",
            left: "0px",
            width: "500px",
            height: "250px",
            backgroundColor: "white",
            border: "5px solid #111",
            MozBorderRadius: inset,
            webkitBorderRadius: inset,
            borderRadius: inset,
            MozBoxShadow: shadow,
            webkitBoxShadow: shadow,
            boxShadow: shadow,
            zIndex: 65001
        }).append(
            $("<div/>").css({
                position: "absolute",
                top: "10px",
                right: "10px",
                bottom: "10px",
                left: "10px",
                overflow: "auto"
            })
        );
        
        // vars
        var table, tbody, row, nodes;
        
        // hide
        var fnHide = function () {
            // remove from DOM
            container.remove();
            underlay.remove();
            // prevent leaks
            underlay = container = table = tbody = row = nodes = fnHide = null;
            return false;
        };
        $(underlay).bind("click", fnHide);
        $(container).bind("click", function () { return false; });
        
        // create table
        table = $("<table/>", {
            border: "0",
            cellPadding: "0",
            cellSpacing: "0"
        }).css({
            width: "100%"
        }).append(
            tbody = $("<tbody/>")
        );
        
        // row template
        var template = $("<tr/>").append(
            $("<td/>").css({
                fontSize: "8pt",
                lineHeight: "12pt",
                color: "#555",
                verticalAlign: "top",
                textAlign: "right",
                padding: "0px 20px 10px 0px",
                width: "100px",
                whiteSpace: "nowrap"
            })
        ).append(
            $("<td/>").css({
                fontSize: "10pt",
                lineHeight: "12pt",
                fontWeight: "bold",
                padding: "0px 0px 10px 0px",
                color: "black",
                verticalAlign: "top",
                width: "90%"
            })
        );
        
        // add headline
        row = template.clone();
        nodes = row.children();
        if (contact.image1_url) {
            nodes.eq(0).append(
                $("<img/>", {
                    src: contact.image1_url,
                    alt: ""
                }).css({
                    height: "80px",
                    margin: "0px 0px 10px 0px"
                })
            );
        }
        // alignment
        nodes.css({
            verticalAlign: "top"
        });
        // button
        nodes.eq(1).append(
            createButton({
                title: "Close",
                click: fnHide
            }).css({
                "float": "right",
                margin: "0px 10px 0px 20px"
            })
        );
        // display name
        nodes.eq(1).append(
            $("<div/>").css({
                fontSize: "12pt",
                lineHeight: "18pt"
            }).text("" + contact.display_name)
        );
        // template
        var headTemplate = $("<div/>").css({
            color: "#555",
            fontSize: "9pt",
            lineHeight: "12pt",
            fontWeight: "normal"
        });
        // position
        if (contact.position) {
            nodes.eq(1).append(
                headTemplate.clone().text(contact.position)
            );
        }
        // department
        if (contact.department) {
            nodes.eq(1).append(
                headTemplate.clone().text(contact.department)
            );
        }
        // company
        if (contact.company) {
            nodes.eq(1).append(
                headTemplate.clone().text(contact.company)
            );
        }

        // add to table body
        row.appendTo(tbody);
        
        // loop fields
        var keys = ox.util.keys(contactFields), i = 0, $i = keys.length, field;
        for (; i < $i; i++) {
            field = keys[i];
            if (contact[field]) {
                // add row
                row = template.clone();
                nodes = row.children();
                nodes.eq(0).text("" + _(contactFields[field]));
                if (contactCallTo[field] !== undefined) {
                    nodes.eq(1).append(
                        $("<a/>", {
                            href: "callto://" + contact[field]
                        }).text("" + contact[field])
                    );
                } else {
                    nodes.eq(1).text("" + contact[field]);
                }
                row.appendTo(tbody);
            }
        }
        
        var drawAddress = function (type, street, code, city, state, country) {
            // add row
            row = template.clone();
            nodes = row.children();
            nodes.eq(0).text("" + _(type));
            var td = nodes.eq(1);
            var tmpl = $("<div/>");
            if (street) {
                td.append(
                    tmpl.clone().text(street)
                );
            }
            if (city) {
                td.append(
                    tmpl.clone().text(
                        (code ? code + " " : "") + city + (state ? ", " + state : "")
                    )
                );
            }
            if (country) {
                td.append(
                    tmpl.clone().text(country)
                );
            }
            row.appendTo(tbody);
        };
        
        if (contact.street_business || contact.city_business) {
            drawAddress(
                "Address (business)", contact.street_business, contact.postal_code_business,
                contact.city_business, contact.state_business, contact.country_business
            );
        }
        if (contact.street_home || contact.city_home) {
            drawAddress(
                "Address (private)", contact.street_home, contact.postal_code_home,
                contact.city_home, contact.state_home, contact.country_home
            );
        }
        
        // show
        container.children().first().append(table);
        container.appendTo(document.body);
        underlay.appendTo(document.body);
        
        // set position
        var dh = $(document).height(), ch = container.outerHeight(), y = e.pageY;
        container.css({
            top: (ch + y + 10 >= dh ? dh - ch - 10 : y) + "px",
            left: e.pageX + "px"
        });
    };
    
    /**
     * Show contact details
     */
    showContactDetails = function (node) {
        
        return function (address, e) {
            // search contact
            searchContacts([address], function (data) {
                // found?
                if (data.map[address]) {
                    // get contact
                    var key = data.map[address].key, contact = data.contacts[key];
                    drawContactDetails(node, contact, e);
                }
            });
        };
    };
    
    /**
     * Draw contacts
     */
    drawContacts = function (list, fn) {
        
        // create empty jquery selection
        var node = $();
        
        // loop
        var i = 0, $i = list.length, contact, address, span;
        var fnClick = function (e) {
            fn(e.data, e);
            return false;
        };
        for (; i < $i; i++) {
            contact = list[i];
            address = (contact[1] || "").toLowerCase();
            // has name?
            if (contact[0] !== null) {
                span = $("<span/>", {
                    title: address
                }).css({
                    color: "#566687",
                    whiteSpace: "nowrap"
                }).text(
                    contact[0].replace(/\\?"|'/g, "")
                );
                // add to address hash
                addresses[address] = true;
            } else {
                span = $("<span/>").css({
                   color: "#555",
                   whiteSpace: "nowrap"
               }).text(contact[1] || "");
            }
            // bind click
            span.bind("click", address, fnClick);
            // add to selection
            node = node.add(span);
            // add space?
            if (i < $i - 1) {
                node = node.add(
                    $("<span/>").css({
                        whiteSpace: "nowrap"
                    }).text("; ")
                );
            }
        }
        return node;
    };
    
    // format timestamp
    getTime = function (timestamp) {
        var now = new Date();
        var zone = now.getTimezoneOffset();
        var time = now.getTime() - zone * 60 * 1000;
        var delta = time - timestamp;
        var n;
        if (delta < HOUR) {
            n = Math.ceil(delta / MINUTE);
            return n + ngettext(" minute ago", " minutes ago", n);
        } else if (delta < DAY) {
            n = Math.ceil(delta / HOUR);
            return n + ngettext(" hour ago", " hours ago", n);
        } else if (delta < WEEK) {
            n = Math.ceil(delta / DAY);
            return n + ngettext(" day ago", " days ago", n);
        } else {
            return formatDate(timestamp, "dateshortday") + " " + formatDate(timestamp, "time") + "h";
        }
    };
    
    /**
     * serializeAddresses
     */
    serializeAddresses = function (list) {
        // loop
        var i = 0, $i = list.length, tmp = [], a, name, email;
        for (; i < $i; i++) {
            a = list[i]; name = a[0]; email = a[1].toLowerCase();
            // add
            tmp.push(
                name ? '"' + name.replace(/\\?"|'/g, "") + '" <' + email + '>' : email
            );
        }
        return tmp.join(", ");
    };
    
    removeAddress = function (list, address) {
        // lowercase
        address = address.toLowerCase();
        // loop
        var i = 0, $i = list.length, tmp = [], a, email;
        for (; i < $i; i++) {
            a = list[i]; email = a[1].toLowerCase();
            // add?
            if (email !== address) {
                tmp.push(a);
            }
        }
        return tmp;
    };
    
    /**
     * Send mail
     */
    sendMail = function (node, content, mail) {
        
        // disable form
        node.find("input, button, textarea").attr("disabled", "disabled");
        
        // get user data
        var id = config.identifier, name = "", address = "";
        internalCache.getUsers([id], function (data) {
            
            // get name & address
            name = data[id].display_name;
            address = config.mail.defaultaddress;
            
            // from
            var from = serializeAddresses([[name, address]]);
            
            // to
            var to = serializeAddresses(mail.from.concat(removeAddress(mail.to, address)));
            var cc = serializeAddresses(removeAddress(mail.cc, address));
            
            var iframe, form;
            
            // send mail
            window.callback_new = function (data) {
                // notify
                ox.UINotifier.ok("Your reply has been sent");
                // remove form
                form.remove(); form = null;
                // remove iframe
                iframe.remove(); iframe = null;
                // remove handler
                delete window.callback_new;
                // hide editor
                hideQuickReply({ data: { node: node, mail: mail } });
            };
            
            iframe = $("<iframe/>", {
                name: "sendmail"
            }).css({
                display: "none"
            }).appendTo(document.body);
            
            form = $("<form/>", {
                method: "post",
                action: AjaxRoot + "/mail?action=new&session=" + session,
                enctype: "multipart/form-data",
                target: "sendmail"
            }).css({
                display: "none"
            }).append(
                $("<input/>", {
                    type: "hidden",
                    name: "json_0",
                    value: JSON.serialize({
                        from: from,
                        to: to,
                        cc: cc,
                        bcc: "",
                        subject: "Re: " + mail.subject,
                        msgref: mail.folder_id + "/" + mail.id,
                        attachments: [{
                            content_type: "text/plain",
                            content: content
                        }],
                        sendtype: 1
                    })
                })
            ).appendTo(document.body).submit();
        });
    };
    
    /**
     * Hide quick reply
     */
    hideQuickReply = function (e) {
        
        // get data
        var data = e.data;
        var node = data.node;
        var mail = data.mail;
        var cells = getCells(node);
        
        // hide editor
        cells.eq(REPLY).empty().parent().hide();
        
        // show reply button
        cells.eq(BUTTON).empty().append(
            createButton({
                title: "Quick reply",
                click: showQuickReply,
                data: { node: node, mail: mail }
            })
        );
        
        // disable edit mode
        setEditMode(node, false);
    };
    
    /**
     * Show quick reply
     */
    showQuickReply = function (e) {
        
        // get data
        var data = e.data;
        var node = data.node;
        var mail = data.mail;
        var cell = getCells(node).eq(REPLY);
        var area;
        
        // enable edit mode
        setEditMode(node, true);
        
        // add
        cell.append(
            area = $("<textarea/>").css({
                fontSize: "9pt",
                lineHeight: "12pt",
                fontFamily: "monospace, Courier New",
                width: "600px",
                height: "200px",
                border: "1px solid #aaa",
                padding: "5px"
            })
        ).append(
            $("<br/>")
        ).append(
            createButton({
                title: "Send mail",
                click: function () {
                    // get content
                    var content = area.val();
                    // send
                    sendMail(node, content, mail);
                }
            }).css({
                marginRight: "10px"
            })
        ).append(
            createButton({
                title: "Cancel",
                click: hideQuickReply,
                data: {
                    node: node,
                    mail: mail
                }
            })
        ).bind("click", function (e) {
            e.stopPropagation();
        });
        
        // hide button
        $(this).hide();
        
        // show
        cell.parent().show();
        
        // focus
        area.focus();
        
        return false;
    };
    
    /**
     * Draw mail content
     */
    drawDetailMail = function (node, mail, cont) {
        
        // insert iframe
        var iframe = $("<iframe/>", {
            src: "newInfoItemHidden.html",
            frameBorder: "0",
            marginWidth: "0",
            marginHeight: "0"
        }).css({
            width: "100%",
            height: "50px",
            backgroundColor: "white",
            margin: "10px 0px 5px 0px",
            cursor: "default",
            borderTop: "1px solid black"
        });
        
        // local vars
        var details, address, search;
        
        // get nodes
        var cells = getCells(node);
        
        // get images
        var images = cells.eq(PORTRAIT).find("img");
        
        var drawAttachments = function (data) {
            // get cell
            var cell = cells.eq(ATTACHMENTS);
            // show row
            cell.empty().append(
                $("<span/>").css("fontWeight", "bold").text("Attachments: ")
            ).parent().show();
            // open attachment
            var fnOpen = function (e) {
                // get ids
                var id = e.data.id, folder = e.data.folder, aId = e.data.aId;
                // get url
                var url = AjaxRoot + "/mail?action=attachment&folder=" + folder + 
                    "&id=" + id + "&attachment=" + aId + "&session=" + session;
                // open popup
                window.open(url, "");
                // prevent bubbling
                return false;
            };
            // loop over attachments
            var i = 1, $i = data.attachments.length, a;
            for (; i < $i; i++) {
                // get attachment
                a = data.attachments[i];
                // draw
                $("<span/>").css({
                    color: "black"
                }).text(a.filename).appendTo(
                    cell
                ).bind("click", {
                    folder: data.folder_id,
                    id: data.id,
                    aId: a.id
                }, fnOpen);
                // add delimiter
                if (i < $i - 1) {
                    $("<span/>").text("; ").appendTo(cell);
                }
            }
        };
        
        var join = new Join(function () {
            
            var data = details;
            
            // portrait found?
            var obj = search.map[address], contact, found = false;
            if (obj !== undefined) {
                contact = search.contacts[obj.key];
                // has image?
                if (contact.image1_url) {
                    images.eq(0).attr("src", contact.image1_url).show();
                    found = true;
                }
            }
            if (!found) {
                images.eq(PORTRAIT).css({
                    backgroundColor: "#efefef",
                    border: "1px solid #ddd"
                }).show();
            }
            
            // has attachments?
            if (data.attachment === true) {
                drawAttachments(data);
            }
            
            // remove spinner
            iframe.removeClass("busy-spinner-white");
            // get first attachment
            var attachment = data.attachments[0];
            if (attachment) {
                // get content
                var content = data.attachments[0].content;
                var content_type = data.attachments[0].content_type.toLowerCase();
                // get document
                var win = iframe[0].contentWindow;
                var doc = win.document;
                // continuation
                var setContent = function (content) {
                    // write content
                    doc.open();
                    doc.writeln(content);
                    doc.close();
                    // adjust padding
                    $("body", doc).css("paddingTop", "10px");
                    // bind
                    var selection = $("body", doc).add(win).add(doc);
                    var setHeight = function (e) {
                        // unbind
                        selection.unbind("resize ready load", setHeight);
                        // adjust outer height
                        var height = $("body", doc).outerHeight(true);
                        iframe.css("height", (height + 20) + "px");
                    };
                    // bind
                    selection.one("resize ready load", setHeight);
                    selection.one("resize ready load", cont);
                    // inject stylesheet
                    $("head", doc).append(
                        $("<style/>", {
                            type: "text/css"
                        }).text(mailStylesheet)
                    );
                    // bind click
                    node.bind("click", fnCloseMail);
                    // set initial height
                    setHeight();
                };
                // text?
                if (content_type === "text/plain") {
                    // text/plain
                    setContent('<html><head></head><body class="plainTextContent">' + content + "</body></html>");
                } else if (content_type === "text/html") {
                    // text/html
                    setContent(content);
                }
            }
        });
        
        var lock = join.add();
        
        // get mail content
        ox.api.mail.httpGet({
            params: {
                id: mail.id,
                folder: mail.folder_id,
                view: "noimg"
            },
            success: join.add(function (data) {
                details = data;
            })
        });
        
        // wait for iframe being loaded
        iframe.one("load", join.add());
        
//        // get position
//        var position = node.position();
//        var scrollTop = node.parent().scrollTop();
//        var y = scrollTop + position.top;
//        // scroll to
//        node.parent().stop().animate({ scrollTop: y }, 250);

        // search for contact
        if (mail.from && mail.from.length) {
            address = (mail.from[0][1] || "").toLowerCase();
            // show spaceholder
            images.eq(1).show();
            // search
            searchContacts([address], join.add(function (data) {
                search = data;
            }));
        }
        
        // maximize
        node.animate({ marginLeft: "10px" }, 0, join.add(function () {
            // add spinner
            iframe.addClass("busy-spinner-white");
            // inc font size
            cells.eq(FROM).css({ fontSize: "11pt", lineHeight: "15pt" });
            cells.eq(SUBJECT).css({ fontSize: "11pt", lineHeight: "15pt", paddingBottom: "0.5em" });
            // show reply button
            cells.eq(BUTTON).empty().append(
                createButton({
                    title: "Quick reply",
                    click: showQuickReply,
                    data: { node: node, mail: mail }
                })
            );
            // show fields (to/cc)
            if (mail.to && mail.to.length) {
                cells.eq(TO).empty().append(
                    $("<span/>").css("fontWeight", "bold").text("To: ")
                ).append(drawContacts(mail.to, showContactDetails(node))).parent().show();
            }
            // cc
            if (mail.cc && mail.cc.length) {
                cells.eq(CC).empty().append(
                    $("<span/>").css("fontWeight", "bold").text("Cc: ")
                ).append(drawContacts(mail.cc, showContactDetails(node))).parent().show();
            }
            // add iframe
            cells.eq(IFRAME).append(iframe).parent().show();
        }));
        
        lock();
    };
    
    hideDetailMail = function (node) {
        // get nodes
        var cells = getCells(node);
        // dec font size
        cells.eq(FROM).css({ fontSize: "", lineHeight: "" });
        cells.eq(SUBJECT).css({ fontSize: "", lineHeight: "", paddingBottom: "" });
        // remove image
        cells.eq(PORTRAIT).find("img").hide();
        // hide reply button
        cells.eq(BUTTON).children().hide();
        cells.eq(REPLY).empty().parent().hide();
        // hide fields
        cells.eq(TO).parent().hide();
        cells.eq(CC).parent().hide();
        cells.eq(ATTACHMENTS).parent().hide();
        cells.eq(CONTACT).empty().parent().hide();
        // remove iframe
        cells.eq(IFRAME).empty().parent().hide();
        // revert
        var level = node.data("level");
        node.animate({ marginLeft: (10 + level * 40) + "px" }, 0, function () {
            // bind click
            node.bind("click", fnOpenMail);
        });
    };
    
    /*
     * Draw single mail
     */
    
    setEditMode = function (node, flag) {
        flag = !!flag;
        node.data("edit", flag).css("cursor", flag ? "default" : "pointer");
    };
    
    var open;
    fnOpenMail = function () {
        // close open mail?
        /*if (open) {
            //$.proxy(fnCloseMail, open)();
        }*/
        // open
        open = this;
        var node = $(this);
        node.unbind("click", fnOpenMail);
        drawDetailMail(node, node.data("mail"), function () {
            // scroll
            //var top = node.position().top + dom.scrollpane.scrollTop();
            //dom.scrollpane.scrollTop(top);
        });
    };
    
    fnCloseMail = function () {
        var node = $(this);
        if (node.data("edit") !== true) {
            node.unbind("click", fnCloseMail);
            hideDetailMail(node);
        }
        open = undefined;
    };
    
    // colors for color_label
    var labelColors = [
        "#eee", "#800", "#57a", "#080", "#aaa"
    ];
    
    collapseThread = function (data) {
        // get key
        var key = data.folder_id + "." + data.id;
        // get thread
        var top = threads[threads[key].top];
        // click
        var fnClick = function () {
            expandThread(data);
            return false;
        };
        // hide except latest
        var i = 0, mails = top.mails, $i = mails.length, obj;
        for (; i < $i; i++) {
            // get
            obj = threads[mails[i]];
            // level
            obj.node.data("level", 0);
            // set margins
            obj.node.css({
                marginTop: "10px",
                marginLeft: "10px"
            });
            // update link
            getCells(obj.node).eq(DATE).find("a").text(
                "Show full thread"
            ).unbind("click").bind("click", fnClick);
            // hide node?
            if (top.latest !== mails[i]) {
                // hide
                obj.node.hide();
            } else {
                // add number of mails
                getCells(obj.node).eq(FROM).append(
                    $("<span/>").addClass("num-mails").css({
                        fontWeight: "normal",
                        color: "black"
                    }).text(
                        " (" + top.mails.length + ")"
                    )
                );
            }
        }
    };
    
    expandThread = function (data) {
        // get key
        var key = data.folder_id + "." + data.id;
        // get thread
        var top = threads[threads[key].top];
        // click
        var fnClick = function () {
            collapseThread(data);
            return false;
        };
        // show
        var i = 0, mails = top.mails, $i = mails.length, obj, level;
        for (; i < $i; i++) {
            // get
            obj = threads[mails[i]];
            // level
            level = obj.level;
            obj.node.data("level", level);
            // set margins
            obj.node.css({
                marginTop: level > 0 ? "2px" : "10px",
                marginLeft: 10 + level * 40 + "px"
            });
            // remove/update links
            if (key === mails[i]) {
                getCells(obj.node).eq(DATE).find("a").text(
                    "Hide full thread"
                ).unbind("click").bind("click", fnClick);
            } else {
                getCells(obj.node).eq(DATE).find("a").remove();
            }
            // remove num of mails
            obj.node.find(".num-mails").remove();
            // show node
            obj.node.show();
        }
    };
    
    /**
     * Draw mail header
     */
    drawMail = function (fragment, mail) {
        
        // node
        var div = mailTemplate.clone(), nodes = getCells(div);
        
        // set data
        div.data("mail", mail);
        
        // init edit mode
        setEditMode(div, false);
        
        // set margin
        var level = currentView === "thread" ? mail.level || 0 : 0;
        div.css("marginLeft", (10 + level * 40) + "px");
        div.data("level", level);
        
        // first of thread?
        if (level === 0) {
            div.css({
                borderColor: "#888",
                borderWidth: "1px",
                marginTop: "10px"
            });
        }
        
        // from
        nodes.eq(FROM).append(drawContacts(mail.from, showContactDetails(div)));
        
        // time
        var t = mail.received_date || 0;
        var time_1 = getTime(t);
        var time_2 = formatDate(t, "dateshortday") + " " + formatDate(t, "time") + "h";
        nodes.eq(DATE).append(
            $("<span/>").text(time_1).hover(
                function () {
                    $(this).text(time_2);
                },
                function () {
                    $(this).text(time_1);
                }
            )
        );
        
        // subject
        nodes.eq(SUBJECT).text(mail.subject + " ");
        
        // read/unread state
        if ((mail.flags & 32) === 0) {
            nodes.eq(FROM).css("fontWeight", "bold");
            nodes.eq(SUBJECT).css("fontWeight", "bold");
        }
        
        // important? (priority higher than normal)
        if (mail.priority < 3) {
            // add symbol
            nodes.eq(SUBJECT).append(
                $("<span/>").css({
                    fontWeight: "bold",
                    color: "#fc0"
                }).text(" \u2605\u2605\u2605 ")
            );
        }
        
        // latest only?
        if (currentView === "latest") {
            // get key
            var key = mail.folder_id + "." + mail.id;
            // get top element
            var top = threads[threads[key].top];
            // add nodes
            if (top.mails.length > 1) {
                nodes.eq(DATE).prepend(
                    $("<span/>").text(" ")
                ).prepend(
                    $("<a/>", {
                        href: "#"
                    }).css({
                        color: "#00c",
                        fontWeight: "normal",
                        textDecoration: "underline"
                    }).text(
                        "Show full thread"
                    ).bind("click", function () {
                        expandThread(mail);
                        return false;
                    })
                );
                // add number of mails
                nodes.eq(FROM).append(
                    $("<span/>").addClass("num-mails").css({
                        fontWeight: "normal",
                        color: "black"
                    }).text(" (" + top.mails.length + ")")
                );
            }
        }
        
        // has attachments?
        if (mail.attachment === true) {
            // add symbol
            nodes.eq(SUBJECT).append(
                $("<span/>").css({
                    fontSize: "1em",
                    fontWeight: "bold",
                    color: "#a00"
                }).text(" \u25A0 ")
            );
//            // add icon
//            nodes.eq(ICONS).append(
//                $("<img/>", {
//                    src: ox.gui.themePath + "img/mail/attachment.gif",
//                    alt: ""
//                }).css({
//                    width: "7px",
//                    height: "14px",
//                    marginLeft: "4px",
//                    display: "inline-block"
//                })
//            );
        }
        
        // color label
        var label = mail.color_label || 0, color;
        if (label) {
            color = labelColors[label % 5];
            div.find(".ox-mail-flag").css({
                top: "-1px",
                right: "-1px",
                bottom: "-1px",
                width: "11px",
                border: "0px none",
                borderLeft: "0px none",
                backgroundColor: color
            });
        }
        
        // bind click
        div.bind("click", fnOpenMail);
        
        // add to fragment
        fragment.appendChild(div[0]);
        
        return div;
    };
    
    /**
     * Draw mails
     */
    drawMails = function (offset, cont) {
        // get list of mails
        ox.api.mail.list({
            data: getSubset(offset),
            params: {
                columns: "600,601,602,603,604,605,606,607,609,610,611,612,614,102"
            },
            success: function (data) {
                // vars
                var i = 0, $i = data.length, frag = newfrag();
                // latest mails only?
                if (currentView === "latest") {
                    // generate meta data
                    var mail, key, top, latest;
                    for (; i < $i; i++) {
                        // get
                        mail = data[i];
                        // get key
                        key = mail.folder_id + "." + mail.id;
                        // is top-level?
                        if (!mail.level) {
                            top = key;
                            latest = mail.received_date;
                        }
                        // add
                        threads[key] = {
                            top: top,
                            mails: [],
                            node: null,
                            latest: key,
                            level: mail.level || 0
                        };
                        threads[top].mails.push(key);
                        // latest?
                        if (mail.received_date >= latest) {
                            threads[top].latest = key;
                            latest = mail.received_date;
                        }
                    }
                    // loop again
                    for (i = 0; i < $i; i++) {
                        // get
                        mail = data[i];
                        // get key
                        key = mail.folder_id + "." + mail.id;
                        // draw
                        threads[key].node = drawMail(frag, mail);
                        // get top
                        top = threads[threads[key].top];
                        // is latest?
                        if (top && top.latest === key) {
                            // show
                            threads[key].node.show();
                        } else {
                            // hide
                            threads[key].node.hide();
                        }
                    }
                } else {
                    // loop
                    for (i = 0; i < $i; i++) {
                        if (currentView === "thread") {
                            drawMail(frag, data[i]);
                        } else if (currentView === "unread") {
                            if ((data[i].flags & 32) === 0) {
                                drawMail(frag, data[i]);
                            }
                        }
                    }
                }
                // add fragment
                dom.scrollpane.get(0).appendChild(frag);
                // continue
                ox.util.call(cont);
            }
        });
    };
    
    /**
     * Search contacts by mail address
     */
    searchContacts = function (list, cont) {
        // pause
        ox.api.http.pause();
        // local success
        var success = function (responses) {
            // loop over responses
            var i = 0, data = responses.data, $i = data.length, r, key;
            var map = function (address, key) {
                address = (address || "").toLowerCase();
                if (address !== "") {
                    // global address book (6) dominates other folders
                    if (addressMap[address] === undefined || key.folder === 6) {
                        addressMap[address] = key;
                    }
                }
            };
            for (; i < $i; i++) {
                r = data[i];
                // get key
                key = { id: r[0], folder: r[1], key: r[1] + "." + r[0] };
                // mapping
                map(r[2], key);
                map(r[3], key);
                map(r[4], key);
            }
        };
        // loop over addresses
        var i = 0, $i = list.length, address;
        var addressMap = {}, contacts = {};
        for (; i < $i; i++) {
            address = list[i];
            // search for contact
            ox.api.http.PUT({
                module: "contacts",
                params: {
                    action: "search",
                    columns: "1,20,555,556,557"
                },
                data: {
                    email1: address,
                    email2: address,
                    email3: address,
                    orSearch: true//,
                    //folder: [6] // GAB only
                },
                success: success
            });
        }
        // resume
        ox.api.http.resume(function () {
            // now get the contact data
            ox.api.http.PUT({
                module: "contacts",
                params: {
                    action: "list"
                },
                data: ox.util.values(addressMap),
                success: function (response) {
                    // remember contact data
                    var i = 0, data = response.data, $i = data.length, contact, key;
                    var columns = ox.api.http.getAllColumns("contacts");
                    for (; i < $i; i++) {
                        contact = ox.api.http.makeObject(data[i], "contacts", columns);
                        key = contact.folder_id + "." + contact.id;
                        contacts[key] = contact;
                    }
                    ox.util.call(cont, {
                        map: addressMap,
                        contacts: contacts
                    });
                }
            });
        });
    };
    
    /*
     * Define thread view
     */
    repaint = function () {
        currentFolder = undefined;
        paint();
    };
    paint = function () {
        // clear selection
        triggerEvent("Selected", []);
        // clear open mail
        open = undefined;
        // get current folder
        var folder = ox.UIController.getFolder();
        // folder changed?
        if (folder !== currentFolder) {
            // set folder
            currentFolder = folder;
            // get all mails
            getAllMails(folder, function (data) {
                // remember list
                mailIDs = data;
                // clear scroll pane
                dom.scrollpane.hide().empty();
                // clear address hash
                addresses = {};
                // add spinner
                dom.container.addClass("busy-spinner-white");
                // draw mails
                drawMails(0, function () {
                    // remove spinner
                    dom.container.removeClass("busy-spinner-white");
                    // show scrollpane
                    dom.scrollpane.show();
                });
            });
        }
    };
    
    registerView(
        "mail/threaded",
        // show
        function () {
            // add node to content area
            $("#contentarea").append(dom.decorator);
            $("#contentarea").append(dom.container);
            // say that this is a valid mail view (required for folder changes)
            menulastviews.mail = "mail/threaded";
        },
        // enter
        paint,
        // leave
        function () {
        },
        // hide
        function () {
            // remove node from content area
            dom.container.appendTo(dom.park);
            dom.decorator.appendTo(dom.park);
        },
        // change (called, e.g., after folder changes)
        paint
    );
    
    
    // parking zone
    dom.park = $("<div/>");
    
    // prepare decorator & container
    dom.decorator = $("<div/>").css({
        position: "absolute",
        top: "0px",
        right: "0px",
        bottom: "0px",
        left: "0px"
    }).addClass(
        "cpbody-color"
    );
    
    dom.container = $("<div/>").css({
        position: "absolute",
        top: "0px",
        right: "0px",
        bottom: "0px",
        left: "4px"
    });
    
    dom.scrollpane = $("<div/>").css({
        position: "absolute",
        top: "30px",
        right: "0px",
        bottom: "0px",
        left: "0px",
        overflow: "auto"
    }).appendTo(dom.container);
    
    // controls
    dom.controls = $("<div/>").css({
        position: "absolute",
        top: "0px",
        right: "0px",
        height: "30px",
        left: "0px",
        lineHeight: "30px",
        textAlign: "left",
        padding: "0px 0px 0px 10px"
    }).appendTo(dom.container);
    
    // radios
    var changeType = function (type) {
        currentView = type || "thread";
        repaint();
    };
    var drawRadio = function (id, name, title, checked, fn) {
        // input field
        var input = $("<input/>", {
            type: "radio",
            id: id,
            name: name
        }).css("border", "0px none").bind("change", fn);
        // checked?
        if (checked === true) {
            input.attr("checked", "checked");
        }
        // label
        var label = $("<label/>", {
            "for": id
        }).text(title + " ");
        return $().add(input).add(label).appendTo(dom.controls);
    };
    
    dom.viewThread = drawRadio("tv-view-thread", "tv-view", "Show full threads", true, function (e) {
        changeType("thread");
    });
    
    dom.viewLatest = drawRadio("tv-view-latest", "tv-view", "Show latest mails per thread only", false, function (e) {
        changeType("latest");
    });
    
    dom.viewUnread = drawRadio("tv-view-unread", "tv-view", "Show unread mails only", false, function (e) {
        changeType("unread");
    });
    
}(jQuery));

// overwrite default mail view
if (menulastviews) {
    menulastviews.mail = "mail/threaded";
    config.gui.mail.view = "mail/threaded";
}
