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

// DEVELOPMENT IN PROGRESS // SUBJECT TO PERMANENT CHANGE!

ox.gui.Desktop = ox.gui.StatefulContainer.extend({
/** @lends ox.gui.Desktop.prototype */
    
    getClass: function() { return "ox.gui.Desktop"; },
    
    /**
     * The topmost GUI control
     * 
     * @constructs
     * @extends ox.gui.StatefulContainer
     */
    construct: function() {
        
        this.globalCounter = 0;
        this.globalTabIndex = 1;
        this.listeners = {};
        this.globalListeners = {};
        
        this.registry = {
            "widget": {
                "list": {}, "observer": {}
            },
            "window": {
                "list": {}, "observer": {}
            }
        };

        this.themePath = "img";
        this.windowManager = null;

        this._super("ox.gui.desktop");
        
        // layout manager
        this.setLayout(new ox.gui.ZeroLayout(this));
    },
    
    nodeInit: function() {
        this._super();
        this.addCSSClass("oxContainer");
        this.addCSSClass("oxStretch");
    },
    
    paint: function() {
        // add special corners
// this.cornerTopRight = newnode("div", 0, {
// className: "oxDesktopCorner oxTopRight"
// });
// document.body.appendChild(this.cornerTopRight);
// this.cornerBottomRight = newnode("div", 0, {
// className: "oxDesktopCorner oxBottomRight"
// });
// document.body.appendChild(this.cornerBottomRight);
// // handler
// var Self = this;
// // $(this.cornerTopRight).mouseover(function() {
// // if (Self.windowManager) {
// // Self.windowManager.expose("hide");
// // }
// // });
// $(this.cornerBottomRight).mouseover(function() {
// if (Self.windowManager) {
// Self.windowManager.expose("expose");
// }
// });
// $(this.cornerBottomRight).mouseout(function() {
// if (Self.windowManager) {
// Self.windowManager.expose("reverse");
// }
// });
        ox.gui.StatefulContainer.prototype.paint.call(this);
    },

    getWindowManager: function() {
        return this.windowManager;
    },

    setWindowManager: function(windowManager) {
        this.windowManager = windowManager;
        return this;
    },
    
    createWindow: function(id, widgetClass, windowManager) {
        // class
        widgetClass = widgetClass ? widgetClass : ox.gui.Window;
        // create
        var w = new widgetClass(id);
        // implizit window manager?
        if (windowManager === undefined) {
            // use default window manager and add now
            if (this.windowManager) {
                this.windowManager.add(w);
                w.windowManager = this.windowManager;
            }
        } else {
            // use explicit window manager (do not add now)
            w.windowManager = windowManager;
        }
        return w;
    },
    
    /**
     * Gets a widget. The widget might not yet be created, so this function uses
     * a callback.
     */
    getWidget: function(id, callback) {
        return this.getObject("widget", id, callback);
    },
    
    /**
     * Gets a window. The window might not yet be created, so this function uses
     * a callback.
     */
    getWindow: function(id, callback) {
        return this.getObject("window", id, callback);
    },
    
    /**
     * Shows a window. The window might not yet be created, so this function
     * uses a callback internally.
     */
    showWindow: function(id) {
        this.getObject("window", id, function(window) {
            window.show();
        });
    },
    
    /**
     * @private
     */
    getObject: function(type, id, callback) {
        var reg = this.registry[type];
        // exists?
        if (reg.list[id] !== undefined) {
            ox.call(callback, reg.list[id]);
            return reg.list[id];
        } else {
            // create observer
            if (reg.observer[id] === undefined) {
                reg.observer[id] = [];
            }
            reg.observer[id].push(callback);
            return undefined;
        }
    },
    
    /**
     * Registers a widget in the global widget repository.
     */
    registerWidget: function(widget) {
        this.registerObject("widget", widget);
    },
    
    /**
     * Unregisters a widget
     */
    unregisterWidget: function(widget) {
        this.unregisterObject("widget", widget);
    },
    
    /**
     * Registers a window in the global window repository.
     */
    registerWindow: function(window) {
        this.registerObject("window", window);
    },
    
    /**
     * Unregisters a window
     */
    unregisterWindow: function(window) {
        this.unregisterObject("window", window);
    },
    
    /**
     * @private
     */
    registerObject: function(type, obj) {
        var reg = this.registry[type], id = obj.id || "";
        // add object
        reg.list[id] = obj;
        // any observers?
        if (reg.observer[id] !== undefined) {
            // loop observers
            var observers = reg.observer[id];
            for (var i = 0; i < observers.length; i++) {
                // callback
                observers[i](obj);
            }
            // delete observers
            delete reg.observer[id];
        }
    },
    
    /**
     * @private
     */
    unregisterObject: function(type, obj) {
        var reg = this.registry[type], id = obj.id || "";
        // remove object
        delete reg.list[id];
    },
    
    oops: function(e) {
        var message = Object.isString(e) ? e : (e.message || e) + "\n\n" + ox.desktop.oops.caller;
        alert("Oops! This sould not happen:\n\n" + message);
    },

    oopsFunc: function(functionSignature, message) {
        alert("Oops!\n" + functionSignature + "\n" + message);
    },
    
    setRootDOMNode: function(DOMNode) {
        this.setParentDOMNode(DOMNode);
        return this;
    },

    addDOMListener: function(options) {
        // get options
        var defaults = { 
            type: "click",
            target: document,
            callback: $.noop,
            scope: null
        };
        var opt = $.extend(defaults, options);
        
        // add listener
        $(opt.target).bind(opt.type, $.proxy(opt.callback, opt.scope || opt.target));
    },
    
    removeDOMListener: function(options) {
        // get options
        var defaults = { 
            type: "click",
            target: document,
            callback: $.noop,
            scope: null
        };
        var opt = $.extend(defaults, options);
        
        // add listener
        $(opt.target).unbind(opt.type, $.proxy(opt.callback, opt.scope || opt.target));
    },

    addGlobalListener: function(options) {
        // get options
        var defaults = { 
            type: "default",
            callback: $.noop,
            scope: this
        };
        var opt = $.extend(defaults, options);
        // lower case
        var types = opt.type.toLowerCase().split(/\s+/);
        delete opt.type;
        for (var i in types) {
            var type = types[i];
            // first listener?
            if (this.globalListeners[type] === undefined) {
                this.globalListeners[type] = [];
            }
            // add listener
            this.globalListeners[type].push({
                "callback": opt.callback,
                "scope": opt.scope
            });
        }
    },
    
    removeGlobalListener: function(options) {
        // get options
        var defaults = { 
            type: "default",
            callback: $.noop
        };
        var opt = $.extend(defaults, options);
        // lower case
        var type = opt.type.toLowerCase();
        var removeAll = opt.callback == $.noop;
        // queue exists?
        if (this.globalListeners[type]) {
            var queue = this.globalListeners[type], i = 0;
            // loop through queue
            while (i < queue.length) {
                if (removeAll || queue.callback == opt.callback) {
                    // remove from queue
                    queue.splice(i, 1);
                } else {
                    i++;
                }
            }
        }
    },

    addWidgetListener: function(options) {
        // get options
        var defaults = { 
            type: "valid",
            target: this,
            callback: $.noop,
            scope: this
        };
        var opt = $.extend(defaults, options);
        // lower case
        var types = opt.type.toLowerCase().split(/\s+/);
        delete opt.type;
        for (var i in types) {
            var type = types[i];
            var target = opt.target;
            // first listener?
            if (this.listeners[target.id] === undefined) {
                this.listeners[target.id] = [];
            }
            // add listener
            this.listeners[target.id].push({
                "callback": opt.callback,
                "type": type,
                "scope": opt.scope
            });
        }
    },
    
    removeWidgetListener: function(options) {
        // get options
        var defaults = { 
            type: null,
            target: this,
            callback: $.noop
        };
        var opt = $.extend(defaults, options);
        // remove all listeners? (i.e. no type given)
        if (!opt.type) {
            delete this.listeners[opt.target.id];
        } else {
            // remove all callbacks of one type?
            var removeAll = opt.callback == $.noop;
            // queue exists?
            var target = opt.target;
            if (this.listeners[target.id]) {
                var queue = this.listeners[target.id], i = 0;
                // lower case
                var type = opt.type.toLowerCase();
                // loop through queue
                while (i < queue.length) {
                    var listener = queue[i];
                    if (listener.type == opt.type && (removeAll || listener.callback == opt.callback)) {
                        // remove from queue
                        queue.splice(i, 1);
                    } else {
                        i++;
                    }
                }
            }
        }
    },
    
    getWidgetListeners: function(widget) {
        var id, listeners, tmp = [];
        if (widget) {
            id = widget.id;
            listeners = this.listeners[id];
            if (listeners) {
                for (var i in listeners) {
                    tmp.push(listeners[i]);
                }
            }
        }
        return tmp;
    },
    
    getAllListeners: function() {
        
        var tmp = [], widget, queue, i, type, listener;
        
        // loop widgets
        for (widget in this.listeners) {
            queue = this.listeners[widget];
            // loop listeners
            for (i in queue) {
                listener = queue[i];
                tmp.push({ domain: "widget", type: listener.type, scope: listener.scope, callback: listener.callback });
            }
        }
        // loop globals
        for (type in this.globalListeners) {
            queue = this.globalListeners[type];
            // loop listeners
            for (i in queue) {
                listener = queue[i];
                tmp.push({ domain: "ox", type: type, scope: listener.scope, callback: listener.callback });
            }
        }
        return tmp;
    },
    
    removeListenerByScope: function(scope) {
        
        var id, queue, i, type, listener;
        
        // loop widgets
        for (id in this.listeners) {
            queue = this.listeners[id];
            // loop listeners
            i = 0;
            while (i < queue.length) {
                listener = queue[i];
                if (listener.scope == scope) { queue.splice(i, 1); } else { i++; }
            }
        }
        // loop globals
        for (type in this.globalListeners) {
            queue = this.globalListeners[type];
            // loop listeners
            for (i in queue) {
                listener = queue[i];
                if (listener.scope == scope) { queue.splice(i, 1); } else { i++; }
            }
        }
    },

    triggerEvent: function(type, source, data, callback) {
        // adjust source
        source = source || null;
        // lower case
        type = type.toLowerCase();
        var joint = new Join(callback || $.noop);
        var conts = [];
        var i, item;
        // event queue defined?
        if (this.listeners[source.id] !== undefined) {
            // get queue
            var queue = this.listeners[source.id], $l = queue.length;
            // loop through queue (to join)
            for (i = 0; i < $l; i++) {
                item = queue[i];
                if (type == item.type) {
                    conts[i] = joint.add($.noop);
                }
            }
            // loop again through queue
            for (i = 0; i < $l; i++) {
                item = queue[i];
                // match?
                if (type == item.type) {
                    // call back!
                    var ret = ($.proxy(item.callback, item.scope)({
                        "name": type, "source": source, "data": data, "cont": conts[i]
                    }));
                    // sync?
                    if (ret !== false) {
                        // no waiting
                        conts[i]();
                    }
                }
            }
            
        }
        // no conts?
        if (conts.length === 0) {
            ox.call(callback);
        }
    },
    
    triggerGlobalEvent: function(type, data) {
        // lower case
        type = type.toLowerCase();
        // event queue defined?
        if (this.globalListeners[type] !== undefined) {
            // get queue
            var queue = this.globalListeners[type];
            // loop through queue
            for (var i = 0; i < queue.length; i++) {
                var item = queue[i];
                // call back!
                ($.proxy(item.callback, item.scope)(data || null));
            }
        }
    },
    
    shutdown: function(options) {
        // options
        options = $.extend({
            animate: $.noop,
            complete: $.noop
        }, options);
        // destroy desktop
        this.destroy();
        // destroy ox namespace (keep function "call" so that final callbacks don't fail)
        window.ox = { call: ox.call };
        window.oxWidgetFactory = null;
        // animate
        options.animate(function () {
            // clear body
            $(document.body).css({ background: "#111 none" }).empty();
            // be last
            setTimeout(function () {
                // remove all scripts
                var headTag = document.getElementsByTagName('HEAD').item(0);
                var $c = headTag.childNodes, i = 0;
                while (i < $c.length) {
                    if ($c[i].tagName == "SCRIPT") {
                        // remove script
                        headTag.removeChild($c[i]);
                    } else {
                        i++;
                    }
                }
                // callback
                options.complete();
            }, 10);
        });
    },
    
    destroy: function() {
        // remove special event handler
        $(document.body).unbind();
        $(document).unbind();
        $(window).unbind();
        // remove main window controller
        this.windowManager = null;
        // super class
        ox.gui.Container.prototype.destroy.call(this);
    }
});


// ------------------------------------------------------------------------------

// create desktop object
ox.desktop = new ox.gui.Desktop();

// shortcuts
ox.$w = function(id) {
    return ox.desktop.registry.widget.list[id] || null;
};

// ------------------------------------------------------------------------------

