/**
 * 
 * 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>
 * @ignore
 */

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


ox.gui.TabControl = ox.gui.StatefulContainer.extend({
/** @lends ox.gui.TabControl.prototype */
    
    getClass: function() { return "ox.gui.TabControl"; },
    
    /** 
     * A tab control widget. Manages tab pages.
     * @constructs
     * @extends ox.gui.StatefulContainer
     * @param {String} id An optional unique id for the widget.
     */
    construct: function (id) {
        
        // call super class constructor
        this._super(id);
        
        // set layout manager (for tabs; not pages)
        this.setLayout(new ox.gui.TabControlLayout(this));
        
        // expand/hover
        this.expanded = true;
        this.expandable = false;
        this.inHover = false;
        this.lastClickedChild = null;
        
        // create tab container
        this.tabContainer = document.createElement("div");
        this.tabContainer.className = "oxTabControl";
        // create tab page container
        this.tabPageContainer = document.createElement("div");
        this.tabPageContainer.className = "oxTabControlPageContainer";
        
        // create hover
        var target = $("#everything");
        this.dom.hover = document.createElement("div");
        this.dom.hover.className = "oxTabControlPageHover";
        target.append(this.dom.hover);
        this.dom.hoverUnderlay = document.createElement("div");
        this.dom.hoverUnderlay.className = "oxTabControlPageHoverUnderlay";
        target.append(this.dom.hoverUnderlay);
        
        // event handler
        var self = this;
        $(this.dom.hoverUnderlay).add(document.body).bind("click", function (e) {
            if (self.inHover && self.expanded) {
                // collapse
                self.collapse();
            }
        });
        
        // access keys of tab pages
        this.accesskeys = {};

        // set target node
        this.defaultTargetDOMNodeForChildren = this.tabPageContainer;
        
        this.enableI18n();
    },
    
    i18nHandler: function() {
        this.layoutManager.doLayout();
    },
    
    nodeInit: function() {
        // stretch DOM node
        this.setStyle("overflow: visible");
    },
    
    nodeListeners: function() {
        
        var fnWheel = function (e) {
            var p = 0 + this.currentChild.position;
            var children = this.getChildren();
            p = Math.max(0, Math.min(p - e.deltaSign, children.length-1));
            this.showChild(children[p].id);
            return false;
        };
        
        // wheel event (turned off)
        // this.addListener("dom:mousewheel", this.dom.hover, fnWheel);
        
        // double click
        this.addListener("dom:dblclick", this.tabContainer, function (e) {
            // only on upper bar
            if (e.target === this.tabContainer) {
                this.toggleHover();
                return false;
            }
        });
    },
    
    add: function (widget) {
        // must be an instance of Widget
        if (widget.id && widget instanceof ox.gui.Widget) {
            // invisible
            widget.statusVisible = true; // required to force paintInvisible (see next row)
            widget.setVisible(false);
            // call super class method
            ox.gui.StatefulContainer.prototype.add.call(this, widget);
            // first added page?
            if (!this.currentChild && !this.inHover) {
                this.currentChild = widget;
                this.currentState = widget.id;
                this.currentChild.setVisible(true);
                this.triggerWidgetEvent("tabchanged", this.currentChild);
            }
            // add to index
            this.childIndex[widget.id] = widget;
            
        } else {
            ox.desktop.oopsFunc(this.getClass()+"(<widget>)", "<widget> must be an instance of ox.gui.Widget and it MUST have an id!");
        }
        // support chaining
        return this;
    },
    
    hideCurrentChild: function () {
        if (this.currentChild != null) {
            // hide
            this.currentChild.hide();
            this.currentState = "";
            // hide hovers, e.g. menustrips
            this.hideHovers();
        }
    },
    
    setPosition: function (position) {
        if (typeof position === "number" && position > 0 && this.children.length > position) {
            // show child
            this.showChild(this.children[position].id);
        }
    },
    
    showChild: function (childID) {
        // switch to child
        if (this.childIndex[childID] !== undefined && this.currentState != childID) {
            this.hideCurrentChild();
            this.currentChild = this.childIndex[childID];
            this.currentState = childID;
            // update tabs
            this.layoutManager.update(this);
            // show child
            this.currentChild.show();
        }
    },
    
    /**Highest
     * Toggles expand/collapse.
     */
    toggle: function() {
        if (this.expandable) {
            if (this.expanded) {
                this.collapse();
            } else {
                this.expand();
            }
        }
    },
    
    /**
     * Expands the tab page container.
     */
    expand: function() {
        if (this.expandable && !this.expanded) {
            if (this.inHover) {
                // adjust dimensions
                // get offset of tab control
                var o = $(this.dom.node).offset();
                // add height of tab control
                o.top += $(this.tabContainer).height();
                // move hover to proper position
                $(this.dom.hover).css({
                    top: o.top + "px",
                    left: o.left + "px"
                });
                // move underlay to proper position
                $(this.dom.hoverUnderlay).css({
                    top: o.top + "px"
                }).show();
                // show hover
                $(this.dom.hover).show();
            }
            // show container
            $(this.tabPageContainer).show();
            // set flag
            this.expanded = true;
            // update tabs
            this.layoutManager.update(this);
            // trigger event
            this.triggerWidgetEvent("tabexpanded", this);
            // trigger event
            this.triggerWidgetEvent("tabtoggled", this);
        }
    },

    /**
     * Collapses the tab page container.
     */
    collapse: function() {
        if (this.expandable && this.expanded) {
            // hide
            $(this.dom.hoverUnderlay).hide();
            $(this.tabPageContainer).hide();
            $(this.dom.hover).hide();
            // set flag
            this.expanded = false;
            // update tabs
            this.layoutManager.update(this);
            // trigger event
            this.triggerWidgetEvent("tabcollapsed", this);
            // trigger event
            this.triggerWidgetEvent("tabtoggled", this);
        }
    },
    
    /**
     * Toggle "hover mode".
     */
    toggleHover: function (flag, event) {
        // adjust params
        flag = flag === undefined ? !this.inHover : flag;
        event = event === undefined || event === true;
        // change?
        if (flag !== this.inHover) {
            if (flag === false) {
                // unregister
                this.hasHover(false);
                // move
                $(this.tabPageContainer).
                    removeClass("oxTabControlPageContainerInHover").
                    appendTo(this.dom.node);
                this.inHover = false;
                // hide underlay
                $(this.dom.hoverUnderlay).hide();
                // trigger event
                if (event) {
                    this.triggerWidgetEvent("togglehover", false);
                }
                // expand
                this.expand();
            } else {
                // register
                this.hasHover(true);
                // append to hover
                $(this.tabPageContainer).
                    addClass("oxTabControlPageContainerInHover").
                    appendTo(this.dom.hover);
                this.inHover = true;
                // trigger event
                if (event) {
                    this.triggerWidgetEvent("togglehover", true);
                }
                // collapse
                this.collapse();
            }
        }
    },
    
    hideHovers: function () {
        if (this.inHover) {
            // collapse
            this.collapse();
            // hide underlay
            $(this.dom.hoverUnderlay).hide();
        }
        // continue
        ox.gui.StatefulContainer.prototype.hideHovers.call(this);
    }
});

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

ox.gui.TabPage = ox.gui.Container.extend({
/** @lends ox.gui.TabPage.prototype */
    
    getClass: function() { return "ox.gui.TabPage"; },
    
    /** 
     * A tab page
     * @constructs
     * @extends ox.gui.Container
     * @param {String} id An optional unique id for the widget.
     * @param {String} title The title of the tab page.
     */
    construct: function(id, title) {
        // call super class constructor (inherit from Container)
        this._super(id);
        
        // tab title
        this.title = title || _("No title");
    },
    
    initNode: function() {
        this._super();
        this.setStyle("overflow: hidden");
    }
});

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

ox.gui.TabControlLayout = ox.gui.LayoutManager.extend({
/** @lends ox.gui.TabControlLayout.prototype */
    
    getClass: function() { return "ox.gui.TabControlLayout"; },
    
    /** 
     * @constructs
     * @extends ox.gui.LayoutManager
     */
    construct: function(container) {
        this._super(container);
        this.tds = [];
        this.firstRun = true;
    },
    
    doLayout: function() {

        var layoutmanager = this;
        var tabControl = this.container;
        
        // clear
        tabControl.tabContainer.innerHTML = "";
        tabControl.accesskeys = {};
        layoutmanager.tds = [];
        
        // add "toggle" button
        var button = document.createElement("div");
        button.className = tabControl.inHover ? "oxTabControlToggleReverse" : "oxTabControlToggle";
        tabControl.tabContainer.appendChild(button);
        
        // add listener
        tabControl.addListener("dom:click", button, function(e) {
            if (this.expanded) {
                this.collapse();
            } else {
                this.showChild(this.children[0].id);
                this.expand();
            }
            this.lastClickedChild = null;
            this.toggleHover();
            return false;
        });
        
        tabControl.addListener("widget:togglehover", function (e) {
            button.className = e.data ? "oxTabControlToggleReverse" : "oxTabControlToggle";
        });
        
        // create table
        var table = document.createElement("table");
        table.border = table.cellPadding = table.cellSpacing = 0;
        var tbody = document.createElement("tbody");
        var tr = document.createElement("tr");
        // loop children
        tabControl.each(function(child, i, childCount) {
            // add to DOM & show
            var td = document.createElement("td");
            var className = i < childCount - 1 ? "oxTab" : "oxTabLast";
            className += child == tabControl.currentChild ? " oxTabCurrent" : "";
            td.className = className;
            // add a dead link (safari needs this for tab index)
            var a = document.createElement("a");
            var title = escapeHTML(expectI18n(child.title));
            a.innerHTML = title.replace(/^&amp;(.)/, "<u>$1</u>");
            a.href = "#";
            a.tabIndex = ox.gui.globalTabIndex++;
            td.appendChild(a);
            tr.appendChild(td);
            // save for faster updates
            layoutmanager.tds.push(td);
            // shortcut key?
            if (title.search(/&amp;\w/) != -1) {
                // get shortcut key/keyCode
                var matches = title.match(/&amp;(.)/);
                child.shortcutKey = matches[1].toUpperCase();
                child.shortcutKeyCode = child.shortcutKey.charCodeAt(0);
                // add to queue
                if (tabControl.accesskeys[child.shortcutKey] === undefined) {
                    tabControl.accesskeys[child.shortcutKey] = { 'pages': [], 'position': 0, 'lock': false };
                }
                tabControl.accesskeys[child.shortcutKey].pages.push({
                    'tabPage': child, 'link': a, 'key': matches[1].toLowerCase()
                });
            }
            // add event listeners
            child.addListener("dom:focus", a, function(e) {
                var tab = this.parent;
                // show tab (unless already shown)
                if (tab.currentChild != this) {
                    this.parent.showChild(this.id);
                    if (!tab.expanded) tab.expand();
                }
                // move access key
                if (ox.browser.WebKit || ox.browser.IE) {
                    var access = tab.accesskeys[tab.currentChild.shortcutKey];
                    if (access) {
                        var l = access.pages.length;
                        var current = access.position;
                        var next = (access.position+1) % l;
                        var currentPage = access.pages[current];
                        currentPage.link.accessKey = "";
                        var nextPage = access.pages[next];
                        nextPage.link.accessKey = nextPage.key;
                        access.position = next;
                    }
                }
                return false;
            });
            // click handler
            var fnClick = function (e) {
                var tab = this.parent;
                // we have to use "lastClickedChild" here, since this click event 
                // interferes with "dom:onFocus" (see above)
                if (tab.inHover && tab.lastClickedChild == this && tab.expanded) {
                    tab.collapse();
                } else {
                    // todo: abstract solution for tracking
                    track({
                        type: "Click/Tab",
                        text: "Change to tab \"" + this.title.replace(/&/, "") + "\" (" + this.id + ")"
                    });
                    tab.showChild(this.id);
                    tab.expand();
                }
                tab.lastClickedChild = this;
                return false;
            };
            child.addListener("dom:click", td, fnClick);
//            child.addListener("dom:mouseover", td, function (e) {
//                var tab = this.parent;
//                // change if hover
//                if (tab.inHover) {
//                    tab.showChild(this.id);
//                    tab.expand();
//                }
//            });
        });
        tbody.appendChild(tr);
        table.appendChild(tbody);
        tabControl.tabContainer.appendChild(table);

        // add listener
        tabControl.addListener("dom:click", document, function(e) {
            if (this.inHover && this.expanded) {
                this.lastClickedChild = null; // dom:focus workaround (see above)
                this.collapse();
            }
        });
        
        // set access key - works perfect for IE/Safari (Alt+Key)
        // since it prevents the browser menu from popping up
        for (var key in tabControl.accesskeys) {
            var page = tabControl.accesskeys[key].pages[0];
            page.link.accessKey = page.key;
        }
        
        if (ox.browser.Gecko) {
            tabControl.addListener("dom:keydown", document, function(e) {
                var ascii = e.charCode || e.which || e.keyCode;
                var keyChar = String.fromCharCode(ascii);
                // alt key?
                if (this.statusVisible && e.altKey) {
                    // look for tab page
                    var access = this.accesskeys[keyChar];
                    if (access && !access.lock) {
                        access.lock = true;
                        var l = access.pages.length;
                        var next = (access.position+1) % l;
                        // change tab
                        this.showChild(access.pages[next].tabPage.id);
                        if (!this.expanded) this.expand();
                        // remember new position
                        access.position = next;
                        // stop event
                        return false;
                    }
                }
            });
            
            tabControl.addListener("dom:keyup", document, function(e) {
                var ascii = e.charCode || e.which || e.keyCode;
                var keyChar = String.fromCharCode(ascii);
                // look for tab page
                var access = this.accesskeys[keyChar];
                if (access) {
                    access.lock = false;
                }
            });
        }
        // add tab pages
        tabControl.each(function(child) {
            tabControl.tabPageContainer.appendChild(child.dom.node);
        });
        
        if (this.firstRun) {
            // add container
            tabControl.dom.node.appendChild(tabControl.tabContainer);
            // which parent node?
            if (tabControl.expandable && tabControl.inHover) {
                tabControl.dom.hover.appendChild(tabControl.tabPageContainer);
            } else {
                tabControl.dom.node.appendChild(tabControl.tabPageContainer);
            }
            this.firstRun = false;
        }
        
        // show current tab page
        if (tabControl.currentChild) {
            tabControl.currentChild.show();
        }
    },
    
    update: function() {

        // get table cells
        var tds = this.tds;
        var tabControl = this.container;
        
        // loop children
        tabControl.each(function(child, i, childCount) {
            // exists?
            if (tds[i] !== undefined) {
                // determine class name
                var className = i < (childCount - 1) ? "oxTab" : "oxTabLast";
                // current?
                if (tabControl.expanded && child == tabControl.currentChild) {
                    className += " oxTabCurrent";
                    tds[i].className = className;
                    try {
                        tds[i].firstChild.focus();
                    }
                    catch (e) {
                        // IE might say that this element cannot be focused if it's invisible
                    }
                } else {
                    tds[i].className = className;
                }
            }
        });
    }
});
