/**
 * 
 * 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-2010 Open-Xchange, Inc.
 * Mail: info@open-xchange.com 
 * 
 * @author Matthias Biggeleben <matthias.biggeleben@open-xchange.com>
 * 
 */

ox.gui.initSidepanel = function (sidenode) {
    
    var newFolderIcon = null;
    
    // prepare parent node
    $("<div/>", { id: "ox-sidesplit" }).
    addClass("oxStretch cpbody-r").
    css("right", "2px").
    append($("<div/>").
            css({ position: "absolute", top: "24px", right: "-10px",
                width: "12px", height: "24px" }).addClass("sp-toggle").
                append(
                        $("<img/>").attr("src", getFullImgSrc("img/arrows/arrow_double_gray_right.gif")).
                        css({ marginTop: "8px"})
                ).click(function() {
                    ox.widgets.sidepanel.toggle();
                    delete ox.widgets.sidepanel.userToggle;
                }).hide()
    ).appendTo(sidenode[0]);
        
    // create new sidepanel container
    var sidepanel = ox.widgets.sidepanel = new ox.gui.Container("ox-sidepanel-container").
        setLayout(new ox.gui.BorderLayout()).
        css({ right: "5px", background: "white" }).
        addTo(ox.desktop).
        setParentDOMNode(sidenode[0]);
    
    // initial sidebar width
    sidepanel.oldWidth = 229; // 19.1em
    
    // function to trigger sidebar toggle    
    sidepanel.toggle = function(state) {
        // set toggle state
        if (state !== undefined) {
            if (state === this.toggled) {
                return; // nothing changed, bye
            }
            this.toggled = state;
        } else {
            this.toggled = !this.toggled;
        }
                
        $("div.sp-toggle").css({ display: this.toggled ? "" : "none"});
        $(".sp-toggle-img img").css({ display: this.toggled ? "none" : ""});
        
        // hide sidepanel drag bar
        $("#sidepanel_dragpoint").css({ display: this.toggled ? "none" : ""});
        
        // hide newFolderIcon when avialable and toggled (nice-to-have :-))
        if (newFolderIcon !== null) {
            newFolderIcon.setVisible(!this.toggled);
        }
        
        // remember old width of the sidebar before toggle
        if (this.toggled) {
            this.oldWidth = $("#sidesplit").outerWidth();
        }
        
        // resize split
        resizeSplit("sidesplit", this.toggled ? "7px" : this.oldWidth + "px");
        
        // trigger global event
        triggerEvent("OX_Sidepanel_Collapse", this.toggled);
    };
    
    // hide when landing page is portal
    if ((ox.api.config.get("gui.global.landing_page.module") || "portal") === "portal") {
    	sidepanel.toggle(true);
    }
    
    // view
    var view = ox.widgets.sidepanelViewControl = new ox.gui.ViewControl("ox-side-view").
        setLayoutParam({ position: "center" }).
        css({ background: "white" }).
        setCSSClass("oxStretch");
    
    // register for resize
    resizeEvents.register("Resized", function () {
        sidepanel.resize();
    });
    
    // view hash
    var v = ox.widgets.sidepanelViews = {};
    
    var meta = {
        "portal": {
            title: _("Portal")
        },
        "mail": {
            title: _("E-Mail")
        },
        "calendar": {
            title: _("Calendar"),
            module: "calendar",
            icon: getFullImgSrc("img/folder/calendar.gif"),
            sections: {
                "private": _("Private calendars"),
                "shared": _("Shared calendars"),
                "public": _("Public calendars")
            }
        },
        "contacts": {
            title: _("Contacts"),
            module: "contacts",
            icon: getFullImgSrc("img/folder/contacts.gif"),
            sections: {
                "private": _("Private contacts"),
                "shared": _("Shared contacts"),
                "public": _("Public contacts")
            }
        },
        "tasks": {
            title: _("Tasks"),
            module: "tasks",
            icon: getFullImgSrc("img/folder/tasks.gif"),
            sections: {
                "private": _("Private tasks"),
                "shared": _("Shared tasks"),
                "public": _("Public tasks")
            }
        },
        "infostore": {
            title: _("Infostore"),
            sections: {
                "private": _("Private folders"),
                "all": _("All folders")
            }
        },
        "configuration": {
            title: _("Configuration")
        },
        "foldertree": {
            title: _("Folders")
        }
    };
    
    // mixin
    ox.gui.util = {};
    
    ox.gui.util.inlineEdit = function (node, value, success, abort) {
        // disable selection?
        if (this.selection) {
            this.selection.disable();
        }
        // this
        var self = this;
        // input field
        var input = $("<input/>", { type: "text", value: "" }).
            bind("keydown", function (e) {
                e.stopPropagation();
            }).
            bind("selectstart", function (e) {
                e.stopPropagation();
            });
        // handler
        var fnAbort = function (e) {
            // unbind
            input.unbind("blur", fnAbort);
            // call
            ox.util.call(abort);
        };
        var fnOk = function (e) {
            // unbind
            input.unbind("blur", fnAbort);
            // changed?
            if (value !== input.val()) {
                // changed, success!
                ox.util.call(success, input.val());
            } else {
                // same value, abort!
                ox.util.call(abort);
            }
        };
        // replace node content
        input.
            css({
                width: "100%",
                border: "1px solid #555",
                borderWidth: "1px 0px 1px 0px",
                background: "#eee" 
            }).
            val(value || "").
            bind("mousedown", function () {
                return false;
            }).
            bind("keydown", function (e) {
                switch (e.which) {
                case 13: // enter
                    fnOk(e);
                    break;
                case 27: // escape
                    fnAbort(e);
                    break;
                }
            }
        );
        // bind abort
        input.bind("blur", fnAbort);
        // add to node
        $(node).empty().append(input);
        // focus input field
        input.focus();
        input.select();
    };

    var addRootFolder = configGetKey("modules.folder.tree") == 1;
    // Icon for adding new folders to the root level of the advanced tree when tree=1
    if (addRootFolder) {
        newFolderIcon = new ox.gui.Image().
        setSrc(getFullImgSrc("img/folder/newfolder.gif")).setTitle(_("New folder")).
        css({ verticalAlign: "middle", cursor: "pointer", marginLeft: "5px", marginTop: "4px" }).
        setVisible(false).
        setLayoutParam({ position: "left", width: 4 });
        
        // enable only when expertview is on
        ox.UIController.dispatcher.bind("expertchanged", function (e) {
           newFolderIcon.setVisible(e.enabled);
           newFolderIcon.layout.width = e.enabled ? "30px" : "4px"; // change width
           ox.widgets.sidepanel.title.paint(); // trigger paint
        });
    }
    
    // flat view
    (function () {
        
        /*
         * Context Menu
         * ------------------------------------------------------------------------------------
         */
        
        if (addRootFolder) {
            var rootMenu = new PulldownMenu(newFolderIcon.dom.node);
            rootMenu.getContext = constant({
                data: { id: 1 },
                widget: ox.widgets.sidepanelViews.folderTree
            });
        }
    
        globalContextMenus.newFolderType = new PopupMenu();
        
        var PIM = { calendar: 1, tasks: 1, contacts: 1, system: 1 };
        var mail = { mail: 1 };
        if (addRootFolder) {
            PIM["mail"] = 1;
            mail = PIM;
        }
        var items = {
            mail:      { name: _("E-Mail"),    when: mail },
            calendar:  { name: _("Calendar"),  when: PIM },
            tasks:     { name: _("Tasks"),     when: PIM },
            contacts:  { name: _("Contacts"),  when: PIM },
            infostore: { name: _("InfoStore"), when: { infostore: 1 } }
        };
        
        for (var i in items) (function(type) {
            function createHandler(context) {
                // Disable the default repaint and manually trigger it later.
                // This allows to specify a callback for the repaint.
                var widget = context.widget !== undefined ? context.widget : ox.widgets.sidepanelViews.folderTree;
                // unbind
                ox.api.folder.dispatcher.unbind("modify", widget.onModify);
                // create

                ox.api.folder.create({
                    folder: context.data.id,
                    data: { module: type },
                    success: function (data) {
                    	//widget can be simple view or tree view, so look for setOpen
                        if (widget.setOpen) {
                            widget.setOpen([ data.folder_id, data.id ]);
                        }
                        widget.repaint(function() {
                        	widget.selection.clickQuiet(data.id);
                        	widget.startEdit(data.id);
                        });
                    },
                    error: function () {
                        ox.api.folder.dispatcher.bind("modify", widget.onModify);
                    }
                });
            }
            var def = items[type];
            var key = "modules." + type + ".module";
            var item = new MenuItem(def.name, createHandler);
            item.onShow = function () {
                // get module
                if (ox.UIController.showExpertTree) {
                    // allow all types
                    this.setEnabled((this.getContext().type in def.when) && configGetKey(key));
                } else {
                    // allow current type only
                    this.setEnabled(type === ox.UIController.getModule());
                }
            };
            globalContextMenus.newFolderType.addItem(item);
            if (addRootFolder) {
                item = new MenuItem(def.name, createHandler);
                item.onShow = function() {
                    this.setEnabled(("system" in def.when) && configGetKey(key));
                };
                rootMenu.addItem(item);
            }
        })(i);
        
        var menu = new ContextMenu();
        
        // create global refs
        globalContextMenus.simpleFolderMenu = menu;
        
        // new folder
        var new_folder = new MenuItem(_("New folder"), globalContextMenus.newFolderType);
        new_folder.setIcon("img/folder/newfolder.gif", "img/folder/newfolder_d.gif");
        menu.addItem(new_folder);
        
        // send as link
        var link = new MenuItem(_("Send as link"), function (context) {
            // get folder first
            ox.api.folder.get({
                folder: context.data.id,
                success: function (data) {
                    // use global fn
                    infostore_sendLink([{ data: {
                        folder_id: data.id,
                        module: data.module
                    }}]);
                }
            });
        });
        menu.addItem(link);
        
        // subscribe
        var subscribe = new MenuItem(_("Subscribe folder"), function (context) {
            SubscribeFolder.openWindow();
        });
        menu.addItem(subscribe);
        
        // "Extended" (submenu)
        var extended = globalContextMenus.extended_folder_menu = new PopupMenu();
            // Import
            var import_data = new MenuItem(_("Import"), function (context) {
                ox.api.folder.get({
                    folder: context.data.id,
                    success: function (data) {
                        // set global var
                        importFolderDestination = data;
                        triggerEvent("OX_Switch_View", "configuration/import");
                    }
                });
            });
            extended.addItem(import_data);
            // Export (Submenu)
            var export_submenu = new PopupMenu();
                var export_submenu_ical = new MenuItem(_("iCalendar"),
                    function (ctx) {
                        ox.api.folder.exportContacts(ctx.data.id, "ICAL");
                    });
                export_submenu.addItem(export_submenu_ical);
                var export_submenu_vcard = new MenuItem(_("vCard"),
                    function (ctx) {
                        ox.api.folder.exportContacts(ctx.data.id, "VCARD");
                    });
                export_submenu.addItem(export_submenu_vcard);
                var export_submenu_csv = new MenuItem(_("CSV"), function (ctx) {
                    ox.api.folder.exportContacts(ctx.data.id, "CSV");
                });
                export_submenu.addItem(export_submenu_csv);
                var export_contact = new MenuItem(_("Export"), export_submenu);
                extended.addItem(export_contact);
        // add to menu
        menu.addItem( new MenuItem(_("Extended"), extended));
        
        // separator
        menu.addItem(new MenuSeparator());
        
        // delete
        var del = new MenuItem(_("Delete"), function (context) {
            removeFolder(context.data.id);
        });
        del.setIcon("img/menu/delete_folder.gif", "img/menu/delete_folder_d.gif");
        menu.addItem(del);
            
        // rename
        var rename = new MenuItem(_("Rename"), function (context) {
            // start edit
            context.widget.startEdit(context.data.id);
        });
        rename.setIcon("img/folder/renamefolder.gif", "img/folder/renamefolder_d.gif");
        menu.addItem(rename);
        
        var cut = new MenuItem(_("Cut"), function (context) {
            // cut node
            context.widget.cut(context.data.id);
        });
        cut.setIcon("img/folder/cutfolder.gif", "img/folder/cutfolder_d.gif");
        menu.addItem(cut);
        
        var paste = new MenuItem(_("Paste"), function (context) {
            ox.api.folder.get({
                folder: context.data.id,
                success: function(target) {
                    ox.api.folder.move(context.widget.cutNode.data, target);
                    context.widget.cut();
                }
            });
        });
        paste.setIcon("img/folder/pastefolder.gif", "img/folder/pastefolder_d.gif");
        menu.addItem(paste);
        
        var empty = new MenuItem(_("Empty folder"), function (context) {
            // clear folder
            var text = "Are you sure you want to delete all E-Mails from this folder? The deleted E-Mails will be moved to the Trash folder."; /*i18n*/
            // permanently delete message or is folder the trash folder?
            if (configGetKey("mail.deletemail") || (context.data.id == configGetKey("mail.folder.trash"))) {
                text = "Are you sure you want to permanently delete all E-Mails from this folder? The deleted E-Mails will be irrevocably lost."; /*i18n*/
            }
            function cbok () {
                // select folder to clear to avoid a removed subfolder still being selected
                ox.UIController.setFolder({
                    folder: context.data.id,
                    module: "default",
                    success: function () {
                        // clear folder now
                        ox.api.folder.clear(context.data.id, function () {
                            // update folder / sub folders
                            ox.api.http.pause();
                            ox.api.folder.get({
                                folder: context.data.id,
                                cache: false
                            });
                            ox.api.folder.getSubFolders({
                                folder: context.data.id,
                                cache: false
                            });
                            ox.api.http.resume(function () {
                                // trigger
                                triggerEvent("OX_Folder_Cleared", context.data.id);
                                // trigger modify
                                ox.api.folder.dispatcher.trigger("modify");
                            });
                        });
                    }
                });
            }
            newConfirm(_("Empty folder"),_(text),AlertPopup.YESNO,null,null,cbok,null,null);
          
        });
        empty.setIcon("img/folder/empty_folder.gif", "img/folder/propertiesfolder_d.gif");
        menu.addItem(empty);
        
        // separator
        menu.addItem(new MenuSeparator());
            
        var props = new MenuItem(_("Properties"), function (context) {
            ox.api.folder.viewProperties(context.data.id, false);
        });
        props.setIcon("img/folder/propertiesfolder.gif", "img/folder/propertiesfolder_d.gif");
        menu.addItem(props);
        
        menu.onShow = function (context) {
            // get context
            var id = context.data.id, api = ox.api.folder;
            // get folder
            api.get({
                folder: id, 
                success: function (folder) {
                
                    // new folder
                    new_folder.setEnabled((folder.own_rights & 127) >= 4);
                    
                    // module system and name default is the parent root mail folder
                    context.type = api.is("account", folder) ? "mail": folder.module;
                    
                    // subscribe
                    subscribe.setVisible(api.is("mail", folder));
                    
                    // send link (anything but system and mail)
                    link.setEnabled(folder.own_rights & (127 << 7) && folder.module != "mail" && ("infostore_sendLink" in window));
                    link.setVisible(!api.is("system", folder) && context.type !== "mail");
                    
                    // delete
                    del.setEnabled(api.can("delete", folder));
                    
                    // rename
                    rename.setEnabled(api.can("rename", folder));
                    
                    cut.setVisible(context.widget.cut !== undefined);
                    if (cut.visible) {
                        cut.setEnabled(del.enabled &&
                            (!context.widget.cutNode ||
                                context.widget.cutNode.id != id));
                    }
                    
                    paste.setVisible(context.widget.cut !== undefined);
                    if (paste.visible) {
                        paste.disable();
                        if (context.widget.cutNode) {
                            api.canMove(context.widget.cutNode.data, folder,
                                function() { paste.enable(); },
                                function() { paste.disable(); });
                        }
                    }
                    
                    // empty
                    empty.setVisible(api.can("empty", folder));
                    
                    // import
                    import_data.setEnabled(api.can("import", folder));
                    
                    // export
                    export_contact.setEnabled(api.can("export", folder));
                    export_submenu_ical.setVisible(api.is("calendar", folder));
                    export_submenu_vcard.setVisible(api.is("contacts", folder));
                    export_submenu_csv.setVisible(api.is("contacts", folder));
                }
            });
        };
        
        /*
         * Tree views
         * ------------------------------------------------------------------------------------
         */
        ox.gui.TypedFolderTree = ox.gui.Tree.extend({
            
            construct: function (id, options) {
            
                // super constructor
                ox.gui.Tree.prototype.construct.call(this, id);
                
                // options
                this.options = $.extend({
                    type: "mail",
                    icon: "mail.gif",
                    root: "1",
                    tree: ox.api.config.get("modules.folder.tree", "0"),
                    showRootNode: false,
                    loadRootNode: false
                }, options || {});

                this.css({ padding: "10px 0px 10px 0px" });
                
                this.firstPaint = true;

                // show root node
                this.showRootNode = this.options.showRootNode;
                this.loadRootNode = this.options.loadRootNode;
                this.loadRootNodeId = this.options.root;

                var TYPE = this.options.type;
                var self = this;
            
                // node parser
                this.setNodeParser(function (data) {
                    return { 
                        "id": data.id, "parent": data.folder_id, "name": data.title, 
                        "type": data.module, "hasChildren": data.subfolders
                    };
                });
                
                this.addListener("widget:select", function(e) {
                    var api = ox.api.folder;
                    // get folder data
                    api.get({
                        folder: e.data,
                        success: function (data) {
                            // not system?
                            if (api.is(TYPE, data) && api.can("read", data)) {
                                // change folder
                                ox.UIController.setFolder({ folder: data.id });
                            }
                        }
                    });
                });
                
                this.selection.onRename(function (id, item) {
                    // get folder
                    ox.api.folder.get({
                        folder: id, 
                        success: function (data) {
                            // can rename?
                            if (ox.api.folder.can("rename", data)) {
                                // start edit
                                self.startEdit(id);
                            }
                        }
                    });
                });
                
                this.addListener("widget:edited", function (e) {
                    // update folder
                    ox.api.folder.update({
                        folder: e.data.id,
                        data: {
                            title : e.data.value
                        },
                        success: function (data) {
//                            // remove folder
//                            self.remove(e.data.id);
//                            // add updated folder
//                            self.add(data);
//                            self.repaint();
//                            // select
//                            self.selection.select(data.id);
                            // continue
                            ox.util.call(e.cont);
                        },
                        error : function () {
                            // repaint
                            self.repaint();
                            // select
                            self.selection.select(e.data.id);
                            // continue
                            ox.util.call(e.cont);
                        }
                    });
                    return false;
                });
                
                this.customize = function (node) {
                    
                    var data = node.data, api = ox.api.folder, id;
                    var name = data.title;
                    
                    // clear all custom styles
                    $(node.dom.title).parent().css({ fontWeight: "" }).
                        removeClass("font-color-disabled font-style-low");
                    $(node.dom.icon).css({ backgroundImage: "" });
                    
                    // add style
                    var processUnread = function (meta) {
                        if (data.unread !== null && data.unread > 0) {
                            $(node.dom.title).parent().css({ fontWeight: "bold" });
                            meta.name = meta.name;
                            meta.html = meta.name + " (" + data.unread + ")";
                        }
                        return meta;
                    };
                    
                    // top folder?
                    if (data.folder_id === this.options.root && this.options.tree === 0) {
                        src = this.options.icon;
                    } 
                    else {
                        var src = "folder_closed" /* default icon */, accountId, a = {};
                        // get account id
                        accountId = /^default(\d*)\b/.exec(data.id);
                        if ($.isArray(accountId)) {
                            // default0?
                            if (accountId[1] === "0") {
                                // use config
                                var f = config.mail.folder;
                                a.inbox_fullname = f.inbox;
                                a.trash_fullname = f.trash;
                                a.sent_fullname = f.sent;
                                a.drafts_fullname = f.drafts;
                                a.spam_fullname = f.spam;
                            } else {
                                // get account data from cache
                                a = ox.api.cache.account.get(accountId[1]);
                                // unified inbox, e.g. behaves like an account but is not
                                if (!a) {
                                    id = "default" + accountId[1];
                                    a = {
                                        inbox_fullname: id + "/INBOX",
                                        trash_fullname: id + "/Trash",
                                        sent_fullname: id + "/Sent",
                                        drafts_fullname: id + "/Drafts",
                                        spam_fullname: id + "/Spam"
                                    };
                                }
                            }
                        }
                        
                        // special mail folder?
                        switch (data.id) {
                        case a.inbox_fullname: src = "inbox.gif"; break;
                        case a.trash_fullname: src = "garbage.gif"; break;
                        case a.sent_fullname: src = "outbox.gif"; break;
                        case a.drafts_fullname: src = "draft.gif"; break;
                        case a.spam_fullname: src = "spam.gif"; break;
                        case a.confirmed_ham_fullname: src = "ham.gif"; break;
                        case a.confirmed_spam_fullname: src = "spam.gif"; break;
                        default:
                            // normal mail folder
                            // can read?
                            if ((api.is("system", data) || api.can("read", data)) && node.isCut !== true) {
                                // ok
                                
                                src = node.statusOpen ? "folder_opened.gif" : "folder_closed.gif";
                                $(node.dom.title.parentNode).removeClass(
                                    "font-color-disabled");
                            } else {
                                // cannot read
                                src = node.statusOpen ? "folder_opened_dis.gif" : "folder_closed_dis.gif";
                                $(node.dom.title.parentNode).addClass(
                                    "font-color-disabled");
                            }
                        }
                    
                        // tweaking infostore icons
                        switch (data.module) {
                            case "infostore":
                                if (data.folder_id === "10"){
                                    src = "user";
                                }else{
                                    src = "infostore";
                                }
                                // can read?
                                if (!api.can("read", data)) {
                                    // don't visually change system folders
                                    if (data.folder_id === "1") {
                                        src = src + "_dis.gif"; // disable symbol
                                        $(node.dom.title.parentNode).addClass("font-color-disabled font-style-low"); // gray italic
                                    } else {
                                        src = src + ".gif";
                                    }
                                    node.selectable = false;
                                } else {
                                    src = src + ".gif";
                                    node.selectable = true;
                                }
                                break;
                        }
                        
                        // mark published folders
                        if (ox.api.folder.is("published", data)) {
                            // add shared symbol to original
                            $(node.dom.icon).css({ backgroundImage: "url(" + ox.gui.themePath + "img/folder/" +src+ ")" });
                            src = "shared.png";
                        }
                    }
                    
                    if (data.id === "default0") {
                         // replace with user name
                         var user = internalCache.getUsers([config.identifier]);
                         if (user && user[config.identifier]) {
                             name = user[config.identifier].display_name;
                         }
                    }
                    
                    return processUnread({
                        src: ox.gui.themePath + "img/folder/" + src,
                        name: name
                    });
                };
                
                this.selection.classSelected = "background-color-PMG-selection-elements";
                
                var fnToggle = function () {
                    // get id
                    var ID = this.id + "/" + ox.api.config.get("modules.folder.tree", 0);
                    // loop over open nodes
                    var state = {};
                    $.each(self.getOpen(), function (i, id) {
                        state[id] = true;
                    });
                    // update user config
                    configSetKey(["gui", "tree", ID, "state"], state);
                };
                this.addListener("widget:open", fnToggle);
                this.addListener("widget:close", fnToggle);
                
                // click handler
                this.selection.setClickHandler(function (e) {
                    
                    // context menu?
                    if (e.event.which === 3) {
                        // tracking
                        track({
                            type: "ContextMenu/Tree",
                            id: e.id,
                            text: "Right click on folder " + e.id
                        });
                        // process
                        e.click("quiet");
                        e.context();
                    } else if (e.selectable === true) {
                        // viewing properties?
                        if (currentpath[0] === "configuration") {
                            // change back to folder's module
                            ox.UIController.setFolder({
                                folder: e.id,
                                module: "default"
                            });
                        } else {
                            // normal click
                            // track
                            ox.api.folder.get({
                                folder: e.id,
                                success: function (data) {
                                    track({
                                        type: "ContextMenu/Tree",
                                        id: e.id,
                                        text: "Select " + data.module + " folder \"" + data.title + "\" (" + e.id + ")"
                                    });
                                }
                            });
                            // process
                            if (ox.UIController.getFolder() !== e.id) {
                                e.click("force");
                            } else {
                                e.click();
                            }
                        }
                    }
                    
                    // prevent default
                    return false;
                });
                
                // context menu
                this.selection.setContextMenuHandler(function (id, e) {
                    // show folder context menu
                    var menu = globalContextMenus.simpleFolderMenu;
                    menu.display(e.pageX, e.pageY, {
                        data: { id: id }, 
                        api: true, 
                        simple: true,
                        module: TYPE,
                        widget: self
                    });
                });
                
                // add root node?
                if (this.loadRootNode === false) {
                    this.setRootNode({ id: this.options.root, folder_id: null, title: "Root", module: "root", subfolders: true });
                }
                
                this.onModify = function (data) {

                    // close invalid nodes
                    if (data.why === "folder.remove" || data.why === "folder.move") {
                        // is mail?
                        if (ox.api.folder.is("mail", data.folder)) {
                            // get id
                            var key = data.oldId;
                            // close invalid nodes
                            $.each(ox.util.keys(self.openNodes), function (i, id) {
                                if ((new RegExp("^" + key)).test(id)) {
                                    // get tree node
                                    var node = self.get(id);
                                    if (node) {
                                        node.close();
                                    }
                                }
                            });
                        }
                        // unset current folder
                        ox.UIController.unsetFolder();
                    }
                    
                    if (data.why === "folder.update.local") {
                        // repaint affected node only
                        var node = self.get(data.id);
                        if (node) {
                            node.repaint();
                        }
                    } else {
                        // repaint full tree
                        if (data.why === "folder.move") {
                            ox.UIController.setFolder({
                                folder: data.id,
                                module: "default",
                                success: function () {
                                    self.repaint();
                                }
                            });
                        } else {
                            self.repaint();
                        }
                    }
                };
            },
            
            loadChildren: function (id, cont) {
                // step #2: get sub folders
                var self = this;
                var type = this.options.type;
                var regex = /^default/;
                var getFolders = function () {
                    ox.api.folder.getSubFolders({
                        folder: id,
                        tree: ox.api.config.get("modules.folder.tree", "0"),
                        success: function (data) {
                            // mail only
                            data = $.grep(data, function (elem, i) {
                                if (type === "mail") {
                                    return regex.test(elem.id) === true && (elem.subscribed === true || elem.subscr_subflds === true) && (elem.module === "mail" || elem.module === "system");
                                } else {
                                    return (elem.subscribed === true || elem.subscr_subflds === true) && (elem.module === type || elem.module === "system");
                                }
                            });
                            cont(data);
                        },
                        error: function () {
                            cont(false);
                            // return true; // prevent global error reporting
                        }
                    });
                };
                // step #1: get accounts (cached after first request)
                ox.api.account.all(getFolders);
            },
            
            loadNode: function (id, cont) {
                // get single folder
                var self = this;
                ox.api.folder.get({
                    folder: id,
                    tree: ox.api.config.get("modules.folder.tree", "0"),
                    success: function (data) {
                        ox.util.call(cont, data);
                    }
                });
            },
            
            // prevent flicker
            clear: function () {
            },
            
            expandToFolder: function (folderID) {
                
                // get open nodes
                var open = this.getOpen();
                
                // this
                var self = this;
                
                var getParentIDs = function (data, callback) {
                    // loop over folder
                    var i = 1, $l = data.length, list = [], id;
                    for (; i < $l; i++) {
                        id = data[i].id;
                        // not already open?
                        if ($.inArray(id, open) === -1) {
                            list.push(id);
                        }
                    }
                    callback(list);
                };
                
                var expandTreeNodes = function (list) {
                    
                    // need repaint?
                    if (list.length > 0) {
                        // yes
                        self.setOpen(list);
                        self.repaint(function () {
                            self.selection.clickQuiet(folderID);
                        });
                    } else {
                        // no, select directly
                        self.selection.clickQuiet(folderID);
                    }
                };
                
                // get all parents of folder via api
                ox.api.folder.getParents({
                    folder: folderID,
                    success: function (data){
                        getParentIDs(data, expandTreeNodes);
                    }
                });
            },
            
            paint: function (cont) {

                if (this.painter.running === false) {
                    
                    this.painter.running = true;
                    
                    // first paint?
                    if (this.firstPaint === true) {
                        // get folder state id
                        var ID = this.id + "/" + ox.api.config.get("modules.folder.tree", 0);
                        // get open folders
                        if (configContainsKey(["gui", "tree", ID, "state"])) {
                            this.setOpen(ox.util.keys(configGetKey(["gui", "tree", ID, "state"])));
                        } else {
                            this.setOpen(this.options.open || []);
                        }
                        // visually busy
                        $(this.dom.node).css({ background: "" }).addClass("oxBusySmall");
                        // done
                        this.firstPaint = false;
                    }
                    
                    // unbind
                    ox.api.folder.dispatcher.unbind("modify", this.onModify);
                    
                    // this
                    var self = this;
                    
                    // continuation
                    var step2 = function () {
                        // get ids of open nodes (exclude external accounts)
                        var list = $.grep(ox.util.keys(self.openNodes), function (key) {
                            return /^(\d+|default0)/.test(key);
                        });
                        // pause
                        ox.api.http.pause();
                        var pssst = function () {
                            return true; // prevent global error
                        };
                        // loop
                        var i = 0, $l = list.length;
                        for (; i < $l; i++) {
                            ox.api.folder.getSubFolders({
                                folder: list[i],
                                tree: self.options.tree,
                                error: pssst
                            });
                        }
                        // resume
                        ox.api.http.resume(
                            function () {
                                // paint
                                $(self.dom.node).empty().removeClass("oxBusySmall");
                                self.painter.running = false;
                                ox.gui.Tree.prototype.paint.call(self, function () {
                                    // clear open nodes hash
                                    self.openNodes = {};
                                    // select id
                                    if (self.selection !== undefined) {
                                        self.selection.preselect(currentFolder); // before paint
                                        self.selection.clickQuiet(currentFolder); // after paint
                                    }
                                    // bind
                                    ox.api.folder.dispatcher.bind("modify", self.onModify, window);
                                    // continue
                                    ox.util.call(cont);
                                });
                            },
                            pssst
                        );
                    };
                    
                    // consider current folder (not in nested windows)
                    var currentFolder = ox.UIController ? ox.UIController.getFolder() : undefined;
                    if (currentFolder !== undefined) {
                        // get path
                        ox.api.folder.getParents({
                            folder: currentFolder,
                            tree: this.options.tree,
                            success: function (data) {
                                // remove current folder
                                data.shift();
                                // get ids
                                var list = $.map(data, function (folder) {
                                    return folder.id;
                                });
                                // leads to root folder?
                                if ($.inArray(self.options.root, list) > -1) {
                                    // mark as open
                                    self.setOpen(list);
                                }
                                // continue
                                step2();
                            }
                        });
                    } else {
                        // continue
                        step2();
                    }
                } else {
                    this.painter.queue.push(cont);
                }
            }
        });
        
        /*
         * Mail folder tree
         */
        var tree = ox.api.config.get("modules.folder.tree", 0);
        
        v.mail = new ox.gui.Container("ox-sidepanel-mail").
        setLayout(new ox.gui.BorderLayout());
        	
        var mail_tree = ox.widgets.sidepanelViews.mailTree = new ox.gui.TypedFolderTree("ox-sidepanel-mail-tree", {
            type: "mail",
            icon: "mail.gif",
            root: "1",
            tree: tree,
            open: ["default0"]
        }).setLayoutParam({ position: "center" });
        
        mail_tree.enableDnD(ox.gui.initSidepanel.dndSource, ox.gui.initSidepanel.dndTarget);

        v.mail.add(mail_tree);
        
        
        /*
         * Infostore folder tree
         */
        v.infostore = new ox.gui.Container("ox-sidepanel-infostore").
        setLayout(new ox.gui.BorderLayout()); 
        	
        var infostore_tree = ox.widgets.sidepanelViews.infostoreTree = new ox.gui.TypedFolderTree("ox-sidepanel-infostore-tree", {
            type: "infostore",
            icon: "infostore.gif",
            root: "9",
            open: ["9", "10", ox.api.config.get("folder.infostore")]
        }).setLayoutParam({ position: "center" });
        infostore_tree.enableDnD(ox.gui.initSidepanel.dndSource, ox.gui.initSidepanel.dndTarget);
        
        v.infostore.add(infostore_tree);
        
        /*
         * Flat views
         * ------------------------------------------------------------------------------------
         */
        var flatView = ox.gui.Custom.extend({
            
            construct: function (paint, id, module) {

                // super constructor
                ox.gui.Custom.prototype.construct.call(this, paint, id);

                // module
                this.module = module;
                this.folders = {};
                
                var self = this;
                
                // selection
                var s = this.selection = new ox.gui.Selection();
                s.setMultiple(false);
                s.setNodeFinder(function () {
                    return $(".ox-sidepanel-flat-folder", this.container);
                });
                s.classSelected = "background-color-PMG-selection-elements";
                s.onChange(function (items) {
                    if (self.isVisible() && items.length) {
                        setTimeout(function () {
                            // change folder
                            ox.UIController.setFolder({ folder: items[0].id });
                        }, 10);
                    }
                });
                s.onRename(function (id, item) {
                    // get folder
                    ox.api.folder.get({
                        folder: id,
                        success: function (data) {
                            // can rename?
                            if (ox.api.folder.can("rename", data)) {
                                // start edit
                                self.startEdit(id);
                            }
                        }
                    });
                });
                s.observe(self.dom.node, "ox-sidepanel-view-wrapper");
                
                // click handler
                s.setClickHandler(function (e) {
                    
                    // context menu?
                    if (e.event.which === 3) {
                        // event
                        track({
                            type: "ContextMenu/FlatView",
                            where: self.id,
                            id: e.id,
                            text: "Right click on folder " + e.id
                        });
                        // process
                        e.click("quiet");
                        e.context();
                    } else if (e.selectable === true) {
                        // viewing properties?
                        if (currentpath[0] === "configuration") {
                            // change back to folder's module
                            ox.UIController.setFolder({
                                folder: e.id,
                                module: "default"
                            });
                        } else {
                            // normal click
                            // track
                            ox.api.folder.get({
                                folder: e.id,
                                success: function (data) {
                                    track({
                                        type: "ContextMenu/Tree",
                                        id: e.id,
                                        text: "Select " + data.module + " folder \"" + data.title + "\" (" + e.id + ")"
                                    });
                                }
                            });
                            // process
                            if (ox.UIController.getFolder() !== e.id) {
                                e.click("force");
                            } else {
                                e.click();
                            }
                        }
                    }
                    
                    // prevent default
                    return false;
                });
                
                s.setContextMenuHandler(function (id, e) {
                    // show folder context menu
                    var menu = globalContextMenus.simpleFolderMenu;
                    menu.display(e.pageX, e.pageY, {
                        data: { id: id }, 
                        api: true, 
                        simple: true,
                        module: module,
                        widget: self
                    });
                });
                
                this.addListener("widget:edited", function (e) {
                    // update folder
                    ox.api.folder.update({
                        folder: e.data.id,
                        data: { title: e.data.value },
                        success: function(data) {
                            ox.api.cache.folderFlat.remove(data.module);
                            // select
                            self.selection.select(data.id);
                            // continue
                            ox.util.call(e.cont);
                        },
                        error : function() {
                            // repaint
                            self.paint();
                            // select
                            self.selection.select(e.data.id);
                            // continue
                            ox.util.call(e.cont);
                        }
                    });
                    return false;
                });
                
                // track visibility
                this.addListener("widget:invisible", function () {
                    s.disable();
                });
                this.addListener("widget:visible", function () {
                    s.enable();
                });
                
                // set class now (IE7 issues; flickering scrollbar)
                $(this.dom.node).addClass("ox-sidepanel-view");
                
                this.onModify = function () {
                    // repaint on changes
                    self.repaint();
                };
            }
        });
        
        flatView.prototype.startEdit = function (id) {
            // get
            if (this.folders[id] !== undefined) {
                
                var self = this;
                
                // unbind
                ox.api.folder.dispatcher.unbind("modify", this.onModify);
                
                var success = function (value) {
                    // trigger event
                    self.trigger(
                        "widget:edited",
                        {
                            node: self,
                            id: id,
                            value: value
                        },
                        function () {
                            // repaint (enables selection)
                            self.repaint();
                        }
                    );
                };
                
                var abort = function () {
                    // repaint (enables selection)
                    self.repaint();
                };
                
                var node = this.folders[id].node;
                ox.gui.util.inlineEdit.call(this, node, node.data("title"), success, abort);
            }
        };
        
        var sections = {
            "private": {
                title: _("Private folders")
            },
            "public": {
                title: _("Public folders")
            },
            "shared": {
                title: _("Shared folders")
            }
        };
        
        // "Global address book"
        
        var paintFlatView =  function (cont) {
        
            var self = this;
            
            // unbind
            ox.api.folder.dispatcher.unbind("modify", this.onModify);
            
            function addDnD(folder, node, out) {
                if (self.dndSource) {
                    self.dndSource(folder, function (type, callback) {
                        out.dndSource = registerSource(node, type, callback,
                            null, null, foldertreedisable, defaultdisabledremove);
                    });
                }
                if (self.dndTarget) {
                    self.dndTarget(folder, function (callbacks) {
                        var cbs = {};
                        for (var i in callbacks) {
                            cbs[i] = (function (cb) {
                                return function (a, b, c, d, e, f) {
                                    legacyOut(a, b, c, d, null, f);
                                    cb(a, b, c, d, e, f);
                                };
                            })(callbacks[i]);
                        }
                        out.dndTarget = registerTarget(node, cbs, null, null,
                            legacyIn, legacyIn, legacyOut, true);
                    });
                }
                function legacyIn(e, type, objects, position, targetNode) {
                    foldertreeenable(e, type, objects, position, targetNode, folder);
                    var mynode = e.currentTarget || e.srcElement || false;
                    if (!mynode.className.match(/dndOver/)) {
                        mynode.className += " dndOver";
                    }
                }
                function legacyOut(e, type, objects, position, OutOpen, dropNode) {
                    if (dropNode) {
                        dropNode.className = removeClass(dropNode.className, "dndOver");    
                    } else if (e) {
                        var mynode = e.currentTarget || e.srcElement || false;
                        if (mynode) {
                            mynode.className = removeClass(mynode.className, "dndOver");  
                        }
                    }
                }
            }
            
            var paintFolders = function (folders, node) {
                
                // sort by title, default folder always first
                var id = String(ox.api.config.get("folder."+ self.module));
                folders.sort(function (a, b) {
                    return a.id === id ? -1 : a.title > b.title ? +1 : -1;
                });
                // add owner
                var addOwner = function (folder, node) {
                    if (ox.api.folder.is("shared", folder)) {
                        ox.api.folder.derive("owner", folder, function (data) {
                            node.append("<br/>");
                            node.append(
                                $("<span/>").css({ color: "#666", fontStyle: "italic" }).
                                    text("(" + data.display_name + ")")
                            );
                        });
                    }
                };
                // loop
                var i = 0, $l = folders.length, folder, div, count = 0;
                for (i = 0; i < $l; i++) {
                    // get
                    folder = folders[i];
                    // read permisssion?
                    if (ox.api.folder.can("read", folder)) {
                        var img = $("<img/>").attr({ src: meta[self.module].icon }).
                        css({ backgroundRepeat: "no-repeat", position: "absolute", left: "3px" });
                        if (ox.api.folder.is("published", folder)) {// published folders
                            // add shared symbol to original
                            img.css({"background-image" : "url(" + img.attr("src") + ")" });
                            img.attr("src", ox.gui.themePath + "img/folder/shared.png");
                        }
                        
                        // add nodes
                        node.append(
                            // div
                            div = $("<div/>", { oxID: folder.id }).
                                data("title", _(folder.title || "")).
                                addClass("ox-sidepanel-flat-folder").
                                css({ position: "relative" }).
                            append(img).
                            // folder name
                            append(
                                $("<span/>").text(folder.title || "")
                            )
                        );
                        // add owner?
                        addOwner(folder, div);
                        // add to index
                        var out = self.folders[folder.id] = {
                            id: folder.id,
                            node: div
                        };
                        // support DND
                        addDnD(folder, div[0], out);
                        // count
                        count++;
                    }
                }
                return count;
            };
            
            setTimeout(function () {
            
                // clear
                for (var i in self.folders) {
                    f = self.folders[i];
                    if (f.dndSource) unregisterSource(f.node[0], f.dndSource);
                    if (f.dndTarget) unregisterSource(f.node[0], f.dndTarget);
                    delete self.folders[i];
                }
                
                $(self.dom.node).empty();
                
                // add spinner
                if (!ox.browser.IE) { // IE7 flicker issue
                    $(self.dom.node).addClass("busy-spinner-white");
                }
                
                // get visible folders via API (flat list)
                ox.api.folder.getAllVisible(self.module, function (data) {
                        
                    // remove spinner
                    if (!ox.browser.IE) { // IE7 flicker issue
                        $(self.dom.node).removeClass("busy-spinner-white");
                    }
                    
                    // add sections
                    for (var id in sections) {
                        $(self.dom.node).append(
                            self.dom[id] = $("<div/>").addClass("ox-sidepanel-section").append(
                                $("<div/>").addClass("ox-sidepanel-section-title").append(
                                    addTranslated(meta[self.module].sections[id])
                                )
                            )
                        );
                        // paint folders
                        var count = paintFolders(data[id] || [], self.dom[id]);
                        // remove section?
                        if (count === 0) {
                            self.dom[id].remove();
                        }
                    }
                    
                    // enable selection
                    self.selection.enable();
                    self.selection.update();
                    self.selection.clickQuiet(ox.UIController.getFolder());
                    
                    // bind to folder api
                    ox.api.folder.dispatcher.bind("modify", self.onModify, window);
                    
                    // continuation
                    ox.util.call(cont);
                });
                
            }, 10);
        };

        // No source, since dragging folders without hierarchy makes no sense
        flatView.prototype.dndTarget = ox.gui.initSidepanel.dndTarget;
        
        // calendar
        v.calendar = new flatView(paintFlatView, "ox-sidepanel-calendar", "calendar");
        
        // contacts
        v.contacts = new flatView(paintFlatView, "ox-sidepanel-contacts", "contacts");
        
        // tasks
        v.tasks = new flatView(paintFlatView, "ox-sidepanel-tasks", "tasks");
        
    }());
    
    
    /*
     * Module title
     */
    var title = ox.widgets.sidepanel.title = new ox.gui.Container("ox-sidebar-title").
    setLayout(new ox.gui.BorderLayout()).
    css({ height: "26px" }).
    setLayoutParam({ position: "top", height: 27 }).
    addCSSClass("ox-sidepanel-title topheader-color").
    addTo(sidepanel).
    add(
        new ox.gui.Custom(
            function () {
                $(this.dom.node).empty().
                    append(addTranslated(this.title));
            },
            "ox-sidepanel-title"
        ).
        setLayoutParam({ position: "center" }).
        css({ marginLeft: "6px" }).
        addListener("widget:viewchanged", view, function (e) {
            // make sure folder & config are shown
            $("#folder_tree").show();
            // change title
            var match = e.data.id.match(/(\w+)$/);
            this.title = meta[match[1]].title;
            this.paint();
        })
    ).add(
            new ox.gui.Image().
            css({ cursor: "pointer" }).
            addCSSClass("sp-toggle-img").
            setLayoutParam({ position: "right", width: 13 }).
            setSrc(getFullImgSrc("img/arrows/arrow_double_white_left.gif")).
            setTitle(_("Collapse sidepanel")).
            addListener("click", function (e) {
                ox.widgets.sidepanel.toggle();
                ox.widgets.sidepanel.userToggle = true;
            })
    );
    
    // add new folder image only if required
    if (addRootFolder) {
        title.insert(newFolderIcon, 0);
    }
    
    // add view to sidepanel
    sidepanel.add(view);
    
    /*
     * Module views
     */
    v.portal = new ox.gui.Widget("ox-sidepanel-portal").addTo(view);
    v.mail.addTo(view);
    v.calendar.addTo(view);
    v.contacts.addTo(view);
    v.tasks.addTo(view);
    v.infostore.addTo(view);
    v.folder = new ox.gui.Container("ox-sidepanel-foldertree").addTo(view).
        setLayout(new ox.gui.BorderLayout());
    
    
    //--- quota 
    
    var quotaContainer = { mail: [], filestore: [] }, quotaReq = [];
    
    // Since all bars are needed twice - in the simple and in the expert view -
    // the bars are created by functions.

    function createMailBars(container, qContainer) {
        // store to widgets container for public access
        if (!ox.widgets.sidepanel.quota) {
            ox.widgets.sidepanel.quota = {};
        }
        var bar = ox.widgets.sidepanel.quota.mail = new ox.gui.Bar({ textFormat: function(used, max) {
            return bytesToString(used) + " / " + bytesToString(max);
        }, title: function(used, max) { 
            return _("E-Mail") + " " + bytesToString(used) + " / " +
                   bytesToString(max);
        } }).
            setLayoutParam({ position: "bottom", height: 18 }).hide();
        container.add(bar);
        
        var bar2 = ox.widgets.sidepanel.quota.infostore= new ox.gui.Bar({ textFormat: "fraction" }).
            setLayoutParam({ position: "bottom", height: 18 }).hide();
        container.add(bar2);
        
        qContainer.push({ id: "mail_storage",
            field_map: { usage:"use", quota:"quota" }, bar: bar });
        qContainer.push({ id: "mail_count",
            field_map: { usage:"countuse", quota:"countquota" }, bar: bar2 });
    }
    
    function createInfoStoreBars(container, qContainer) {
        var bar = new ox.gui.Bar({ textFormat: function(used, max) {
            return bytesToString(used) + " / " + bytesToString(max);
        }, title: function(used, max) { 
            return _("Infostore") + " " + bytesToString(used) + " / " +
                   bytesToString(max);
        } }).
            setLayoutParam({ position: "bottom", height: 18 }).hide();
        container.add(bar);
        
        qContainer.push({ id: "filestore",
            field_map: { usage:"use", quota:"quota" }, bar: bar });
    }
    
    // register quota bars for available modules
    if (ox.api.config.get("modules.mail.module")) {
        createMailBars(v.mail, quotaContainer.mail);
        createMailBars(v.folder, quotaContainer.mail);
        quotaReq.push({ module:"quota", action: "mail" });
    }
    
    if (ox.api.config.get("modules.infostore.module")) {
        createInfoStoreBars(v.infostore, quotaContainer.filestore);
        createInfoStoreBars(v.folder, quotaContainer.filestore);
    	quotaReq.push({ module:"quota", action: "filestore" });
    }
    
    
    // fetches quota from the back-end
    function checkQuota() {    	
    	// helper to remove quota object with given ID from container
    	function removeFromContainer(id) {
    		for (var i in quotaContainer) {
                for (var ia in quotaContainer[i]) {
                    if (quotaContainer[i][ia].id == id) {
                    	if (quotaContainer[i][ia].bar) {
                    		var parent = quotaContainer[i][ia].bar.parent;
                    		quotaContainer[i][ia].bar.destroy();
                    		//ox.widgets.sidepanelViews.mail.validate();
                    		parent.validate();
                    	}
                        delete(quotaContainer[i][ia]);
                    }
                }
            }
    	}

    	// fire put
    	ox.api.http.PUT({
            module: "multiple",
            data: quotaReq,
            appendColumns: false,
            success: function (data) {
    			// now its gonna be tricky
    			// iterate through server results
	    		for (var i=0; i < data.length; i++) {
	    			// iterate through container
	                for (ia in quotaContainer[quotaReq[i].action]) {
	                	// getting quota object mapped to results
	                	var quota = quotaContainer[quotaReq[i].action][ia];
	                	if (!quota) continue;
	                	// no results for this request? remove it!
	                	if (data[i] == undefined || data[i].data == undefined) {
	             		   removeFromContainer(quota.id);
	                 	   continue;
	                    }
	             	   	// getting quota information (count and usage)
	                    var tQuota = data[i].data[quota.field_map.quota];
	                    var tUsage = data[i].data[quota.field_map.usage];
	                    // no results for this request? remove it!
	                    if (tQuota == undefined || tQuota == -1024 || tQuota == -1) {
	                    	removeFromContainer(quota.id);
	                        continue;
	                    }
	                    // store quota information to container
	                    quota.data = { quota: tQuota, usage: tUsage };
	                    
	                    // paint
	                    quota.bar.setMax(tQuota);
	                    quota.bar.progress(tUsage);
	                    if (quota.bar.isVisible() == false) { 
	                        quota.bar.show();
	                    }
	                }
	            }
        	}
    	});
    };
    // receive information the first time
    checkQuota();
    // update quota information on refresh
    register("OX_Refresh", checkQuota);
    
    
    //--- mini-cal   
    
    ox.widgets.miniCalendar = new ox.gui.Custom(
            function () {
                var Self = this;
                $(this.dom.node).empty().addClass("oxStretch");
                
                this.hide = function() {
                	this.setVisible(false);
                	Self.layout.height = 0;
                    Self.invalidate();
                    ox.widgets.sidepanel.validate();
                };
                
                this.show = function() {
                    // disabled means not visible at all
                    if (this.isEnabled() === false) {
                        return;
                    }
                	this.setVisible(true);
                	Self.layout.height = (Self.toggled ? (2*pxPerEm) : (13*pxPerEm));
                	Self.invalidate();
                	ox.widgets.sidepanel.validate();
                };
                
                this.toggle = function(state) {
                    // disabled means not visible at all
                    if (this.isEnabled() === false) {
                        return;
                    }
                	Self.toggled = !Self.toggled; 
                	if (typeof state == "boolean") {
                		Self.toggled = state;
                	}
                    $("img.mini-toggle", Self.dom.node).attr("src",
                            getFullImgSrc("img/" + (Self.toggled ? "plus.gif" : "minus.gif")));
                    
                    Self.layout.height = (Self.toggled ? (2*pxPerEm) : (13*pxPerEm));
                    
                    Self.invalidate();
                    ox.widgets.sidepanel.validate();
                };
                
                var content = $("<div/>").
                    css({ height: "11.3em", width: "18em", overflow: "hidden", position: "absolute"}).
                    append($("<div/>").attr("id", "mini-content").addClass("calminimainCSS"));
                
                var header = $("<table/>").addClass("headercontenttable border-color-design").
                    css({ height: "2em", backgroundImage: "url('" + getFullImgSrc("img/toolbar/toolbar30.png") + "')" }).
//                    bind("mousedown", function(event) {
//                    	// toggle mini-cal when clicking on the header (e.g. year selection)
//                    	if (ox.widgets.miniCalendar.toggled) {
//                    	    ox.widgets.miniCalendar.userToggle = false;
//                    		ox.widgets.miniCalendar.toggle();
//                    	}
//                    }).
                    append(
                            $("<tr/>").append(
                                    $("<td/>").css({ width: "50%" }).text(" ")
                            ).append(
                                    $("<td/>").attr("align", "right").css({ cursor: "pointer", width: "10px" }).
                                    append($("<img/>").attr("src", getFullImgSrc("img/arrows/arrow_darkgrey_left.gif"))
                                    ).bind("click", function() {
                                        oMiniCalendar.back(1);
                                    })
                            ).append(
                                    $("<td/>").attr("align", "center").append(
                                            $("<div/>").addClass("mini-month").attr("id", "mini-month")
                                    )
                            ).append(
                                    $("<td/>").attr("align", "left").css({ cursor: "pointer", width: "10px" }).
                                    append($("<img/>").attr("src", getFullImgSrc("img/arrows/arrow_darkgrey_right.gif"))
                                    ).bind("click", function() {
                                        oMiniCalendar.next(1);
                                    })
                            ).append(
                                    $("<td/>").css({ width: "50%"}).attr("align", "left").append(
                                            $("<div/>").addClass("mini-year").attr("id", "mini-year")
                                    )
                            ).append(
                                    $("<td/>").css({ width: "20px"}).attr("align", "right").append(
                                            $("<img/>").addClass("mini-toggle").
                                            attr("src", getFullImgSrc("img/minus.gif")).
                                            css({ cursor: "pointer" }).
                                            click(function() {
                                                ox.widgets.miniCalendar.userToggle = true;
                                                ox.widgets.miniCalendar.toggle();
                                            })
                                    )
                            )
                    );
                
                $(this.dom.node).append(header);
                $(this.dom.node).append(content);
                
                function fn_minicalendar_action() {
                    oMiniCalendar.setSelected(this.id);
                    activeDay=oMiniCalendar.selectedDate;
                    activeMonth=oMiniCalendar.selectedMonth;
                    activeYear=oMiniCalendar.selectedYear;
                    
                    // notify
                    track({
                        type: "DatePicked/MiniCalendar ",
                        text: "Select date " + activeYear + "-" + activeMonth + "-" + activeDay
                    });
                    triggerEvent("OX_Mini_Calendar_Date_Picked", activeYear, activeMonth, activeDay);
                    
                    if(currentpath[0] == "calendar") {
                        if (currentpath[1] != "team" && currentpath[2] == "month") {
                            // this routine is not required in team view; might do too much in other views anyway...
                            loadMonthView();
                        }
                        ox.UIController.setModule({module: "calendar", view: currentpath.join("/") ,folder:"auto", force: "module"});

                    } else if (configContainsKey("folder.calendar")) {
                      
                       ox.UIController.setModule({module: "calendar", folder:"auto", view:"calendar/calendar/day", force: "module"});
                     
                    }
                }
                function updateMiniCalData() {
                    oMiniCalendar.update();
                }
                
                register("OX_Refresh_Mini_Calendar", updateMiniCalData);
                register("OX_Refresh", updateMiniCalData);

                oMiniCalendar = new cAnimMiniCalendar(fn_minicalendar_action, null,
                        [ $("#mini-content", content)[0], $(".mini-month", header)[0], $(".mini-year", header)[0]]);
                b3xViewLoaded = false;

            },
            "ox-sidepanel-view-minical"
        ).
        css({ background: "white", border: "1px solid" }).
        addCSSClass("border-color-design").
        setLayoutParam({ position: "bottom", height: (13*pxPerEm) }).
        addTo(sidepanel);
    
    ox.widgets.miniCalendar.userToggle = false;
    if (ox.api.config.contains("gui.portal.minicalendar")) {
        ox.widgets.miniCalendar.userToggle = !ox.api.config.get("gui.portal.minicalendar");
    }

};


// Two functions shared between ox.gui.FolderTree and ox.gui.TypedFolderTree
ox.gui.initSidepanel.dndSource = function(data, cont) {
    cont("folder/" + data.type, constant(data.id));
};
ox.gui.initSidepanel.dndTarget = function(subfolder, cont) {
    function folderHandler(e, t, data, p, n, d) {
        ox.api.folder.get({
            folder: data,
            success: function(data) {
                ox.api.folder.move(data, subfolder);
            }
        });
    }
    var tObj = {};
    if (   (subfolder.own_rights & 127) >= 4 // folder permissions >= create subfolders
        || subfolder.module == 'mail')
    {
        if (subfolder.type == 5) {
            if (subfolder.id == 1) {
                tObj["folder/1"] = folderHandler;
            } else if (subfolder.id in { 2: 1, 10: 1, 15: 1 }) {
                tObj["folder/2"] = folderHandler;
            } else {
                tObj["folder/" + subfolder.type] = folderHandler;
            }
        } else {
            if ( (subfolder.type == 7 || subfolder.type == 1) && configGetKey("modules.folder.tree") == 1) {
                tObj["folder/1"] = tObj["folder/7"] = folderHandler;
            } else {
                tObj["folder/" + subfolder.type] = folderHandler;
            }
        }
    }
            
    /*
     * check if user has writeObject permissions and if it's not a 
     * shared folder of module calendar, tasks or contacts. move operations
     * into a shared folder of the named modules will be declined by the server
     */
    var tmp_module = subfolder.module;
    if (   (subfolder.own_rights & 127) >= 2 // folder permissions >= create objects
        && !(subfolder.type == 3 && tmp_module == "tasks"))
    {            
        /*
         * user has writeObject permissions on this folder, register event
         * which handles move operations
         */
        tObj[subfolder.module] = function(e,dragType,data,mouseposition,targetNode,dropNode) { 
            if (subfolder.type == 2) {
                for (var i in data.currentObjects) {
                    if (data.currentObjects[i].private_flag) {
                        return;
                    }
                }
            }
            data.endMoving(subfolder.id);
        };
    } else {
        /*
         * user doesn't have writeObject permissions or it's a shared folder 
         * so register dummy event
         */
        tObj[subfolder.module] = $.noop;
    }
        
    if (subfolder.module != "contacts") { 
        tObj.contacts = $.noop;
    }
    if (subfolder.module != "tasks") { 
        tObj.tasks = $.noop;
    }
    if (subfolder.module != "calendar") {
        tObj.calendar = $.noop;
    }
    if (subfolder.module != "infostore") { 
        tObj.infostore = $.noop;
    }
    if (subfolder.module != "mail") { 
        tObj.mail = $.noop;
    }
    if (subfolder.module == "contacts") { 
        tObj.mailaddress = function (e, t, objects) {
            createNewContactfromMail(objects, subfolder.id);
        };
    } else { 
        tObjmailaddress = $.noop;
    }
    cont(tObj);
};
