/**
 * 
 * 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) Open-Xchange Inc., 2006-2011
 * 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: true, browser: true, devel: true, evil: true, forin: true, undef: true, eqeqeq: true, immed: true */

/*global ox, jQuery, registerModule, _, PortalItem, registerView, showNode, hideNode,
cPortal, OXCache, register, triggerEvent, configuration_changed_fields,
getFullImgSrc, PortalExternalItem, bUWAEnabled, url, UWA, internalCache */

registerModule("portal", _("Start Page"), 1);

var	bPortalConfigChanged = false;
var oPortalObject = null;

// -------

var oPortal = (function ($) {
    
    // dom nodes
    var dom = {};
    
    // dom parking zone (to save event handlers)
    var park = $("<div/>");
    
    // widgets
    var widgets = [];
    var grid = [];
    
    // layout nodes
    var layoutNodes = $();
    
    // placeholder for DnD
    var placeholder = $("<div/>").addClass("ox-portal-placeholder");
    
    // config shortcut/keys
    var config = $.noop;
    var keyInternal = "gui.portal.internalcontents";
    var keyExternal = "gui.portal.externalcontents";
    
    // current layout
    var currentLayout = 2;

    // DnD
    var dnd = (function () {
        
        var gridX = [], gridY = {};
        
        var px, py;
        var ppx, ppy;
        var outer, width, height;
        var iframes;
        
        var numSort = function (a, b) {
            return a - b;
        };
        
        var getGridPosition = function (x, y) {
            // consider dimensions
            x = x + (width >> 1);
            // transform mouse position to grid position
            px = 0;
            py = -1;
            var i, $i;
            for (i = 0, $i = gridX.length; i < $i; i++) {
                if (x > gridX[i]) {
                    px = i;
                }
            }
            if (gridY[px] !== undefined) {
                for (i = 0, $i = gridY[px].length; i < $i; i++) {
                    if (y > gridY[px][i]) {
                        py = i;
                    }
                }
            }
        };
        
        return {
            
            getWidget: function (x, y) {
                // loop widgets
                var i = 0, $i = grid.length, obj;
                for (; i < $i; i++) {
                    obj = grid[i];
                    if (obj.x === x && obj.y === y) {
                        return obj;
                    }
                }
                return null;
            },
            
            start: function (n) {
                
                // remember
                outer = n;
                width = n.outerWidth();
                height = n.outerHeight();
                
                // resize placeholder
                placeholder.height((height - 4) + "px");
                
                // vars
                var i, $i, node, offset, x, y;
                
                // get vertical borders
                gridX = [];
                for (i = 0, $i = layoutNodes.length; i < $i; i++) {
                    // get node
                    node = layoutNodes.eq(i);
                    // get offset
                    offset = node.offset();
                    // floor
                    x = offset.left >> 0;
                    // add
                    gridX.push(x);
                }
                
                // get horizontal borders
                gridY = {};
                // loop widgets
                for (i = 0, $i = grid.length; i < $i; i++) {
                    // get node
                    node = grid[i].node;
                    x = grid[i].x;
                    // get offset
                    offset = node.offset();
                    // floor
                    y = (offset.top >> 0);
                    if (gridY[x] === undefined) {
                        gridY[x] = [];
                    }
                    gridY[x].push(y);
                }
                // sort x
                gridX.sort(numSort);
                // sort y
                for (x in gridY) {
                    gridY[x].sort(numSort);
                }
                
                // apply iframe fix
                iframes = dom.container.find("iframe").overlay();
            },
            
            update: function (x, y) {
                // add scroll position
                y += dom.container.scrollTop();
                // get grid position
                getGridPosition(x, y);
                // change position?
                if (px !== ppx || py !== ppy) {
                    if (py === -1) {
                        // add as first
                        placeholder.prependTo(layoutNodes.eq(px).children());
                    } else {
                        var widget = dnd.getWidget(px, py);
                        if (widget) {
                            // insert after
                            placeholder.insertAfter(widget.node);
                        } else {
                            // append
                            placeholder.appendTo(layoutNodes.eq(px).children());
                        }
                    }
                    ppx = px;
                    ppy = py;
                }
            },
            
            stop: function () {
                
                // remove iframe fix
                iframes.overlay(false);
                
                // insert after
                outer.insertAfter(placeholder);
                // remove placeholder
                placeholder.remove();
                // show
                outer.show();
                
                // clear grid
                grid = [];
                
                // loop over layoutNodes
                layoutNodes.each(function (x, node) {
                    $(node).children().first().children().each(function (y, node) {
                        // get widget
                        var widget = $(node).data("widget");
                        // update grid
                        grid.push({
                            widget: widget,
                            node: $(node),
                            x: x,
                            y: y
                        });
                    });
                });
                
                // update configuration
                dnd.store();
            },
            
            store: function () {
                
                // clone grid
                var tmp = grid.slice();
                
                var getPosition = function (key, value) {
                    var i = 0, $i = tmp.length, obj, pos = null;
                    for (; i < $i; i++) {
                        obj = tmp[i];
                        if (obj.widget[key] === value && value !== undefined) {
                            pos = { x: obj.x, y: obj.y };
                            break;
                        }
                    }
                    return pos;
                };
                
                var updatePositions = function (internal, list) {
                    var i = 0, $i = list.length, obj, pos;
                    for (; i < $i; i++) {
                        obj = list[i];
                        if (internal) {
                            pos = getPosition("module", obj.module);
                        } else {
                            pos = getPosition("id", obj.id || obj.title);
                        }
                        if (pos) {
                            obj.adj = pos;
                        }
                    }
                    return list;
                };
                
                // update internal
                config.set(keyInternal, updatePositions(true, config.get(keyInternal)));
                // update external
                config.set(keyExternal, updatePositions(false, config.get(keyExternal)));
                
                configuration_changed_fields.gui = true;
            },
            
            close: function (data) {
                
                var key, value, list;
                var isInternal = data.module !== undefined;
                
                // internal?
                if (isInternal) {
                    key = "module";
                    value = data.module;
                    list = config.get(keyInternal);
                } else {
                    key = "id";
                    value = data.id || data.title;
                    list = config.get(keyExternal);
                }
                
                // loop
                var i = 0, $i = list.length, obj;
                for (; i < $i; i++) {
                    obj = list[i];
                    if (obj[key] === value) {
                        // set invisible
                        obj.visible = false;
                        if (isInternal) {
                            // update limit
                            obj.params.limit = 0;
                        }
                        break;
                    }
                }
                
                // update config
                config.set(isInternal ? keyInternal : keyExternal, list);
                
                configuration_changed_fields.gui = true;
            }
        };
        
    }());
    
    var drawWidget = function (node, data, isInternal) {
        
        var outer, header, title, inner;
        
        outer = $("<div/>").addClass("ox-portal-widget").css({
            position: "relative"
        })
        .append(
            header = $("<div/>")
                .addClass("ox-portal-header")
                .append(
                    $("<img/>", { src: getFullImgSrc("img/dummy.gif"), alt: "" })
                    .addClass("ox-portal-close")
                    .css({
                        "float": "right"
                    })
                    .bind("click", function () {
                        dnd.close(data);
                        drawCheckboxes();
                        oPortal.repaint();
                    })
                )
                .append(
                    title = $("<span/>").text("\u00a0")
                )
        )
        .append(
            inner = $("<div/>").css({
                position: "relative",
                minHeight: "50px",
                padding: "8px"
            })
        )
        .appendTo(node);
        
        // set title
        switch (data.module) {
        case "calendar":
            title.text("" + _("Calendar"));
            break;
        case "mail":
            title.text("" + _("E-Mail"));
            break;
        case "tasks": 
            title.text("" + _("Tasks"));
            break;
        case "infostore":
            title.text("" + _("InfoStore"));
            break;
        default: // external
            title.text("" + data.title);
            break;
        }
        
        // prevent selection
        if (ox.browser.Gecko) {
            // Firefox
            outer.css("MozUserSelect", "-moz-none");
        } else {
            // IE, WebKit
            outer.bind("selectstart", function () {
                return false;
            });
        }
        
        // create new portal object
        var widget;
        if (isInternal) {
            widget = new PortalItem(
                data.module, inner.get(0), header.get(0), data.params.limit,
                data.adj, $("<div/>").get(0), dom.container.get(0)
            );
        } else {
            widget = new PortalExternalItem(
                data.id || data.title, // id
                data.module, inner.get(0), header.get(0), data.parameter,
                data.adj, $("<div/>").get(0), dom.container.get(0),
                data.url
            );
            widget.autorefresh = data.autorefresh;
            widget.standalone = data.standalone;
        }
        
        outer.data("widget", widget);
        
        // make draggable
        outer.draggable({
            handle: ".ox-portal-header",
            helper: function () {
                // "clone" fix for jQuery (>1.5), since clone's default is now "true"
                return $(this).clone(false);
            },
            opacity: 0.75,
            revert: false,
            start: function (e, ui) {
                ui.helper.css({
                    width: outer.width() + "px",
                    height: outer.height() + "px",
                    zIndex: 65000
                }).find("iframe").remove();
                // get grid
                dnd.start(outer);
                // hide
                outer.hide();
            },
            drag: function (e, ui) {
                dnd.update(ui.position.left, ui.position.top);
            },
            stop: function (e, ui) {
                ui.helper.remove();
                dnd.stop();
                outer.show();
                placeholder.remove();
            }
        });
        
        return {
            x: data.adj.x,
            y: data.adj.y,
            node: outer,
            widget: widget
        };
    };
    
    var getAllData = function () {
        
        var meta = [];
        
        var success = function (response) {
            // loop over response
            var i = 0, $i = response.length, data, widget;
            for (; i < $i; i++) {
                // get widget
                widget = meta[i].widget;
                // error?
                if (response[i].error) {
                    widget.setError(response[i]);
                } else {
                    // set data
                    widget.setData(
                        response[i].data,
                        meta[i].index,
                        response[i].timestamp,
                        meta[i].limit
                    );
                }
            }
            
            // loop again to update
            for (i = 0; i < $i; i++) {
                meta[i].widget.update();
            }
            
            meta = response = data = widget = null;
        };
        
        // loop over internal widget instances
        var i = 0, $i = widgets.length, widget, req, all = [], j, $j;
        for (; i < $i; i++) {
            // get
            widget = widgets[i];
            // internal?
            if (!widget.extern) {
                // get requests
                req = widget.getRequests();
                // add
                for (j = 0, $j = req.length; j < $j; j++) {
                    all.push(req[j]);
                    meta.push({ widget: widget, index: j, limit: req[j].limit });
                }
            }
        }
        // send "multiple" server request
        ox.api.http.PUT({
            module: "multiple",
            data: all,
            success: success
        });
    };
    
    /*
     * Layout
     */
    
    var applyLayout = function () {
        
        var tmpl = $("<div/>").css({
            "float": "left",
            width: "100%"
        }).append(
            $("<div/>").css({
                marginRight: "15px",
                minHeight: "1px"
            })
        );
        
        // park widgets
        dom.container.find(".ox-portal-widget").detach();
        
        // clear
        layoutNodes.remove();
        layoutNodes = $();
        
        var add = function (node, last) {
            if (last) {
                node.children().first().css("marginRight", "0px");
            }
            layoutNodes = layoutNodes.add(
                node.appendTo(dom.container)
            );
        };
        
        // layout #1?
        switch (currentLayout) {
        case 1:
            add(tmpl.clone().css({ width: "100%" }), true);
            break;
        case 2:
            add(tmpl.clone().css({ width: "50%" }));
            add(tmpl.clone().css({ width: "50%" }), true);
            break;
        case 3:
            add(tmpl.clone().css({ width: "33%" }));
            add(tmpl.clone().css({ width: "33%" }));
            add(tmpl.clone().css({ width: "34%" }), true);
            break;
        case 4:
            add(tmpl.clone().css({ width: "40%" }));
            add(tmpl.clone().css({ width: "60%" }), true);
            break;
        case 5:
            add(tmpl.clone().css({ width: "60%" }));
            add(tmpl.clone().css({ width: "40%" }), true);
            break;
        }
    };
    
    var getLayoutNode = function (adj) {
        var $l = layoutNodes.length, index = Math.max(0, Math.min(adj.x || 0, $l - 1));
        return layoutNodes.eq(index).children().first();
    };
    
    var refreshLayout = function () {
        // apply layout
        applyLayout();
        // loop over grid
        var i = 0, $i = grid.length, obj, node;
        for (; i < $i; i++) {
            obj = grid[i];
            // get layout node
            node = getLayoutNode({ x: obj.x, y: obj.y });
            // append
            node.append(obj.node);
        }
    };
    
    var drawPortal = function () {
        
        // apply layout
        applyLayout();
        
        // get internal objects
        var internal = config.get(keyInternal);
        var external = config.get(keyExternal);
        var inbox = config.get("mail.folder.inbox");
        
        var sorter = function (a, b) {
            return a.adj.y - b.adj.y;
        };
        
        // sort by vertical position
        internal.sort(sorter);
        external.sort(sorter);
        
        // clear list
        widgets = [];
        grid = [];
        
        // loop over internal widgets
        var i = 0, $i = internal.length, item, node, obj;
        for (; i < $i; i++) {
            // get
            item = internal[i];
            // defined?
            if (item.adj !== undefined) {
                // inbox missing?
                if (item.module === "mail" && inbox === null) {
                    item.visible = false;
                }
                // visible?
                if (item.visible) {
                    // get layout node
                    node = getLayoutNode(item.adj);
                    // draw widget (returns instance of PortalItem)
                    obj = drawWidget(node, item, true);
                    widgets.push(obj.widget);
                    grid.push(obj);
                }
            }
        }
        
        // external
        if (bUWAEnabled && url.external !== 0) {
            // loop over external widgets
            for (i = 0, $i = external.length; i < $i; i++) {
                // get object
                item = external[i];
                // visible?
                if (item.visible) {
                    // get layout node
                    node = getLayoutNode(item.adj);
                    // draw widget (returns instance of PortalItem)
                    obj = drawWidget(node, item, false);
                    widgets.push(obj.widget);
                    grid.push(obj);
                    // paint frame
                    obj.widget.appendFrame();
                }
            }
        }
        
        // get all data
        getAllData();
    };
    
    var paint, drawCheckboxes;
    
    drawCheckboxes = function () {
        
        var limits = { mail: 10, calendar: 10, tasks: 10, infostore: 5 };
        
        var fnChange = function (e) {
            // get module
            var module = e.data.module;
            var checked = $(this).is(":checked");
            // get internal widgets
            var i = 0, list = config.get(keyInternal), $i = list.length, obj;
            for (; i < $i; i++) {
                obj = list[i];
                if (obj.module === module) {
                    obj.visible = checked;
                    obj.params.limit = checked ? limits[module] : 0;
                    break;
                }
            }
            // update config
            config.set(keyInternal, list);
            // repaint
            paint(true);
        };
        
        var isChecked = function (module) {
            // get internal widgets
            var i = 0, list = config.get(keyInternal), $i = list.length, obj, checked = false;
            for (; i < $i; i++) {
                obj = list[i];
                if (obj.module === module) {
                    checked = obj.visible;
                    break;
                }
            }
            return checked;
        };
        
        var checkbox = function (module, title) {
            
            return $().add(
                $.checkbox(
                    "ox-portal-show-" + module, // id
                    "1", // value
                    isChecked(module), // checked
                    title, // label
                    fnChange, // callback
                    { module: module } // data
                )
            ).add(
                $("<br/>")
            );
        };
        
        // clear
        dom.checkboxes1.empty();
        dom.checkboxes2.empty();
        // add
        dom.checkboxes1.append(checkbox("mail", "Show mails" /*i18n*/ ));
        dom.checkboxes1.append(checkbox("calendar", "Show appointments" /*i18n*/ ));
        dom.checkboxes2.append(checkbox("tasks", "Show tasks" /*i18n*/ ));
        dom.checkboxes2.append(checkbox("infostore", "Show files" /*i18n*/ ));
    };
    
    paint = function (force) {
        
        var isFirst = false, className = "", link;
        
        if (dom.container === undefined) {
            
            // set shortcut
            config = ox.api.config;
            
            // get layout
            currentLayout = config.get("gui.portal.layout", 2);
            
            // topbar
            dom.topbar = $("<div/>").addClass("ox-portal-topbar").css({
                position: "absolute",
                top: "0px",
                right: "0px",
                height: "30px",
                lineHeight: "30px",
                left: "0px",
                padding: "0px 28px 0px 10px",
                textAlign: "left",
                zIndex: 2
            })
            .append(
                $("<i/>").append(addTranslated(getGreetingPhrase()))
                    .append(newtext(", "))
            )
            .append($("<b/>").text(""))
            .append($("<span/>").text(". \u00a0 "))
            .append(
                link = $("<a/>")
            )
            .appendTo("#portalContainer");
            
            var id = config.get("identifier");
            internalCache.getUsers([id], function (data) {
                dom.topbar.children().eq(1).text("" + data[id].display_name);
            });
            
            var fnChangeLayout = function (e) {
                // get nodes
                var nodes = dom.controls.find(".ox-portal-layout");
                // remove class
                nodes.eq(currentLayout - 1).removeClass("active");
                // set new layout
                currentLayout = e.data.layout || 2;
                // update config
                config.set("gui.portal.layout", currentLayout);
                configuration_changed_fields.gui = true;
                // add class
                nodes.eq(currentLayout - 1).addClass("active");
                // refresh layout
                refreshLayout();
            };
            
            // controls
            dom.controls = $("<div/>")
                .addClass("ox-portal-controls").css({
                    position: "absolute",
                    top: "30px",
                    right: "0px",
                    height: "60px",
                    left: "0px",
                    padding: "10px",
                    zIndex: 1
                })
                .append(
                    $("<img/>", { src: getFullImgSrc("img/dummy.gif"), alt: "" })
                        .addClass("ox-portal-layout one")
                        .bind("click", { layout: 1 }, fnChangeLayout)
                )
                .append(
                    $("<img/>", { src: getFullImgSrc("img/dummy.gif"), alt: "" })
                        .addClass("ox-portal-layout two")
                        .bind("click", { layout: 2 }, fnChangeLayout)
                )
                .append(
                    $("<img/>", { src: getFullImgSrc("img/dummy.gif"), alt: "" })
                        .addClass("ox-portal-layout three")
                        .bind("click", { layout: 3 }, fnChangeLayout)
                )
                .append(
                    $("<img/>", { src: getFullImgSrc("img/dummy.gif"), alt: "" })
                        .addClass("ox-portal-layout four")
                        .bind("click", { layout: 4 }, fnChangeLayout)
                )
                .append(
                    $("<img/>", { src: getFullImgSrc("img/dummy.gif"), alt: "" })
                        .addClass("ox-portal-layout five")
                        .bind("click", { layout: 5 }, fnChangeLayout)
                )
                .append(
                    dom.checkboxes1 = $("<div/>").css({
                        display: "inline-block",
                        verticalAlign: "top",
                        height: "60px",
                        margin: "10px 20px 0px 0px"
                    })
                )
                .append(
                    dom.checkboxes2 = $("<div/>").css({
                        display: "inline-block",
                        verticalAlign: "top",
                        height: "60px",
                        margin: "10px 20px 0px 0px"
                    })
                )
                .hide()
                .appendTo("#portalContainer");
            
            // add jump into UWA config
            if (bUWAEnabled) {
                dom.controls.append(
                    $("<div/>").css({
                        display: "inline-block",
                        verticalAlign: "top",
                        height: "60px",
                        margin: "10px 20px 0px 0px"
                    }).append(
                        $.button({
                            title: "UWA Widgets..." /*i18n*/,
                            theme: "dark",
                            click: function () {
                                // jump
                                ox.UIController.setModule({
                                    module: "configuration",
                                    view :"configuration/portal/external",
                                    success: function() {
                                        ox.widgets.configTree.get("configuration/portal").open();
                                        ox.widgets.configTree.selection.click("configuration/portal/external", false, false, true);
                                    }
                                });
                            }
                        })
                    )
                );
            }
            
            drawCheckboxes();
            
            // which browser?
            if (ox.browser.Gecko) {
                className = "firefox";
            } else if (ox.browser.WebKit) {
                className = "webkit";
            } else if (ox.browser.IE) {
                className = "IE";
            }
            
            // main container
            var parent = $("#portalContainer").addClass(className);
            dom.container = $("<div/>").addClass("ox-portal").css({
                position: "absolute",
                top: "30px",
                right: "0px",
                bottom: "0px",
                left: "0px",
                padding: "10px",
                overflow: "hidden",
                overflowX: "hidden",
                overflowY: "scroll",
                zIndex: 3
            })
            .appendTo(parent);
            
            // turn into quick config
            $.quickConfig(
                dom.container, dom.controls, link,
                "Change layout" /*i18n*/,
                "Close configuration" /*i18n*/
            );
            
            // mark active layout
            dom.controls.find(".ox-portal-layout").eq(currentLayout - 1).addClass("active");
            
            isFirst = true;
        }
        if (isFirst || force) {
            drawPortal();
        }
        return isFirst;
    };
    
    // public function/variables
    return {
        
        // initialize
        paint: paint,
        
        repaint: function () {
            paint(true);
        },
        
        refresh: function () {
            getAllData();
        },
        
        getGrid: function () {
            return grid;
        },
        
        refreshLayout: function () {
            refreshLayout();
        },
        
        updateControls: function () {
            drawCheckboxes();
        }
    };
    
}(jQuery));

// -------

registerView("portal",
    // show
	function () {
        showNode("portal");
    },
    // enter
	function () {
        if (bPortalConfigChanged) {
            // repaint
            oPortal.repaint();
            bPortalConfigChanged = false;
        } else {
            if (oPortal.paint()) {
                // set default folder for current module
                ox.api.ui.setFolder();
                // register
                register("OX_Refresh", oPortal.refresh);
                register("OX_Configuration_Changed", oPortal.updateControls);
            }
        }
	},
	// leave
	function () {
	},
	// hide
	function () {
		hideNode("portal");
	},
	// change
	function () {
	}
);

function fn_clickedItem(sModule, oObj) {
	OXCache.newRequest(null, sModule, { objects: [oObj] }, null, function () {
	    triggerEvent("OX_Direct_Linking", sModule, oObj);
	});
}

register("OX_Portal_Click_Item", fn_clickedItem);

register("OX_Configuration_Changed", function (param) {
    if (param && (param === "configuration/portal/layout")) {
        bPortalConfigChanged = true;
    }
});

/*
 * UWA Messaging
 */

(function () {
    
    var msgHandler = function (message) {
        var id = message.id;
        switch (message.action) {
        case "resizeHeight":
            var frame = document.getElementById('frame_' + id);
            if (frame) {
              frame.setAttribute("height", message.value + 25);
            }
            break;
        }
    };
       
    UWA.MessageHandler = new UWA.iFrameMessaging();
    UWA.MessageHandler.init({
        'eventHandler': msgHandler
    });
    
}());
