/**
 * @name Container
 * @memberOf ui
 * @class
 * A container is a component that can contain other components. You can use
 * it to create complex components by composing more simple components.
 * You can provide a template of how you want the components markup be rendered,
 * and a layout of how you want them to be visually postioned.
 * <warning>
 * You might want to use the more feature-loaded {@link ui.Group} component,
 * which inherits from ui.Container.
 * </warning>
 *
 * @augments ui.MVCComponent
 */
module("ui.Container")
.require("ui.Core","ui.layout.FlexLayout")
.declare("ui.Container").extend("ui.MVCComponent")
.as(
    /**@lends ui.Container.prototype*/
    {

    options:{
        /**
         *@cfg view
         *view file
         */
        view:"%basePath%/resources/views/ContainerView.html",
        layout:"flex",
        layoutOptions:{
            childSelector:".ui-container-child"
        }
    },

    events:["childAdded",
            "childRemoved"],

    styles:["%basePath%/resources/styles/ui-container.css"],

    /**
     * Internal object responsible for generating ids for childs that are
     * added without a specified id.
     */
    idManager:{
        idCount:0,
        generateID: function(comp){
            var type = comp.widgetName || "widget";
            return type + this.idCount++;
        }
    },

    _init: function(){
        this.base();
        this._childs = {};
        this._childIDs = [];
        $.extend(this.viewData,{
            childs:this._childIDs,
            layout:this.options.layout
        })
        var layout = ui.ComponentManager.getClassByAlias(this.options.layout)
                     || module.get(this.options.layout);
        if(layout){
            this.layout = new layout(this.element, this.options.layoutOptions);
        }

        this.element.bind("resize", $.proxy(this,"_onResize"));
    },

    _onResize:function(){
        this.layout && this.layout.doLayout();
    },

    /**
     * Returns the current count of children components added to the container.
     * @returns {Number} The count of children.
     */
    numChildren: function(){
        return this._childIDs.length
    },

    /**
     * Checks if a given component instance has been added to the container.
     * @param {ui.Component} child
     * The component instance to check.
     * @returns {Boolean}
     * <code>true</code> if the component has been added, <code>false</code>
     * otherwise.
     */
    contains: function(child){
        if(typeof child == "string"){
            return (this._childs[child])? true:false;
        }
        else if (typeof child == "object"){
            return (this.getChildId(child))? true:false;
        }
        else return false;
    },

    /**
     * Adds a child to the container.
     * @param {ui.Component} child
     * The component instance to add to the container.
     * @param {string} [id]
     * An identifying string for the component in the container childs list. If
     * not passed the container assigns a unique generated id.
     * @param {Number} [index]
     * The position on the childs list on where to add the child component.
     * If not passed the child is added at the last position by default.
     */
    addChild: function(child,id, index){
        if(!module.typeOf(child,"ui.Component")){
            throw new Error("Child must be a component.");
        }
        if(!this.contains(child)){
            id = id || this.idManager.generateID(child);
            this._childs[id] = child;
            index = (index != null)? index :this._childIDs.length;
            this._childIDs.splice(index,0,id);
            this.updateDisplay();
            
            if(child.parent){
                child.parent.removeChild(child);
            }
            
            child.id = id;
            child.parent = this;

            var e = {type:"childAdded"};
            e.childID = id;
            e.child = child;
            this.trigger(e);
        }
        else{
            //if already added, check if same id
            //and move id to last position so it will
            //be redered last
            var oldID = this.getChildId(child);
            var idx = this._childIDs.indexOf(oldID);
            this._childIDs.splice(idx, 1);
            this._childIDs.push(id);
            if(id !== oldID){
                //if new id, change
                this._childs[id] = this._childs[oldID];
                delete this._childs[oldID];
            }
            this.updateDisplay();

            var e = {type:"childUpdated"};
            e.childID = id;
            e.child = child;
            this.trigger(e);
        }
    },

    /**
     * Removes a component instance from the container, if previously added.
     * @param {ui.Component} child
     * The component instance to remove from the childs list.
     */
    removeChild: function(child){
        if(this.contains(child)){
            var id;
            if(typeof child == "string"){
                id = child;
                child = this._childs[child];
            }
            else if (typeof child == "object"){
                id = this.getChildId(child);
            }
       
            this.__toRemoveChild = child;
            this._childIDs.splice(this._childIDs.indexOf(id),1);
            this.updateDisplay();
            
            delete child.parent;
            delete child.id;

            var e = {type:"childRemoved"};
            e.childID = id;
            e.child = child;
            this.trigger(e);       
        }
        else{
            throw new Error("Child is not in the container.")
        }
    },

    /**
     * Returns the component child mapped in the container with a given id.
     * @param {string} id
     * The id of the child component to get.
     * @returns {ui.Component}
     * The child component mapped with the given id, <code>null</code> if
     * no child is mapped with the given id.
     */
    getChildById: function(id){
        return this._childs[id] || null;
    },

    /**
     * Returns the id string for a given component if it was added to the
     * container.
     * @param {ui.Component} child
     * The child component to get the id from.
     * @returns {string}
     * The child mapped id, <code>undefined</code> if the child component
     * passed was not added to the container.
     */
    getChildId: function(child){
        var self = this;
        var childID;
        $.each(this._childIDs, function(i, id){
            if(self._childs[id]===child){
                childID = id;
                return false; //break
            }
            else return true //continue
        })

        return childID;
    },

    children: function(){
        var self = this;
        var childs = [];
        jQuery.each(self._childIDs, function(_,ch){
            childs.push(self._childs[ch]);
        });
        return childs;
    },

    updateDisplay: function(){
        this.base();
        var self = this;
        var childs = $.makeArray(this._childIDs);
        var placeholders = this._getComponentPlaceholders();
        $.each(childs, function(i,id){
            var comp;
            for (var e = 0; e < placeholders.length; e++) {
                if(placeholders[e].id == id){
                    comp = placeholders[e];
                }
            }

            if(comp){
                comp = $(comp);
                var child = self._childs[id];
                var attrs = comp.getAttributes();
                if(attrs["class"]){
                    child.element.addClass(attrs["class"]);
                    delete attrs["class"];
                }
                if(attrs["style"]){
                    child.element.css(attrs["style"]);
                    delete attrs["style"];
                }
                child.element.attr(attrs);
                comp.replaceWith(child.element);
            }
        });
        
        var removeChild = this.__toRemoveChild;
        if(removeChild){
            removeChild.element.remove();            
            delete this.__toRemoveChild;
        }

        this.layout && this.layout.doLayout();
    },

    _getComponentPlaceholders: function(){
        var result;
        result = this.element[0].getElementsByTagName("component");
        if(result.length == 0){
            result = this.element[0].getElementsByTagName("bhv:component");
        }
        return result;
    }
});


// SIG // Begin signature block
// SIG // MIIMzQYJKoZIhvcNAQcCoIIMvjCCDLoCAQExDjAMBggq
// SIG // hkiG9w0CBQUAMGYGCisGAQQBgjcCAQSgWDBWMDIGCisG
// SIG // AQQBgjcCAR4wJAIBAQQQEODJBs441BGiowAQS9NQkAIB
// SIG // AAIBAAIBAAIBAAIBADAgMAwGCCqGSIb3DQIFBQAEEEtH
// SIG // sjF8Aa0KwGR0INktZmWgggoPMIIE/DCCBGWgAwIBAgIQ
// SIG // ZVIm4bIuGOFZDymFrCLnXDANBgkqhkiG9w0BAQUFADBf
// SIG // MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s
// SIG // IEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVibGljIFBy
// SIG // aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN
// SIG // MDkwNTIxMDAwMDAwWhcNMTkwNTIwMjM1OTU5WjCBtjEL
// SIG // MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJ
// SIG // bmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
// SIG // b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0
// SIG // cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwOTEw
// SIG // MC4GA1UEAxMnVmVyaVNpZ24gQ2xhc3MgMyBDb2RlIFNp
// SIG // Z25pbmcgMjAwOS0yIENBMIIBIjANBgkqhkiG9w0BAQEF
// SIG // AAOCAQ8AMIIBCgKCAQEAvmcdtGCqEElvVhd8Zslehg3V
// SIG // 8ayncYOOi4n4iASJFQa6LYQhleTRnFBM+9IivdrysjU7
// SIG // Ho/DCfv8Ey5av4l8PTslHvbzWHuc9AG1xgq4gM6+J3Rh
// SIG // ZydNauXsgWFYeaPgFxASFSew4U00fytHIES53mYkZorN
// SIG // T7ofxTjIVJDhcvYZZnVquUlozzh5DaowqNssYEie16oU
// SIG // AamD1ziRMDkTlgM6fEBUtq3gLxuD3KgRUj4Cs9cr/SG2
// SIG // p1yjDwupphBQDjQuTafOyV4l1Iy88258KbwBXfwxh1rV
// SIG // jIVnWIgZoL818OoroyHnkPaD5ajtYHhee2CD/VcLXUEN
// SIG // Y1Rg1kMh7wIDAQABo4IB2zCCAdcwEgYDVR0TAQH/BAgw
// SIG // BgEB/wIBADBwBgNVHSAEaTBnMGUGC2CGSAGG+EUBBxcD
// SIG // MFYwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlz
// SIG // aWduLmNvbS9jcHMwKgYIKwYBBQUHAgIwHhocaHR0cHM6
// SIG // Ly93d3cudmVyaXNpZ24uY29tL3JwYTAOBgNVHQ8BAf8E
// SIG // BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
// SIG // aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5r
// SIG // w8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNp
// SIG // Z24uY29tL3ZzbG9nby5naWYwHQYDVR0lBBYwFAYIKwYB
// SIG // BQUHAwIGCCsGAQUFBwMDMDQGCCsGAQUFBwEBBCgwJjAk
// SIG // BggrBgEFBQcwAYYYaHR0cDovL29jc3AudmVyaXNpZ24u
// SIG // Y29tMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwu
// SIG // dmVyaXNpZ24uY29tL3BjYTMuY3JsMCkGA1UdEQQiMCCk
// SIG // HjAcMRowGAYDVQQDExFDbGFzczNDQTIwNDgtMS01NTAd
// SIG // BgNVHQ4EFgQUl9BrqCZwyKE/lB8ILcQ1m6ShHvIwDQYJ
// SIG // KoZIhvcNAQEFBQADgYEAiwPA3ZTYQaJhabAVqHjHMMaQ
// SIG // PH5C9yS25INzFwR/BBCcoeL6gS/rwMpE53LgULZVECCD
// SIG // bpaS5JpRarQ3MdylLeuMAMcdT+dNMrqF+E6++mdVZfBq
// SIG // vnrKZDgaEBB4RXYx84Z6Aw9gwrNdnfaLZnaCG1nhg+W9
// SIG // SaU4VuXeQXcOWA8wggULMIID86ADAgECAhAjTaBL0kKF
// SIG // PErLmuhhwhm7MA0GCSqGSIb3DQEBBQUAMIG2MQswCQYD
// SIG // VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4x
// SIG // HzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx
// SIG // OzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov
// SIG // L3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTA5MTAwLgYD
// SIG // VQQDEydWZXJpU2lnbiBDbGFzcyAzIENvZGUgU2lnbmlu
// SIG // ZyAyMDA5LTIgQ0EwHhcNMDkwODI3MDAwMDAwWhcNMTIw
// SIG // OTIwMjM1OTU5WjCByDELMAkGA1UEBhMCVVMxEzARBgNV
// SIG // BAgTCkNhbGlmb3JuaWExEzARBgNVBAcTClNhbiBSYWZh
// SIG // ZWwxFjAUBgNVBAoUDUF1dG9kZXNrLCBJbmMxPjA8BgNV
// SIG // BAsTNURpZ2l0YWwgSUQgQ2xhc3MgMyAtIE1pY3Jvc29m
// SIG // dCBTb2Z0d2FyZSBWYWxpZGF0aW9uIHYyMR8wHQYDVQQL
// SIG // FBZEZXNpZ24gU29sdXRpb25zIEdyb3VwMRYwFAYDVQQD
// SIG // FA1BdXRvZGVzaywgSW5jMIGfMA0GCSqGSIb3DQEBAQUA
// SIG // A4GNADCBiQKBgQC1R1YKdvQF2Rj4+knWfj81afUtVyep
// SIG // GF2P4tcYD53qlYmYi9t9Csc6PMWlUZhMGbOceQKYcBjc
// SIG // mWvyghJnoaEQ6796ZcsLD0pMH2R4SpV/SjxiQ280beig
// SIG // NerJS5X+ftOMCs1qSQ1LXlRFEohaewkNWsIp/+f1Y0vE
// SIG // dGzggnEKOQIDAQABo4IBgzCCAX8wCQYDVR0TBAIwADAO
// SIG // BgNVHQ8BAf8EBAMCB4AwRAYDVR0fBD0wOzA5oDegNYYz
// SIG // aHR0cDovL2NzYzMtMjAwOS0yLWNybC52ZXJpc2lnbi5j
// SIG // b20vQ1NDMy0yMDA5LTIuY3JsMEQGA1UdIAQ9MDswOQYL
// SIG // YIZIAYb4RQEHFwMwKjAoBggrBgEFBQcCARYcaHR0cHM6
// SIG // Ly93d3cudmVyaXNpZ24uY29tL3JwYTATBgNVHSUEDDAK
// SIG // BggrBgEFBQcDAzB1BggrBgEFBQcBAQRpMGcwJAYIKwYB
// SIG // BQUHMAGGGGh0dHA6Ly9vY3NwLnZlcmlzaWduLmNvbTA/
// SIG // BggrBgEFBQcwAoYzaHR0cDovL2NzYzMtMjAwOS0yLWFp
// SIG // YS52ZXJpc2lnbi5jb20vQ1NDMy0yMDA5LTIuY2VyMB8G
// SIG // A1UdIwQYMBaAFJfQa6gmcMihP5QfCC3ENZukoR7yMBEG
// SIG // CWCGSAGG+EIBAQQEAwIEEDAWBgorBgEEAYI3AgEbBAgw
// SIG // BgEBAAEB/zANBgkqhkiG9w0BAQUFAAOCAQEAIfxkh8Fd
// SIG // IHK+qtTf+9Eq5fjkk5gMMTQCOa+2aR7mqDzLfIFRGQzr
// SIG // tcc5/izsb/wPLUwdw1cRpnxO8/qLA2Ol+b99FONTOyyc
// SIG // Y8unwviYhdEjuFmqHkyC5MUYroZEjvTObFkkgN98Y48h
// SIG // C+mG2hdlVKXR0zr9r5q/rmmivVWbojvcYKHoW31O5OcM
// SIG // PsrWuOD305Ygmpck/91iopE3UN4tfeWYhzNj1F6Ai4Xa
// SIG // 5KiaMcs3zmoZ+6SePyI2YUgtff6yvy/rk8KVT41KGD2h
// SIG // fC+QrtVSkoDWP/MDtLjbTPCWElC1NWSEKowRI8t2x594
// SIG // Skjnzu/W5Lh97ixircOuM4IvBzGCAigwggIkAgEBMIHL
// SIG // MIG2MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNp
// SIG // Z24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
// SIG // IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh
// SIG // dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChj
// SIG // KTA5MTAwLgYDVQQDEydWZXJpU2lnbiBDbGFzcyAzIENv
// SIG // ZGUgU2lnbmluZyAyMDA5LTIgQ0ECECNNoEvSQoU8Ssua
// SIG // 6GHCGbswDAYIKoZIhvcNAgUFAKCBsDAZBgkqhkiG9w0B
// SIG // CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
// SIG // DAYKKwYBBAGCNwIBFTAfBgkqhkiG9w0BCQQxEgQQgoxS
// SIG // ZipGRwhygYcNOAoDTzBUBgorBgEEAYI3AgEMMUYwRKAm
// SIG // gCQAQQB1AHQAbwBkAGUAcwBrACAAQwBvAG0AcABvAG4A
// SIG // ZQBuAHShGoAYaHR0cDovL3d3dy5hdXRvZGVzay5jb20g
// SIG // MA0GCSqGSIb3DQEBAQUABIGAOTN5V5IHSgHh3XFDrC8o
// SIG // DHHhSkx7+2CsEUZbAXPLOAwhDz3sEv3XftQFOgF1FUV/
// SIG // VEu2cLoSL9CmJ9Yb2GoNJ16zcAe+GMbDHtwMBs+M5Pnq
// SIG // MCHVcMoYAfDnowNbH9wXxhCGHSEI4DP5MRuSwq1K1cK8
// SIG // 6pxOVvzhAjta8kpOU2M=
// SIG // End signature block
