/**
 * 
 * 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>
 * @author Alexander Quast <alexander.quast@open-xchange.com>
 * 
 */

/*
 * Tree views
 * ------------------------------------------------------------------------------------
 */
ox.gui.FolderTree = ox.gui.Tree.extend({
    
    construct: function (id, options) {
    
        // super constructor
        ox.gui.Tree.prototype.construct.call(this, id);
    
        // options
        this.options = $.extend({
            tree: ox.api.config.get("modules.folder.tree") || 0
        }, options || {});
        if (this.options.root === undefined) {
            this.options.root = this.options.tree === 1 ? "1" : "0";
        }
        
        var TYPE = this.options.type;
        var self = this;
        
        this.css({ padding: "10px 0px 10px 0px" });
        
        // node parser
        this.setNodeParser(function (data) {
            // root node fix
            
            if (data){ // fix to prevent error on console TODO fix it real
                var parent = data.id === self.options.root ? null : data.folder_id;
            }
            
            return { 
                "id": data.id, "parent": parent, "name": data.title, 
                "type": data.module, "hasChildren": data.subfolders
            };
        });
        
        // this tree displays all folders
        this.customize = function (node) {
            
            var messagingServices = {
                    "com.openexchange.messaging.facebook": {
                        icon: "facebook.png"
                    },
                     "com.openexchange.messaging.rss": {
                        icon: "rss.png"
                    },
                    "com.openexchange.messaging.twitter": {
                        icon: "twitter.png"
                    }
            };
            
            var data = node.data, api = ox.api.folder, id;
            var name = data.title;
            
            // clear all custom styles
            $(node.dom.title).parent().css({ fontWeight: "" });
            $(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;
                    // inner-HTML is evil, so wrap it all in a text node
                    meta.html = newtext(meta.name + " (" + data.unread + ")");
                }
                return meta;
            };
            
            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 from api!
                    var config = ox.api.config.get();
                    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"
                        };
                    }
                }
            }
          
          
            // iterate through all modules (mail, calendar, system etc..)
            switch (data.module){
            // "src" is the icon to be displayed
            case "system" :
                if (ox.api.folder.is("account", data)) { // is mail account?
                    src= "mail";
                } else {
                    switch(data.id) {
                        case "1":
                            src = "user";
                            break; // show user symbol for static id 1
                        case "2":
                            src = "public";
                            node.selectable = false;
                            break; // show user public folder
                        case "3":
                            src = "shared";
                            node.selectable = false;
                            break; // show shared folder id
                    }
                  }
                if(/u:/.test(data.id)) {
                    src = "user";
                }
                break;
            case "mail" :   // special mail folder?
                
                switch (data.id) {
                case a.inbox_fullname: src = "inbox";break;
                case a.trash_fullname: src = "garbage";break;
                case a.sent_fullname: src = "outbox"; break;
                case a.drafts_fullname: src = "draft"; break;
                case a.spam_fullname: src = "spam"; break;
                case a.confirmed_ham_fullname: src = "ham"; break;
                case a.confirmed_spam_fullname:  src = "spam"; break;
                default:
                    // special mail folders
                    // TODO nicening, remove unneeded else block
                    if ((api.is("system", data) || api.can("read", data)) && node.isCut !== true) {
                        // ok
                        src = node.statusOpen ? "folder_opened" : "folder_closed";
                    } else {
                        // cannot read
                        src = node.statusOpen ? "folder_opened" : "folder_closed";
                    }                  
                }
            break;
            case "contacts": 
                src = "contacts"; 
                $(node.dom.title.parentNode).removeClass("font-style-low");
                
                break;
            case "tasks": 
                src = "tasks"; 
                $(node.dom.title.parentNode).removeClass("font-style-low");
                break;
            
            case "calendar": 
                src = "calendar";
                $(node.dom.title.parentNode).removeClass("font-style-low");
                break;
                
            case "infostore": 
                if (data.folder_id === "10"){
                    src = "user";
                } else {
                    src = "infostore";
                    $(node.dom.title.parentNode).removeClass("font-style-low");
                    
                    if (data.id === "9" || data.id === "10" || data.id === "14" || data.id === "15") {
                        
                        node.selectable = false;
                    }
                }
                break;
            case "messaging":
                
                  var service = /^(.*?):/.exec(data.id);
                 
                  if(service){
                     src = messagingServices[service[1]].icon;
                
                  }
                
                break;
            default:
                // nothing yet
                break;
            }
          
            // complete image source to grayish or colored icons
            // also text-style to gray or gray italic
            if (this.options.type === undefined  || (this.options.type == "") || (data.module === this.options.type ) 
                    || (data.folder_id === "0") || (data.module === "system" && src ==="mail" && this.options.type === "mail")) {
                
                // folder has no read and write access
                if (!api.can("read", data) && data.module !== "system" &&
                    data.module !== "infostore" || node.isCut)
                {
                    src = src + "_dis.gif"; // disable symbol
                    $(node.dom.title.parentNode).addClass("font-color-disabled font-style-low"); // gray italic
                } else {
                    if(data.module != "messaging"){ 
                        src = src + ".gif"; //standard icon, messaging has own png
                    }
                    
                    $(node.dom.title.parentNode).removeClass("font-color-disabled"); // remove gray text
                                  
                    if (ox.api.folder.is("published", data)) {// published folders
                        // add shared symbol to original                 
                        $(node.dom.icon).css({"background-image" : "url(" + ox.gui.themePath + "img/folder/" +src+ ")" });
                        src = "shared.png" ;
                    }
                }
            } else {
                if(data.module != "messaging"){ 
                    src = src + "_dis.gif"; //standard icon, messaging has own png
                }
                $(node.dom.title.parentNode).addClass("font-color-disabled"); // for module selection also gray out every unwanted folders
            }
            
            if (data.id === "default0") {
                // Return a text node which is asynchronously filled with
                // the user's display name.
                var titlenode = newtext(name);
                internalCache.getUsers([config.identifier], function(users) {
                    titlenode.data = users[config.identifier].display_name;
                });
                return {
                    src: ox.gui.themePath + "img/folder/" + src,
                    html: titlenode
                };
            } else {
                return processUnread({
                    src: ox.gui.themePath + "img/folder/" + src,
                    name: name
                });
            }
        };
       
        this.selection.classSelected = "background-color-PMG-selection-elements";
        this.showRootNode = false;

        // add root node
        this.setRootNode({
            id: this.options.root,
            folder_id: null,
            title: "Root",
            module: "root",
            subfolders: true 
        });
        
        var ID = this.id + "/" + ox.api.config.get("modules.folder.tree", 0);
        
        var fnToggle = function () {
            // 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);
        
        // 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 || []);
        }

        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) {
        var self = this;
        ox.api.folder.getSubFolders({
            folder: id, 
            success: function (data) {
                // subscribed folders only
                data = $.grep(data, function (elem, i) {
                    return elem.subscribed === true || elem.subscr_subflds === true;
                });
                cont(data);
            },
            error: function (error) {
                cont(false);
            }
        });
    },
    
    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);
        }
    }
});

// extend API
ox.api.ui.selectFolder = (function () {
    
    var trees = {};
    
    return function (options) {
        
        var opt = $.extend({
            root: ox.api.config.get("modules.folder.tree", 0)
        }, options || {});
        
        // clear
        removeChildNodes(opt.node);
        
        // create tree?
        var id = opt.id, tree;
        if (trees[id] === undefined) {
            tree = trees[id] = new ox.gui.FolderTreePopup(opt);
            tree.setParentDOMNode(opt.node);
            tree.paint();
        } else {
            tree = trees[id];
            tree.setParentDOMNode(opt.node);
            tree.selection.clear();
            tree.repaint();
        }
    };
}());

/*
 * Tree view for popup folder tree (like move objects)
 * ------------------------------------------------------------------------------------
 */

ox.gui.FolderTreePopup = ox.gui.FolderTree.extend({
    
    construct: function (options) {

        var opt = $.extend({
            // none
        }, options || {});

        ox.gui.FolderTree.prototype.construct.call(this, opt.id || null, opt);
        
        var callback = opt.callback;
        
        this.addListener("widget:select", function (e) {
            var api = ox.api.folder;
            api.get({
                folder: e.data, 
                success: function (data) {
                    // typed?
                    if (opt.type !== undefined) {
                        if (opt.type === data.module) {
                            callback(data);
                        }
                    } else if (data.module !== "system") {
                        callback(data);
                    }
                }
            });
        });
    }
});
    
ox.gui.initFolderTree = function () {
   
   var tree = ox.widgets.folderTree = new ox.gui.FolderTree("ox-sidepanel-foldertree", {
       type: "", root: ox.api.config.get("modules.folder.tree") === 1 ? "1" : "0"
   });
   
   tree.enableDnD(ox.gui.initSidepanel.dndSource,
                  ox.gui.initSidepanel.dndTarget);
   
   ox.widgets.sidepanelViews.folderTree = tree;
   
   // add listeners
   tree.addListener("widget:select", function(e) {
       var api = ox.api.folder;
       var self = this;
       // get folder data
       api.get({
           folder: e.data, 
           success: function (data) {
               // TODO: check whether "someone" meant folder_id === 1?
               if (data.id !== 2 && data.id !== 3 && data.id !== 9 && data.id !== 10 && data.id !== 14 && data.id !== 15) {
                   //not system?
                   if (!api.is("system", data) && api.can("read", data)) {
                       // "normal" folder
                       ox.UIController.setModule({ folder: data.id, module: data.module });
                   } else if (e.data === "1") {
                       // jump to portal
                       ox.UIController.setModule({ module: "portal" });
                   } else if(e.data === "6"){
                       // GAL fix
                       ox.UIController.setModule({ folder: "6", module: "contacts" });
                   }
               }
           }
       });
   });
   
   tree.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
                   tree.startEdit(id);
               }
           }
       });
   });
   
   tree.addListener("widget:edited", function (e) {
       // update folder
       var self = this;
       ox.api.folder.update({
           folder: e.data.id,
           data: { title: e.data.value },
           success: function (data) {
                ox.api.folder.refresh({ folders: [e.data.data.folder_id],
                                        success: e.cont });
           },
           error : function () {
               // repaint
               self.repaint();
               // select
               self.selection.select(e.data.id);
               // continue
               ox.util.call(e.cont);
           }
       });
       return false;
   });
   
   // click handler
   tree.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
           });
           // cont
           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 + ")"
                       });
                   }
               });
               if (ox.UIController.getFolder() !== e.id) {
                   e.click("force");
               } else {
                   e.click();
               }
           }
       }
       
       // prevent default
       return false;
   });
   
   // context menu
   tree.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: tree.options.type,
           widget: tree
       });
   });
    
   // do not show root node
   tree.showRootNode = false;
   
   // add
   ox.widgets.sidepanelViews.folder.insert(tree, 0);
   tree.setLayoutParam({ position: "center" });
    
   /*
    EXAMPLE USAGE
    ***********************************************************
    
    masterFolderTree = new ox.gui.FolderTree(null, {
        type: "mail", root: "0"
    });
    
    var testKnoten = $("<div>").css({
        position: "absolute", top: "30px", right: "250px", bottom: "50px", left: "350px", zIndex: 65000,
        border: "5px solid #fc0", backgroundColor: "white"
    }).appendTo(document.body);
    
    masterFolderTree.setParentDOMNode(testKnoten[0]);
    
    masterFolderTree.paint();
 
    END EXAMPLE ***************************************
 */ 
   
   
};