;
(function ($) {
    /**
     * 布局类,这个类是一个抽象类,不能直接使用
     * @class FR.Layout
     * @extends FR.Widget
     * @abstract
     *
     * @cfg {JSON} options 配置属性
     * @cfg {Boolean} [options.scrollable=false] 内部区域在显示不下的时候是否要显示滚动条
     * @cfg {Boolean} [options.scrollx=false] 内部区域在显示不下的时候是否要显示横向滚动条
     * @cfg {Boolean} [options.scrolly=false] 内部区域在显示不下的时候是否要显示纵向滚动条
     * @cfg {String} [options.widgetBackground=null] 布局容器的背景
     * @cfg {JSON} [options.border=null] 边框
     * @cfg {String} [options.border.type] 边框样式
     * @cfg {String} [options.border.color] 边框颜色
     * @cfg {String} [options.border.width] 边框宽度
     * @cfg {Boolean} [options.border.corner=false] 是否是圆角边框
     * @cfg {String} [options.border.borderStyle] 边框线阴影样式
     */
    FR.Layout = FR.extend(FR.Widget, {
        /**
         * @private
         */
        _defaultConfig: function () {
            return $.extend(FR.Layout.superclass._defaultConfig.apply(), {
                scrollable: false,
                scrollx: false,
                scrolly: false,
                widgetBackground: null,
                border: null,
                onClick: null
            });
        },
        /**
         * @private
         */
        _init: function () {
            FR.Layout.superclass._init.apply(this, arguments);
            this._init4Margin();
            this._init4Style();
            this._init4Scroll();
            this._init4Click();
        },
        /**
         * 初始化布局与外层容器的边间距
         * @private
         */
        _init4Margin: function () {
            if (this.options.marginTop) {
                this.element.css('marginTop', this.options.marginTop);
                this.marginHeight = (this.marginHeight || 0) + parseInt(this.options.marginTop);
            }
            if (this.options.marginLeft) {
                this.element.css('marginLeft', this.options.marginLeft);
                this.marginWidth = (this.marginWidth || 0) + parseInt(this.options.marginLeft);
            }
            if (this.options.marginBottom) {
                this.element.css('marginBottom', this.options.marginBottom);
                this.marginHeight = (this.marginHeight || 0) + parseInt(this.options.marginBottom);
            }
            if (this.options.marginRight) {
                this.element.css('marginRight', this.options.marginRight);
                this.marginWidth = (this.marginWidth || 0) + parseInt(this.options.marginRight);
            }
        },
        /**
         * 初始化布局样式,包括背景,边框,圆角
         * @private
         */
        _init4Style: function () {
            this._initBackGround();
            var border = this.options.border;
            if (border) {
                this.element.css('border-style', border.type);
                this.element.css('border-color', border.color);
                this.element.css('border-width', border.width);
                if (border.corner) {
                    this.element.css('border-radius', "15px 15px 15px 15px");
                    if ($.browser.msie) {
                        this.element.addClass('ie-border-radius');
                    }
                }
                if (!($.browser.msie && $.browser.version < '9.0')) {
                    this.element.css('box-shadow', border.borderStyle);
                }
            }
        },
        _initBackGround: function () {
            //设置控件背景
            if (!this.options.widgetBackground) {
                return;
            }
            if (this.options.type && this.options.type == 'fit') {
                this._initFitBackground();
                return;
            }
            var alpha = this.options.widgetOpacity;
            if (!alpha) {
                this.element.css('background', this.options.widgetBackground.background);
                return;
            }
            //因为有透明度, 如果直接设置opacity属性, 会被子层div继承, 因此平级放一个背景div
            this.$background = $("<div class='widgetBackground'></div>");
            //IE
            this.$background.css('filter', 'alpha(opacity=' + alpha * 100 + ')');
            //Chrome ff
            this.$background.css('opacity', alpha);
            this.element.css('background', this.options.widgetBackground.background);
            this.$background.prependTo(this.element);
        },
        /**
         * 自适应布局做为表单主体,背景要覆盖内边距区域,加一层同级div放在前面
         */
        _initFitBackground: function () {
            var parent = this.element.parent();
            var margin = this.element.margin();
            var w = this.element.width() + (margin.left || 0) + (margin.right || 0);
            var h = this.element.height() + (margin.top || 0) + (margin.bottom || 0);
            if (this.$background && parent.has(this.$background).length > 0) {
                this.$background.css('width', (w || 0));
                this.$background.css('height', (h || 0));
                this.$background.css('top', this.element.css('top'));
                this.$background.css('left', this.element.css('left'));
                return;
            }
            this.$background = $("<div class='widgetBackground'></div>");
            this.$background.css('position', 'absolute');
            var alpha = this.options.widgetOpacity;
            if (alpha) {
                //IE
                this.$background.css('filter', 'alpha(opacity=' + alpha * 100 + ')');
                //Chrome ff
                this.$background.css('opacity', alpha);
            }
            this.$background.css('width', (w || 0));
            this.$background.css('height', (h || 0));
            FR.setBackground(this.$background, this.options.widgetBackground, h);
            this.$background.prependTo(parent);
        },
        /**
         * 初始化布局的滚动形态
         * @private
         */
        _init4Scroll: function () {
            if (!this.options.scrollable) {
                this.element.css("overflow", "hidden");
            } else {
                this.element.css("overflow", "auto")
            }
            if (this.options.scrollx) {
                this.element.css({
                    "overflow-x": "auto",
                    "overflow-y": "hidden"
                });
            }
            if (this.options.scrolly) {
                this.element.css({
                    "overflow-x": "hidden",
                    "overflow-y": "auto"
                });
            }
        },
        /**
         * 初始化点击事件
         * @private
         */
        _init4Click: function () {
            var self = this;
            this.element.click(function (e) {
                self.fireEvent(FR.Events.CLICK, e);
            });
            var opts = this.options;
            if ($.isFunction(opts.onClick)) {
                this.element.bind('click', opts.onClick.createDelegate(this));
            }
        },

        /**
         * 重新布局,一般在改变了布局内部组件的时候都需要重新布局
         */
        doLayout: function () {
            this.element.doLayout(arguments);
        },

        /**
         * 设置布局的最小宽度和最小高度
         */
        setMinSize: function () {
            if (this.element.length > 0 && this.element[0].tagName == "BODY") {
                var minSize = this.element["minimumSize"]();
                this.element.css({"min-width": minSize.width, "min-height": minSize.height});
                $("html").css("overflow", "auto");
            }
        },

        /**
         * 初始化后事件
         * @private
         */
        _confirmEvents: function () {
            /*do nothing*/
        }
    });

    /**
     * 绝对布局,里面所有的元素由有横坐标、纵坐标、长以及宽属性决定其位置和大小
     *
     *     @example
     *     var renderEl = $('body');
     *     var layout = new FR.AbsoluteLayout({
     *              renderEl : renderEl,
     *              items : [
     *                  {
     *                      type : 'button',
     *                      text : '(0, 0, 120, 24)',
     *                      x : 0,
     *                      y : 0,
     *                      width : 120,
     *                      height : 24
     *               },
     *               {
     *                      type : 'button',
     *                      text : '(0, 0, auto, auto)',
     *                      x : 40,
     *                      y : 30
     *               }
     *              ]
     *     });
     *     layout.doLayout();
     *
     * @class FR.AbsoluteLayout
     * @extends FR.Layout
     *
     * @cfg {JSON} options 配置属性
     * @cfg {Array} options.items 字组件数组
     */
    FR.AbsoluteLayout = FR.extend(FR.Layout, {

        _defaultConfig: function () {
            return $.extend(FR.AbsoluteLayout.superclass._defaultConfig.apply(), {
                baseCls: 'fr-absolutelayout',
                scrollable: false
            });
        },

        _init: function () {
            FR.AbsoluteLayout.superclass._init.apply(this, arguments);
            var opts = this.options;
            this.element.addClass(opts.baseCls);
            if (!$.isArray(opts.items)) {
                opts.items = [];
                return;
            }
            var items = opts.items, i, len = items.length;
            opts.widgets = [];
            var $container = this.element;
            if (opts.scrollable) {
                $container = $('<div class="fr-core-layout-scrollable">').css({
                    position: 'absolute',
                    top: 0,
                    left: 0
                }).appendTo(this.element);
                opts.scrollContainer = $container;
            }
            for (i = 0; i < len; i++) {
                var itemConfig = items[i];
                // richie:复制父容器的样式给子控件
                //itemConfig.style = o.style;
                //Sean:改成如果控件有自己定义的style,则不使用上级控件传递下来的style,所有布局都统一
                if (!itemConfig.style) {
                    itemConfig.style = opts.style;
                }
                if (itemConfig.type) {
                    itemConfig.el = itemConfig;
                }
                if (itemConfig.el.type) {
                    var widget = FR.createWidget($.extend(itemConfig.el, {
                        resultWidgets: opts.resultWidgets
                    }));
                    //Sean: TODO 表单改好后这个属性统一成resultWidgets,这个可以删
                    opts.widgets.push(widget);
                    var element = widget.element;
                    element.css({left: itemConfig.x, top: itemConfig.y, position: "absolute"});
                    // richer:由于已经生成了widget,就没必要再保存原来的JSON对象了
                    items[i].el = element;
                    $container.append(element);
                    widget.doResize({width: itemConfig.width, height: itemConfig.height});
                } else if (itemConfig.el instanceof $) {
                    var element = itemConfig.el;
                    element.css({left: itemConfig.x, top: itemConfig.y, position: "absolute"});
                    $container.append(element);
                }
            }
            this.element.data('jlayout', jLayout.absolute(opts));
            // IE杂项模式下,如果高度是0,会是几十像素的高度,有边框的情况宽度为0不显示
            if ($.browser.msie && !$.support.boxModel) {
                if (opts.height === 0) {
                    opts.height = 1;
                }
                if (opts.width === 0) {
                    opts.width = 1;
                }
            }
        },

        doResize: function (give) {
            FR.AbsoluteLayout.superclass.doResize.call(this, give);
            var opts = this.options;
            this.element.css({
                width: (give ? (give.width || opts.width) : opts.width),
                height: give ? (give.height || opts.height) : opts.height,
                left: give ? (give.left || opts.left) : opts.left,
                top: give ? (give.top || opts.top) : opts.top
            });
            //wei : 里面的控件也要doResize一下的。
            for (var i = 0, len = this.options.widgets.length; i < len; i++) {
                var widget = this.options.widgets[i];
                if ($.isFunction(widget.doResize)) {
                    //我们有的控件判断了doResize的参数是否空,是就用option.width/height,有的就没做判断,调用doResize会抛错。
                    widget.doResize({});
                }
            }
        },
        doLayout: function () {
            FR.AbsoluteLayout.superclass.doLayout.apply(this, arguments);
            for (var i = 0, len = this.options.widgets.length; i < len; i++) {
                var widget = this.options.widgets[i];
                if ($.isFunction(widget.doLayout)) {
                    widget.doLayout();
                }
            }
        }
    });
    $.shortcut('absolute', FR.AbsoluteLayout);

    /**
     * 流式布局
     *
     *     @example
     *     var $area = $('<div>').css({width: 300, height:300, background:'gray'}).appendTo('body');
     *     var editor = new FR.FlowLayout({
     *          renderEl : $area,
     *          hgap : 5,
     *          vgap : 5,
     *          items : [
     *              {el: {type: 'button', text: 'flow1', width: 60, height: 50}},
     *              {el: {type: 'button', text: 'flow2', width: 60, height: 30}},
     *              {el: {type: 'button', text: 'flow3', width: 60, height: 30}},
     *              {el: {type: 'button', text: 'flow4', width: 90, height: 30}},
     *              {el: {type: 'button', text: 'flow5', width: 90, height: 30}},
     *              {el: {type: 'button', text: 'flow6', width: 90, height: 30}},
     *              {el: {type: 'button', text: 'flow7', width: 90, height: 30}},
     *              {el: {type: 'button', text: 'flow8', width: 180, height: 30}}
     *          ]
     *     });
     *     editor.doLayout();
     *
     * @class FR.FlowLayout
     * @extends FR.Layout
     *
     * @cfg {JSON} options 配置属性
     * @cfg {Number} [options.hgap=5] 水平间隙
     * @cfg {Number} [options.vgap=5] 垂直间隙
     */
    FR.FlowLayout = FR.extend(FR.Layout, /**@class FR.FlowLayout*/{

        _defaultConfig: function () {
            return $.extend(FR.FlowLayout.superclass._defaultConfig.apply(), {
                hgap: 5,
                vgap: 5,
                baseCls: 'fr-flowlayout'
            });
        },

        _init: function () {
            FR.FlowLayout.superclass._init.apply(this, arguments);
            var opts = this.options;
            this.element.addClass(opts.baseCls);
            var items = opts.items, i, len = items.length;
            opts.widgets = [];
            for (i = 0; i < len; i++) {
                var itemConfig = items[i];
                if (itemConfig.el && itemConfig.el.type) {
                    if (!itemConfig.el.style) {
                        itemConfig.el.style = opts.style;
                    }
                    var widget = FR.createWidget($.extend(itemConfig.el, {
                        resultWidgets: opts.resultWidgets
                    }));
                    // 将子widget放到widgets对象里面,以便在doLayout的时候方便使用
                    opts.widgets.push(widget);
                    var element = widget.element;
                    // richer:由于已经生成了widget,就没必要再保存原来的JSON对象了
                    items[i].el = element;
                    this.element.append(element);
                } else if (itemConfig.el instanceof $) {
                    this.element.append(itemConfig.el);
                }
            }
            this.element.data('jlayout', jLayout.flow(opts));
        },

        doResize: function (give) {
            FR.FlowLayout.superclass.doResize.call(this, give);
            var opts = this.options;
            this.element.css({
                width: opts.width,
                height: opts.height,
                left: opts.left,
                top: opts.top
            });
        },

        doLayout: function () {
            FR.FlowLayout.superclass.doLayout.apply(this, arguments);
        }
    });
    $.shortcut("flow", FR.FlowLayout);

    /**
     * 格子布局
     *
     *     @example
     *     var $area = $('<div>').css({width: 300, height:300, background:'gray'}).appendTo('body');
     *     var layout = new FR.GridLayout({
     *              renderEl : $area,
     *              columns: 4,
     *              rows : 3,
     *              widths : ['auto', 30, 'auto', 'auto'],//手动设置宽度,auto表示把除手动设置的以外的宽度均分
     *              heights : ['auto', 'auto', 'auto'],//手动设置宽度,auto表示把除手动设置的以外的高度均分
     *              items : [
     *                  { column : 0,
     *                    row : 0,
     *                    el : {type : 'button', text : 'button1'}
     *                  },
     *                  { column : 1,
     *                    row : 1,
     *                    el : $('<div>').css({background : 'green'})
     *                  },
     *                  { column : 3,
     *                    row : 2,
     *                    el : $('<div>').css({background : 'red'})
     *                  }
     *              ]
     *     });
     *     layout.doLayout();
     *
     * @class FR.GridLayout
     * @extends FR.Layout
     *
     * @cfg {JSON} options 配置属性
     * @cfg {Number} [options.hgap=0] 子组件之间的水平间隙
     * @cfg {Number} [options.vgap=0] 子组件之间的垂直间隙
     * @cfg {Number} [options.leftGap=0] 左边留的空隙
     * @cfg {Number} [options.rightGap=0] 右边留的空隙
     * @cfg {Number} [options.topGap=0] 上边留的空隙
     * @cfg {Number} [options.bottomGap=0] 下边留的空隙
     */
    FR.GridLayout = FR.extend(FR.Layout, {

        _defaultConfig: function () {
            return $.extend(FR.GridLayout.superclass._defaultConfig.apply(), {
                hgap: 0,
                vgap: 0,
                // 左边留的空隙
                leftGap: 0,
                rightGap: 0,
                // 上边留的空隙
                topGap: 0,
                bottomGap: 0,
                baseCls: 'fr-gridlayout'
            });
        },

        _init: function () {
            FR.GridLayout.superclass._init.apply(this, arguments);
            var opts = this.options;
            this.element.addClass(opts.baseCls);
            var items = opts.items, len = items.length;
            opts.widgets = [];
            for (var j = 0; j < len; j++) {
                var itemConfig = items[j];
                if (itemConfig.el.type) {
                    // 根据items的配置文件生成控件
                    if (!itemConfig.el.style) {
                        itemConfig.el.style = opts.style;
                    }
                    var widget = FR.createWidget($.extend(itemConfig.el, {
                        resultWidgets: opts.resultWidgets
                    }));
                    opts.widgets.push(widget);
                    var element = widget.element;
                } else {
                    element = itemConfig.el;
                }
                itemConfig.el = element;
                this.element.append(element);
            }
            this.element.data('jlayout', jLayout.gridLayout(opts));
        },

        doResize: function (give) {
            FR.GridLayout.superclass.doResize.call(this, give);
            var opts = this.options;
            this.element.css({
                width: (give ? (give.width || opts.width) : opts.width),
                height: (give ? (give.height || opts.height) : opts.height),
                left: give ? (give.left || opts.left) : opts.left,
                top: give ? (give.top || opts.top) : opts.top
            });
        },

        doLayout: function () {
            FR.GridLayout.superclass.doLayout.apply(this, arguments);
        }
    });
    $.shortcut("grid", FR.GridLayout);


    /**
     * 冻结格子布局
     * @class FR.FrozenGridLayout
     * @extends FR.Layout
     * @private
     */
    FR.FrozenGridLayout = FR.extend(FR.Layout, /**FR.FrozenGridLayout*/{

        _init: function () {
            FR.FrozenGridLayout.superclass._init.apply(this, arguments);
            var $thisEl = this.element;
            var o = this.options;
            $.each(o.items || [], function (idx, item) {
                // alex:只有当regionEl.parent()不是container才调用appendTo方法,原因是appendTo会改变regionEl的位置
                if (item.parent()[0] != $thisEl[0]) {
                    item.appendTo($thisEl);
                }
            });
            $thisEl.data('jlayout', jLayout.grid(o));
            // 如果设置了layout,那么overflow必然要设置为hidden
        },

        doLayout: function () {
            this.element.doLayout();
        },

        doResize: function (give) {
            FR.FrozenGridLayout.superclass.doResize.apply(this, arguments);
            var opts = this.options;
            this.element.css({
                width: (give ? (give.width || opts.width) : opts.width) - (this.marginWidth || 0),
                height: (give ? (give.height || opts.height) : opts.height) - (this.marginHeight || 0),
                left: give ? (give.left || opts.left) : opts.left,
                top: give ? (give.top || opts.top) : opts.top
            });
        }
    });
    $.shortcut("frozengrid", FR.FrozenGridLayout);

    /**
     * 表格布局
     *
     *     @example
     *     var $area = $('<div>').css({width: 300, height:200, background:'gray'}).appendTo('body');
     *     var layout = new FR.TableLayout({
     *           renderEl : $area,
     *           items: [
     *               [
     *                  null,
     *                  {el : {type: 'label', value: 'label1'}},
     *                  {el : {type: 'button', text: '点击放大区域', handler : function() {
     *                           $area.css({width : 500});
     *                           layout.doLayout();
     *                  }}}
     *              ],
     *              [
     *                  null,
     *                  {el : {type: 'label', value: 'label2'}},
     *                  {el : {type: 'button', text: '点击缩小区域', handler : function() {
     *                          $area.css({width : 300});
     *                          layout.doLayout();
     *                  }}}
     *              ],
     *              [
     *
     *                  {el : $("<div>Space</div>")},
     *                  {el : {type: 'label', value: 'label3'}},
     *                  {el : $("<div>I am a div, align to left!</div>")}
     *              ]
     *          ],
     *          columnSize : [40, 0.4, 'fill'],
     *          rowSize : [24, 24, 24],
     *          vgap : 20
     *     });
     *     layout.doLayout();
     *
     * @class FR.TableLayout
     * @extends FR.Layout
     *
     * @cfg {JSON} options 配置属性
     * @cfg {Number} [options.vgap=5] 组件间的垂直间隙
     * @cfg {Array} options.items 子组件
     * @cfg {Array} options.columnSize 列宽数组,由数字组成,该数字的最后一个元素不是数字表示最后一列自适应剩下的宽度
     * @cfg {Array} options.rowSize 行高数组,由数字组成,该数字的最后一个元素不是数字表示最后一列自适应剩下的高度
     */
    FR.TableLayout = FR.extend(FR.Layout, {

        _defaultConfig: function () {
            return $.extend(FR.TableLayout.superclass._defaultConfig.apply(), {
                baseCls: 'fr-layout-table',
                vgap: 5,
                items: [],
                columnSize: [],
                rowSize: [],
                scrollable: false
            });
        },

        _init: function () {
            FR.TableLayout.superclass._init.apply(this, arguments);
            var opts = this.options;
            var items = opts.items;
            var $container = this.element;
            if (opts.scrollable) {
                $container = $('<div class="fr-core-layout-scrollable">').css({
                    position: 'absolute',
                    top: 0,
                    left: 0
                }).appendTo(this.element);
                opts.scrollContainer = $container;
            }
            for (var i = 0; i < items.length; i++) {
                var rowItems = items[i];
                for (var j = 0; j < rowItems.length; j++) {
                    var item = rowItems[j];
                    if (item == null) {
                        continue;
                    }
                    // richie:需要防止item为null的情况
                    if (item && item.el && item.el.type) {
                        if (!item.el.style) {
                            item.el.style = opts.style;
                        }
                        var widget = FR.createWidget($.extend(item.el, {
                            resultWidgets: opts.resultWidgets
                        }));
                        item.element = widget.element;
                    } else if (item && item.el instanceof $) {
                        item.element = item.el;
                    }
                    $container.append(item.element);
                }
            }
            this.element.data('jlayout', jLayout.tableLayout(opts));
        },

        /**
         * 设置表格布局的指定行的可见性,如果该行不可见,其余的行会依次填补掉不可见行的位置
         * @param {Number/Number[]} index 要改变的行或者行组成的数组
         * @param {Boolean} flag 可见性,true表示要设置为可见,false表示要设置为不可见
         */
        setRowVisible: function (index, flag) {
            if ($.isArray(index)) {
                for (var r = 0; r < index.length; r++) {
                    this.setRowVisible(index[r], flag);
                }
            } else {
                var currentItem = this.options.items[index];
                for (var i = 0; i < currentItem.length; i++) {
                    var item = currentItem[i];
                    if (item && item.element) {
                        if (flag === true) {
                            item.element.show();
                        } else {
                            item.element.hide();
                        }
                    }
                }
            }
        },

        /**
         * 判断该行是否可见
         * @param {Number} index 行数索引
         * @returns {Boolean} 返回是否可见
         */
        isRowVisible: function (index) {
            var currentItem = this.options.items[index];
            for (var i = 0; i < currentItem.length; i++) {
                var item = currentItem[i];
                if (item && item.element) {
                    if (!item.element.isVisible()) {
                        return false;
                    }
                }
            }
            return true;
        },

        /**
         * 重置行属性,并刷新布局
         * @param {Number[]} rowSize 行高数组
         */
        refreshRowSize: function (rowSize) {
            this.options.rowSize = rowSize;
            this.element.data('jlayout', jLayout.tableLayout(this.options));
            this.doLayout();
        },

        doResize: function (give) {
            FR.TableLayout.superclass.doResize.call(this, give);
            var opts = this.options;
            this.element.css({
                width: (give ? (give.width || opts.width) : opts.width),
                height: (give ? (give.height || opts.height) : opts.height),
                left: give ? (give.left || opts.left) : opts.left,
                top: give ? (give.top || opts.top) : opts.top
            });
            this.doLayout();
        },

        doLayout: function () {
            FR.TableLayout.superclass.doLayout.apply(this, arguments);
        }
    });
    $.shortcut("tablelayout", FR.TableLayout);

    /**
     * 边界布局
     *
     *     @example
     *     var $area = $('<div>').css({
     *          position : 'absolute',
     *          top : 5,
     *          left : 5,
     *          width: 300,
     *          height:120,
     *          background:'gray'}).appendTo('body');
     *     var editor = new FR.BorderLayout({
     *           renderEl : $area,
     *           items : [
     *               {
     *                   region: 'north',
     *                   height: 20,
     *                   el: {type: 'button', text: 'North'}
     *               },
     *               {
     *                  region: 'south',
     *                  height: 20,
     *                  el: {type: 'button', text: 'South'}
     *               },
     *               {
     *                   region: 'center',
     *                   el: {type: 'button', text: 'Center'}
     *               },
     *               {
     *                   region: 'east',
     *                   width: 30,
     *                  el: {type: 'button',text: 'East'}
     *               },
     *               {
     *                   region: 'west',
     *                   width: 30,
     *                   el: {type: 'button',text: 'West'}
     *               }
     *           ]
     *      });
     *      editor.doLayout();
     *
     * @class FR.BorderLayout
     * @extends FR.Layout
     *
     * @cfg {JSON} options 配置属性
     * @cfg {Array} options.items 布局容器中的内容
     */
    FR.BorderLayout = FR.extend(FR.Layout, {

        _defaultConfig: function () {
            return $.extend(FR.BorderLayout.superclass._defaultConfig.apply(), {
                baseCls: 'fr-quick-border-layout'
            });
        },

        _init: function () {
            FR.BorderLayout.superclass._init.apply(this, arguments);
            var opts = this.options;
            var items = opts.items;
            var regionsAvailable = ["north", "south", "east", "west", "center"];
            this.regionField = {};
            for (var i = 0; i < items.length; i++) {
                var item = items[i];
                var region = item['region'];
                if (regionsAvailable.indexOf(region) != -1) {
                    if (item.el && item.el.type) {
                        if (!item.el.style) {
                            item.el.style = opts.style;
                        }
                        var widget = FR.createWidget($.extend(item.el, {
                            width: item.width,
                            height: item.height,
                            resultWidgets: opts.resultWidgets
                        }));
                        item.el = widget.element;
                    }
                    this.element.append(item.el);
                    this.regionField[region] = item;
                }
            }
            this.element.data('jlayout', jLayout.borderlayout(this.regionField));
        },

        /**
         * 动态改变区域的尺寸
         * @param {"north"/"south"/"east"/"west"} region 区域,可以是东南西北四个位置的任意一个
         * @param {Number} wh 高度或者宽度值
         */
        setRegionWH: function (region, wh) {
            if (!region || isNaN(wh)) {
                return;
            }
            switch (region) {
                case 'north' :
                    this.regionField['north'].height = wh;
                    break;
                case 'south' :
                    this.regionField['south'].height = wh;
                    break;
                case 'east' :
                    this.regionField['east'].width = wh;
                    break;
                case 'west' :
                    this.regionField['west'].width = wh;
                    break;
                default :
            }
            this.element.data('jlayout', jLayout.borderlayout(this.regionField));
        },

        doResize: function (give) {
            FR.BorderLayout.superclass.doResize.call(this, give);
            var opts = this.options;
            this.element.css({
                width: (give ? (give.width || opts.width) : opts.width),
                height: (give ? (give.height || opts.height) : opts.height),
                left: give ? (give.left || opts.left) : opts.left,
                top: give ? (give.top || opts.top) : opts.top
            });
            this.doLayout();
        },

        doLayout: function () {
            FR.BorderLayout.superclass.doLayout.apply(this, arguments);
        }
    });
    $.shortcut('border', FR.BorderLayout);

    /**
     * 居中布局
     *
     *      @example
     *      var $wrapper = $('<div>').css({
     *          width : 300,
     *          height : 200,
     *          top : 5,
     *          left : 5,
     *          position : 'absolute',
     *          background : 'red'
     *      }).appendTo('body');
     *      var layout = FR.createWidget({
     *          renderEl : $wrapper,
     *          type : 'center',
     *          item : {
     *              width : 150,
     *              height : 150,
     *              el : $('<div>').css({background:'green'})
     *          }
     *      });
     *      layout.doLayout();
     *
     * @class FR.CenterLayout
     * @extends FR.Layout
     *
     * @cfg {JSON} options 居中布局的各种属性配置
     * @cfg {JSON} options.item 布局中的元素配置属性
     * @cfg {Number/'auto'} [options.item.width='auto'] 中间部分的宽度
     * @cfg {Number/'auto'} [options.item.height='auto'] 中间部分的高度
     * @cfg {JSON/jQuery} options.item.el 布局中元素对象,可以是一个JSON格式的控件配置属性,也可以是一个jQuery对象
     */
    FR.CenterLayout = FR.extend(FR.Layout, {
        _defaultConfig: function () {
            return $.extend(FR.CenterLayout.superclass._defaultConfig.apply(), {
                baseCls: 'fr-quick-center-layout'
            });
        },
        _init: function () {
            FR.CenterLayout.superclass._init.apply(this, arguments);
            var opts = this.options, item = opts.item;
            if (item && item.el) {
                if (item.el.type) {
                    if (!item.el.style) {
                        item.el.style = opts.style;
                    }
                    var widget = FR.createWidget($.extend(item.el, {
                        width: item.width,
                        height: item.height,
                        resultWidgets: opts.resultWidgets
                    }));
                    item.el = widget.element;
                } else if (!(item.el instanceof $)) {
                    FR.Msg.toast('el must be a widget or a jQuery element!');
                    item.el = $('<div>');
                }
                this.element.append(item.el);
            }
            this.element.data('jlayout', jLayout.center(opts));
        },
        doLayout: function () {
            FR.CenterLayout.superclass.doLayout.apply(this, arguments);
        }

    });
    $.shortcut('center', FR.CenterLayout);

    /**
     * 卡片布局
     * @class FR.CardLayout
     * @extends FR.Layout
     *
     * @cfg {JSON} options 配置属性
     * @cfg {Number} [options.defaultShowIndex=0] 默认加载完显示的tab子组件索引
     * @cfg {Function} [hideAction=null] 子组件隐藏函数,默认会调用jQuery的hide()
     * @cfg {JSON} hideAction.item 隐藏函数的参数,表示即将隐藏的当前项
     */
    FR.CardLayout = FR.extend(FR.Layout, {

        _defaultConfig: function () {
            return $.extend(FR.CardLayout.superclass._defaultConfig.apply(), {
                baseCls: 'fr-quick-card-layout',
                defaultShowIndex: 0,
                hideAction : null,
                showAction : null
            });
        },

        _init: function () {
            FR.CardLayout.superclass._init.apply(this, arguments);
            var opts = this.options;
            this.name2Index = {};
            this.cardsHasCreated = [];
            this._initNameMap();
            this.showCardByIndex(opts.defaultShowIndex);
        },
        /**
         * 初始化控件名索引
         * @private
         */
        _initNameMap: function () {
            var items = this.options.items;
            for (var i = 0; i < items.length; i++) {
                var name;
                if (items[i].el) {
                    name = items[i].el.widgetName;
                } else {
                    name = items[i].widgetName;
                }
                if (!FR.isEmpty(name)) {
                    this.name2Index[name] = i;
                }
            }
        },

        showPaneByIndex: function(index) {
            this.showCardByIndex(index);
        },

        /**
         * 显示指定位置的布局容器
         * @param index 位置索引
         */
        showCardByIndex: function (index) {
            var opts = this.options;
            var items = opts.items;
            this.showIndex = index;
            for (var h = 0; h < this.cardsHasCreated.length; h++) {
                var idx = this.cardsHasCreated[h];
                var it = items[idx];
                this._hideItem(it);
            }
            if (index > -1 && index < items.length) {
                var ii = this.cardsHasCreated.indexOf(index);
                if (ii == -1) {
                    var item = items[index];
                    if (!item.el) {
                        item.el = item;
                    }
                    if (item && item.el && item.el.type) {
                        var widget = FR.createWidget($.extend(item.el, {
                            resultWidgets: opts.resultWidgets
                        }));
                        item.el = widget.element;
                    }
                    item.el.hide();
                    this.element.append(item.el);
                    this.cardsHasCreated.push(index);
                    this.element.data('jlayout', jLayout.card(opts));
                    this._showItem(item);
                } else {
                    it = items[index];
                    this._showItem(it);
                }
            }
            this.doLayout();
        },

        _hideItem : function(item) {
            var opts = this.options;
            if ($.isFunction(opts.hideAction)) {
                opts.hideAction.apply(this, [item]);
            } else {
                item.el.hide();
            }
        },
        _showItem : function(item) {
            item.el.show();
        },

        /**
         * 获取当前所显示布局容器的索引位置
         * @returns {*}
         */
        getShowIndex: function(){
            return this.showIndex? this.showIndex:this.options.defaultShowIndex;
        },

        /**
         * 根据子容器的控件名显示指定位置的布局容器
         * @param name 控件名
         */
        showPaneByName: function(name) {
            return this.showCardByName(name);
        },

        /**
         * 根据子容器的控件名显示指定位置的布局容器
         * @param name 控件名
         */
        showCardByName: function (name) {
            if (FR.isEmpty(name)) {
                return;
            }
            this.showCardByIndex(this.name2Index[name.toUpperCase()]);
        },

        doResize: function (give) {
            FR.CardLayout.superclass.doResize.call(this, give);
            var opts = this.options;
            this.element.css({
                width: (give ? (give.width || opts.width) : opts.width),
                height: (give ? (give.height || opts.height) : opts.height),
                left: give ? (give.left || opts.left) : opts.left,
                top: give ? (give.top || opts.top) : opts.top
            });
            this.doLayout();
        },

        doLayout: function () {
            FR.CardLayout.superclass.doLayout.apply(this, arguments);
        }
    });
    $.shortcut('card', FR.CardLayout);

})(jQuery);