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

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

/*global ox, jQuery, activemodule : true, activefolder : true, triggerEvent, configuration_askforSave, 
mail_accounts, escapeRegExp */

/**
 * UI Controller
 */
ox.UIController = (function () {
    
    // shortcut
    var $ = jQuery;
    
    // set to "ox.util.inspect" for debugging
    var defaultFn = $.noop; //ox.util.inspect;
    
    // class definition
    var UIController = function () {
        
        // current module
        var currentModule;
        // current folder (per module)
        var currentFolder = {};
        
        // this
        var self = this;
        
        // add dispatcher
        this.dispatcher = new ox.api.event.Dispatcher(this);
        
        this.initialModule = "";
        this.initialView = "";
        
        this.showExpertTree = false;
        
        this.setExpertTree = function(enabled) {
            var name = self.getModule();
            
            // set flag
            self.showExpertTree = enabled;
            
            if (name === "portal") {
                ox.widgets.sidepanel.toggle(!self.showExpertTree);
                if (enabled && this.firstSetExpertTree) {
                    ox.widgets.sidepanelViewControl.showView("ox-sidepanel-foldertree");
                    delete(this.firstSetExpertTree);
                }
            }

            // change view
            if (self.showExpertTree ) {
                name = "foldertree";
            }
            
            // change view
            if (this.firstSetExpertTree === undefined) {
                ox.widgets.sidepanelViewControl.showView("ox-sidepanel-" + name);
            }
            
            // set default value in config
            ox.api.config.set("gui.global.expert_tree", enabled ? 1 : 0);
            
            // trigger event
            self.dispatcher.trigger("expertchanged", {
                enabled: enabled
            });
            
            delete(this.firstSetExpertTree);
        }
        
        
        /**
         * Get module
         */
        this.getModule = function () {
            return currentModule;
        };
        
        var processEvent = function (previous, options) {
            // changes
            var force = options.force;
            var changedView = previous.view !== undefined && previous.view !== currentpath2.join("/");
            var viewMismatch = currentModule !== currentpath2[0];
            var changedModule = previous.module !== currentModule || viewMismatch || changedView || force === "module" || force === "both";
            var changedFolder = previous.folder !== currentFolder[currentModule] || force === "folder" || force === "both";
            var change = changedModule && changedFolder ? "both" : (changedModule ? "module" : "folder");
            // module?
            if (changedModule) {
                // trigger module change
                self.dispatcher.trigger("modulechange", {
                    module: currentModule,
                    folder: currentFolder[currentModule],
                    view: options.view,
                    change: change,
                    force: force
                });
            }
            // folder?
            if (changedFolder) {
                // trigger folder changed
                self.dispatcher.trigger("folderchange", {
                    module: currentModule,
                    folder: currentFolder[currentModule],
                    view: options.view,
                    change: change,
                    force: force
                });
            }
        };
        
        // private function
        var setModule = function (options) {
            
            // remember current module & folder
            var previous = {
                module: currentModule,
                folder: currentFolder[currentModule],
                view: currentpath2.join("/")
            };
            
            // options
            var opt = $.extend({
                module: currentModule,
                event: true,
                success: defaultFn,
                folder: undefined,
                view: undefined,
                force: false
            }, options || {});
            
            if (window.expertSelection) {
                expertSelection.setVisible(opt.module !== "configuration");
            }
            
            // use current folder?
            if (opt.folder === undefined) {
                opt.folder = currentFolder[currentModule];
            }
            
            // success wrapper
            var success = function () {
                
                // set current module & folder
                currentModule = opt.module + "";
                // support magic global (deprecated)
                activemodule = opt.module + "";
                
                // trigger?
                if (opt.event === true) {
                    // process event
                    processEvent(previous, opt);
                    // old school event
                    triggerEvent("OX_Switched");
                }
                
                // continue
                ox.util.call(opt.success, options);
            };
            
            // continuation
            var cont = function (folder) {
                // set folder as well?
                if (folder !== undefined) {
                    // prevent overwriting the wrong folder
                    currentModule = undefined;
                    // set folder
                    self.setFolder({
                        folder: folder,
                        success: function () {
                            // remember folder
                            currentFolder[opt.module] = folder + "";
                            // cont
                            success();
                        },
                        event: false
                    });
                } else {
                    success();
                }
            };
            
            // set folder as well?
            if (opt.folder !== undefined) {
                // use default folder?
                if (opt.folder === "default" || (opt.folder === "auto" && currentFolder[opt.module] === undefined)) {
                    // default/auto
                    self.getDefaultFolder(opt.module, cont);
                } else if (opt.folder === "auto") {
                    // auto with folder set previously
                    cont(currentFolder[opt.module]);
                } else {
                    // specified folder
                    cont(opt.folder);
                }
            } else {
                // no folder
                cont();
            }
        };
        
        /**
         * Set module
         */
        this.setModule = function (options) {
            // configuration?
            if (currentModule === "configuration") {
                // ask first
                configuration_askforSave(function () {
                    setModule(options);
                });
            } else {
                // set now
                setModule(options);
            }
        };
        
        /**
         * Get folder
         */
        this.getFolder = function (module) {
            return currentFolder[module !== undefined ? module : currentModule];
        };
        
        /**
         * Get default folder
         */
        this.getDefaultFolder = function (module, success) {
            
            success = ox.util.isFunction(success) ? success : ox.util.inspect;
            
            // mail is a bit more complicated
            var getDefaultMailFolder = function () {
                // get separator
                var separator = ox.api.config.get("modules.mail.defaultseparator", "/");
                // check folder
                var exists = function (id, success) {
                    if (id === 0) {
                        success(true);
                        return;
                        // main IMAP account
                        return ox.api.folder.exists({
                            folder: "default" + id + separator + "INBOX",
                            success: success
                        });
                    } else {
                        // external accounts
                        return ox.api.folder.exists({
                            folder: "default" + id,
                            success: success
                        });
                    }
                };
                // loop over available mail accounts
                ox.api.account.all(function(accounts) {
                    accounts.sort(function(a, b) { return a.id - b.id; });
                    check(0);
                    function check(i) {
                        if (i >= accounts.length) {
                            notFound();
                            return;
                        }
                        var id = accounts[i].id;
                        exists(id, function(doesExist) {
                            if (doesExist) {
                                ox.util.call(success, "default" + id +
                                                      separator + "INBOX");
                            } else {
                                check(i + 1);
                            }
                        });
                    }
                });
                function notFound() {
                    // if we come around here, we haven't found anything yet, so...
                    var rex = new RegExp("^default\\d+(" + escapeRegExp(separator) + "INBOX)?$"), match;
                    for (i in ox.api.cache.folder0.grepKeys("default")) {
                        if ((match = rex.exec(i))) {
                            ox.util.call(success, match[1] ? i : i + separator + "INBOX");
                            return;
                        }
                    }
                    // nothing found
                    ox.util.call(success, undefined);
                }
            };
            
            // mail is a bit different
            if (module === "mail") {
                getDefaultMailFolder(success);
            } else {
                // get folder from config?
                if (ox.api.config.contains("folder." + module)) {
                    // yes
                    ox.util.call(success, ox.api.config.get("folder." + module));
                } else {
                    // no folder (e.g. portal & configuration
                    ox.util.call(success, undefined);
                }
            }
        };
        
        /**
         * Unset folder
         */
        this.unsetFolder = function (module) {
            // use parameter or current module
            module = module !== undefined ? module : currentModule;
            // unset current folder
            if (module !== undefined) {
                currentFolder[module] = undefined;
            }
        };
        
        /**
         * Set folder
         */
        this.setFolder = function (options) {
            
            // remember current module & folder
            var previous = {
                module: currentModule,
                folder: currentFolder[currentModule],
                view: currentpath2.join("/")
            };
            
            // options
            var opt = $.extend({
                module: undefined,
                folder: currentFolder[currentModule],
                view: undefined,
                event: true,
                success: defaultFn,
                force: false
            }, options || {});
            
            // exists?
            ox.api.folder.get({
                folder: opt.folder,
                success: function (data) {
                    
                    // continuation
                    var cont = function (e) {
                        
                        // do nothing for system folders
                        
                        // set current folder
                        if (currentModule !== undefined) {
                            currentFolder[currentModule] = opt.folder + "";
                        }
                        // support magic global (deprecated)
                        activefolder = opt.folder + "";
                        
                        // trigger events
                        if (opt.event === true) {
                            // process event
                            processEvent(previous, opt);
                        }
                        // continue
                        ox.util.call(opt.success, data);
                    };
                    
                    // set module too?
                    if (opt.module !== undefined) {
                        // use default module?
                        if (opt.module === "default") {
                            // not system? (otherwise do nothing)
                            if (data.module !== "system") {
                                // get proper module
                                self.setModule({
                                    module: data.module,
                                    folder: undefined,
                                    event: false,
                                    success: cont
                                });
                            }
                        } else {
                            self.setModule({
                                module: opt.module,
                                folder: undefined,
                                event: false,
                                success: cont
                            });
                        }
                    } else {
                        cont({ module: opt.module });
                    }
                }
            });
        };
        
        /**
         * Get current view
         * @returns {String} Current view path
         */
        this.getView = function () {
            return currentpath.join("/");
        };
        
        // shortcut to dispatcher.bind
        this.bind = function () {
            self.dispatcher.bind.apply(self.dispatcher, arguments);
        };
    };
    
    // return fresh instance
    return new UIController();
    
}());