/**
 * 
 * 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.LayoutManager = Class.extend({
/** @lends ox.gui.LayoutManager.prototype */
    
    getClass: function() { return "ox.gui.LayoutManager"; },
    
    /** 
     * The basic layout manager
     * @constructs
     * @param {ox.gui.Container} The container widget that should be managed
     * by the layout manager.
     */
    construct: function(container) {
        this.container = container || null;
        this.nannies = {};
        this.decorator = null;
        this.firstRun = true;
    },
    
    /**
     * This will layout the container widget.
     */
    doLayout: function() {
    },

    /**
     * This will only do updates on the container widget.
     */
    update: function() {
        this.doLayout();
    },

    /**
     * Handles a resize of the container's children or its parent container.
     */
    resize: function() {
    },
    
    /**
     * Handle i18n changes
     */
    i18nHandler: function () {
    },
    
    getNanny: function (id) {
        return typeof this.nannies[id] == "undefined" ? null : this.nannies[id];
    },
    
    createNanny: function (id, parentNode) {
        var nanny = this.nannies[id] = { node: $("<div/>"), processed: false };
        if (typeof parentNode != "undefined") {
            nanny.node.appendTo(parentNode);
        }
        return nanny;
    },
    
    setUnprocessed: function () {
        for (var id in this.nannies) {
            this.nannies[id].processed = false;
        }
    },

    removeUnprocessed: function () {
        for (var id in this.nannies) {
            if (this.nannies[id].processed === false) {
                this.nannies[id].node.remove();
                delete this.nannies[id];
            }
        }
    },
    
    destroy: function() {
        // container ref
        this.container = null;
        // decorator
        if (this.decorator) {
            this.decorator.remove();
        }
        // nannies
        for (var id in this.nannies) {
             this.nannies[id].node.remove();
             delete this.nannies[id];
        }
    },
    
    park: function (child) {
        if (child === undefined) {
            // move all children's DOM nodes
            // similar to remove but saves all event handlers
            if (this.container) {
                var park = $("<div/>");
                this.container.each(function (child) {
                    park.append(child.dom.node);
                });
            }
        } else if (child) {
            var park = $("<div/>").append(child.dom.node);
        }
    }
});

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

ox.gui.FlowLayout = ox.gui.LayoutManager.extend({
/** @lends ox.gui.FlowLayout.prototype */
    
    getClass: function() { return "ox.gui.FlowLayout"; },
    
    /** 
     * A typical flow layout manager. Actually, the browser will take care
     * of the layout.
     * @extends ox.gui.LayoutManager
     * @constructs
     * @param {ox.gui.Container} The container widget that should be managed
     * by the layout manager.
     */
    construct: function(container) {
        this._super(container);
    },
    
    doLayout: function() {
        
        // local vars
        var con = this.container;
        var targetDOMNode = con.kindergarten;
        
        // loop children
        var $i=0,$c=con.getChildren(),$l=$c.length; for (;$i<$l;$i++) { var child = $c[$i]; // fast loop
            // add to DOM & show
            //child.validate();
            targetDOMNode.appendChild(child.dom.node);
        }
    }
});

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

ox.gui.HBoxLayout = ox.gui.LayoutManager.extend({
    /** @lends ox.gui.HBoxLayout.prototype */
        
    getClass: function() { return "ox.gui.HBoxLayout"; },
    
    /** 
     * A HBox layout manager.
     * @extends ox.gui.LayoutManager
     * @constructs
     * @param {ox.gui.Container} The container widget that should be managed
     * by the layout manager.
     */
    construct: function(container) {
        this._super(container);
    },
    
    doLayout: function() {        
        // local vars
        var con = this.container, tr = $("<tr/>");
        $(con.kindergarten).append($("<table/>").css({ width: "100%" }).append(tr));
        
        // loop children
        var $i=0,$c=con.getChildren(),$l=$c.length; 
        for (;$i<$l;$i++) { 
            var child = $c[$i]; // fast loop
            var td = $("<td/>");
//            for (var attr in child.layout) {
//                switch (attr) {
//                    case "valign":
//                    case "align":
//                    case "width":
//                    case "height":
//                    case "nowrap":
//                        td.attr(attr, child.layout[attr]);
//                        break;
//                }
//            }
            tr.append(td.attr(child.layout || {}).append(child.dom.node));
        }
    }
});

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

ox.gui.BlockFlowLayout = ox.gui.LayoutManager.extend({
/** @lends ox.gui.BlockFlowLayout.prototype */
    
    getClass: function() { return "ox.gui.BlockFlowLayout"; },
    
    /** 
     * A vertical flow layout manager.
     * @extends ox.gui.LayoutManager
     * @constructs
     * @param {ox.gui.Container} The container widget that should be managed
     * by the layout manager.
     */
    construct: function(container) {
        this._super(container);
        this.inheritHeight = true;
    },
    
    doLayout: function() {
        
        // local vars
        var con = this.container;
        var targetDOMNode = con.kindergarten;
        var top = 0;
        
        // loop children
        var $i=0,$c=con.getChildren(),$l=$c.length; for (;$i<$l;$i++) { var child = $c[$i]; // fast loop
            // adjust child
            var div = newnode("div", {
                position: "absolute", 'top': top + "px", left: "0px", right: "0px"
            });
            // add to DOM & show
            //child.validate();
            div.appendChild(child.dom.node);
            targetDOMNode.appendChild(div);
            var h = $(child.dom.node).height();
            div.style.height = h + "px";
            top += h;
        }
        // windows e.g. do not inherit the height
        if (con.layout.inheritHeight) {
            targetDOMNode.style.height = top + "px";
        }
    },
    
    resize: function() {
        
        var con = this.container;
        var targetDOMNode = con.kindergarten;
        var kinder = targetDOMNode.childNodes;
        var top = 0;
        
        // loop children
        var $i=0,$c=con.getChildren(),$l=$c.length; for (;$i<$l;$i++) { var child = $c[$i]; // fast loop
            // resize child
            //child.resize();
            // adjust height & top
            if (kinder[$i]) {
                var h = $(child.dom.node).height();
                kinder[$i].style.top = top + "px";
                kinder[$i].style.height = h + "px";
                top += h;
            }
        }
        // windows e.g. do not inherit the height
        if (con.layout.inheritHeight) {
            targetDOMNode.style.height = top + "px";
        }
    }
});

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

ox.gui.ZeroLayout = ox.gui.LayoutManager.extend({
/** @lends ox.gui.ZeroLayout.prototype */
    
    getClass: function() { return "ox.gui.ZeroLayout"; },
    
    /** 
     * A zero layout manager. Does nothing.
     * @extends ox.gui.LayoutManager
     * @constructs
     * @param {ox.gui.Container} The container widget that should be managed
     * by the layout manager.
     */
    construct: function(container) {
        this._super(container);
    },
    
    doLayout: function() {
        // loop children
        var con = this.container, z = 0;
        var $i=0, $c=con.getChildren(), $l=$c.length, child, p;
        for (;$i<$l;$i++) {
            child=$c[$i]; // fast loop
            p = child.dom.node.parentNode;
            if (p === null || p.nodeType === 11) {
                con.kindergarten.appendChild(child.dom.node);
                child.dom.node.style.zIndex = z++;
            }
        }
    }
});

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

ox.gui.BorderLayout = ox.gui.LayoutManager.extend({
/** @lends ox.gui.BorderLayout.prototype */
    
    getClass: function() { return "ox.gui.BorderLayout"; },
    
    /** 
     * A typical border layout manager. Children can use "top", "right", "bottom",
     * "left", and "center".
     * @extends ox.gui.LayoutManager
     * @constructs
     * @param {ox.gui.Container} The container widget that should be managed
     * by the layout manager.
     */
    construct: function(container) {
        this._super(container);
        this.nannies = {};
        this.decorator = null;
    },
    
    getOrderedChildrenX: function() {
        // create proper order (top, bottom, left, right, center)
        var con = this.container;
        var children = [null, null, null, null, null];
        var $i=0, $c=con.getChildren(), $l=$c.length; for (;$i<$l;$i++) { var child=$c[$i]; // fast loop
            if (child.layout.position) {
                switch(child.layout.position) {
                case "top": children[0] = child; break;
                case "bottom": children[1] = child; break;
                case "left": children[2] = child; break;
                case "right": children[3] = child; break;
                case "center": children[4] = child; break;
                }
            }
        }
        return children;
    },
    
    getOrderedChildren: function() {
        // create proper order (top, bottom, left, right, center)
        var con = this.container;
        var center = [], nonCenter = [];
        var $i=0, $c=con.getChildren(), $l=$c.length; for (;$i<$l;$i++) { var child=$c[$i]; // fast loop
            if (child.layout.position) {
                switch(child.layout.position) {
                case "top":
                case "right":
                case "bottom":
                case "left":
                    nonCenter.push(child);
                    break;
                case "center":
                    center.push(child);
                    break;
                }
            }
        }
        return $.merge(nonCenter, center);
    },
    
    doLayout: function() {
        
        var con = this.container, kindergarten = con.kindergarten, nanny;
        var top = 0, bottom = 0, left = 0, right = 0, height = 0, width = 0;
        
        // stretch container
        con.addCSSClass("oxStretch");
        
        // add decorator DIV (stretch as well)
        if (this.decorator === null) {
            this.decorator = $("<div/>").addClass("oxStretch");
            if (con.layout.padding) {
                // padding becomes margin
                this.decorator.css("margin", con.layout.padding);
            }
            this.decorator.appendTo(kindergarten);
        }
        
        // mark nannies
        this.setUnprocessed();
        
        var numerize = function (value, defaultValue) {
            var n = parseInt(value, 10);
            return isNaN(n) ? (defaultValue || 0) : n;
        };
        
        // loop children
        var $i=0, $c=this.getOrderedChildren(), $l=$c.length;
        for (;$i<$l;$i++) { var child=$c[$i]; // fast loop
            if (child) {
                var css = null;
                switch (child.layout.position) {
                case "top":
                    height = numerize(child.layout.height, 25);
                    css = {
                        "top": top + "px", "left": left + "px", "right": right + "px", "height": height + "px"
                    };
                    top += height;
                    break;
                case "bottom":
                    height = numerize(child.layout.height, 25);
                    css = {
                        "bottom": bottom + "px", "left": left + "px", "right": right + "px", "height": height + "px"
                    };
                    bottom += height;
                    break;
                case "left":
                    width = numerize(child.layout.width, 25);
                    css = {
                        "top": top + "px", "bottom": bottom + "px", "left": left + "px", "width": width + "px"
                    };
                    left += width;
                    break;
                case "right":
                    width = numerize(child.layout.width, 25);
                    css = {
                        "top": top + "px", "bottom": bottom + "px", "right": right + "px", "width": width + "px"
                    };
                    right += numerize(width, 0);
                    break;
                case "center":
                    css = {
                        "top": top + "px", "left": left + "px", "right": right + "px", "bottom": bottom + "px"
                    };
                    break;
                }
                // add
                if (css !== null) {
                    // get nanny
                    nanny = this.getNanny(child.id);
                    // has no nanny?
                    if (nanny === null) {
                        // create nanny
                        nanny = this.createNanny(child.id, this.decorator);
                    }
                    // added?
                    if (nanny.node.get(0).firstChild != child.dom.node) {
                        nanny.node.empty().append(child.dom.node);
                    }
                    // update nanny
                    nanny.node.css(
                        $.extend({ position: "absolute", overflow: "hidden" }, css)
                    );
                    // mark as processed
                    nanny.processed = true;
                }
            }
        }
        
        // remove unprocessed nannies
        this.removeUnprocessed();
    },
    
    resize: function() {
        
        var con = this.container, kinderkarten = con.kindergarten;
        var top = 0, bottom = 0, left = 0, right = 0;
        var outerDIVs = con.kindergarten.childNodes;
        return;
    }
});
