    /**
     * @author Ed Spencer
     * TabBar is used internally by a {@link Ext.tab.Panel TabPanel} and typically should not need to be created manually.
     * The tab bar automatically removes the default title provided by {@link Ext.panel.Header}
     */
    Ext.define('Ext.tab.Bar', {
        extend: 'Ext.panel.Header',
        alias: 'widget.tabbar',
        baseCls: Ext.baseCSSPrefix + 'tab-bar',

        requires: ['Ext.tab.Tab'],

        /**
         * @property {Boolean} isTabBar
         * `true` in this class to identify an object as an instantiated Tab Bar, or subclass thereof.
         */
        isTabBar: true,

        /**
         * @cfg {String} title @hide
         */

        /**
         * @cfg {String} iconCls @hide
         */

        // @private
        defaultType: 'tab',

        /**
         * @cfg {Boolean} plain
         * True to not show the full background on the tabbar
         */
        plain: false,

        childEls: [
            'body', 'strip'
        ],

        // @private
        renderTpl: [
            '<div id="{id}-body" class="{baseCls}-body {bodyCls} {bodyTargetCls}<tpl if="ui"> {baseCls}-body-{ui}<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',
                '{%this.renderContainer(out,values)%}',
            '</div>',
            '<div id="{id}-strip" class="{baseCls}-strip<tpl if="ui"> {baseCls}-strip-{ui}<tpl for="uiCls"> {parent.baseCls}-strip-{parent.ui}-{.}</tpl></tpl>"></div>'
        ],

        /**
         * @cfg {Number} minTabWidth
         * The minimum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#minTabWidth minTabWidth} value.
         * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#minTabWidth minTabWidth} config on the TabPanel.
         */

        /**
         * @cfg {Number} maxTabWidth
         * The maximum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#maxTabWidth maxTabWidth} value.
         * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#maxTabWidth maxTabWidth} config on the TabPanel.
         */

        // @private
        initComponent: function() {
            var me = this;

            if (me.plain) {
                me.setUI(me.ui + '-plain');
            }

            me.addClsWithUI(me.dock);

            me.addEvents(
                /**
                 * @event change
                 * Fired when the currently-active tab has changed
                 * @param {Ext.tab.Bar} tabBar The TabBar
                 * @param {Ext.tab.Tab} tab The new Tab
                 * @param {Ext.Component} card The card that was just shown in the TabPanel
                 */
                'change'
            );

            // Element onClick listener added by Header base class
            me.callParent(arguments);
            Ext.merge(me.layout, me.initialConfig.layout);

            // TabBar must override the Header's align setting.
            me.layout.align = (me.orientation == 'vertical') ? 'left' : 'top';
            me.layout.overflowHandler = new Ext.layout.container.boxOverflow.Scroller(me.layout);

            me.remove(me.titleCmp);
            delete me.titleCmp;

            Ext.apply(me.renderData, {
                bodyCls: me.bodyCls
            });
        },

        getLayout: function() {
            var me = this;
            me.layout.type = (me.dock === 'top' || me.dock === 'bottom') ? 'hbox' : 'vbox';
            return me.callParent(arguments);
        },

        // @private
        onAdd: function(tab) {
            tab.position = this.dock;
            this.callParent(arguments);
        },

        onRemove: function(tab) {
            var me = this;

            if (tab === me.previousTab) {
                me.previousTab = null;
            }
            me.callParent(arguments);
        },

        afterComponentLayout : function(width) {
            var me = this,
                needsScroll = me.needsScroll;

            me.callParent(arguments);
            me.strip.setWidth(width);

            if (needsScroll) {
                me.layout.overflowHandler.scrollToItem(me.activeTab);
            }
            delete me.needsScroll;
        },

        // @private
        onClick: function(e, target) {
            // The target might not be a valid tab el.
            var me = this,
                tabEl = e.getTarget('.' + Ext.tab.Tab.prototype.baseCls),
                tab = tabEl && Ext.getCmp(tabEl.id),
                tabPanel = me.tabPanel,
                isCloseClick = tab && tab.closeEl && (target === tab.closeEl.dom);

            if (isCloseClick) {
                e.preventDefault();
            }
            if (tab && tab.isDisabled && !tab.isDisabled()) {
                if (tab.closable && isCloseClick) {
                    tab.onCloseClick();
                } else {
                    if (tabPanel) {
                        // TabPanel will card setActiveTab of the TabBar
                        tabPanel.setActiveTab(tab.card);
                    } else {
                        me.setActiveTab(tab);
                    }
                    tab.focus();
                }
            }
        },

        /**
         * @private
         * Closes the given tab by removing it from the TabBar and removing the corresponding card from the TabPanel
         * @param {Ext.tab.Tab} toClose The tab to close
         */
        closeTab: function(toClose) {
            var me = this,
                card = toClose.card,
                tabPanel = me.tabPanel,
                toActivate;

            if (card && card.fireEvent('beforeclose', card) === false) {
                return false;
            }

            // If we are closing the active tab, revert to the previously active tab (or the previous or next enabled sibling if
            // there *is* no previously active tab, or the previously active tab is the one that's being closed or the previously
            // active tab has since been disabled)
            toActivate = me.findNextActivatable(toClose);

            // We are going to remove the associated card, and then, if that was sucessful, remove the Tab,
            // And then potentially activate another Tab. We should not layout for each of these operations.
            Ext.suspendLayouts();

            if (tabPanel && card) {
                // Remove the ownerCt so the tab doesn't get destroyed if the remove is successful
                // We need this so we can have the tab fire it's own close event.
                delete toClose.ownerCt;

                // we must fire 'close' before removing the card from panel, otherwise
                // the event will no loger have any listener
                card.fireEvent('close', card);
                tabPanel.remove(card);

                // Remove succeeded
                if (!tabPanel.getComponent(card)) {
                    /*
                     * Force the close event to fire. By the time this function returns,
                     * the tab is already destroyed and all listeners have been purged
                     * so the tab can't fire itself.
                     */
                    toClose.fireClose();
                    me.remove(toClose);
                } else {
                    // Restore the ownerCt from above
                    toClose.ownerCt = me;
                    Ext.resumeLayouts(true);
                    return false;
                }
            }

            // If we are closing the active tab, revert to the previously active tab (or the previous sibling or the nnext sibling)
            if (toActivate) {
                // Our owning TabPanel calls our setActiveTab method, so only call that if this Bar is being used
                // in some other context (unlikely)
                if (tabPanel) {
                    tabPanel.setActiveTab(toActivate.card);
                } else {
                    me.setActiveTab(toActivate);
                }
                toActivate.focus();
            }
            Ext.resumeLayouts(true);
        },

        // private - used by TabPanel too.
        // Works out the next tab to activate when one tab is closed.
        findNextActivatable: function(toClose) {
            var me = this;
            if (toClose.active && me.items.getCount() > 1) {
                return (me.previousTab && me.previousTab !== toClose && !me.previousTab.disabled) ? me.previousTab : (toClose.next('tab[disabled=false]') || toClose.prev('tab[disabled=false]'));
            }
        },

        /**
         * @private
         * Marks the given tab as active
         * @param {Ext.tab.Tab} tab The tab to mark active
         */
        setActiveTab: function(tab) {
            var me = this;

            if (!tab.disabled && tab !== me.activeTab) {
                if (me.activeTab) {
                    if (me.activeTab.isDestroyed) {
                        me.previousTab = null;
                    } else {
                        me.previousTab = me.activeTab;
                        me.activeTab.deactivate();
                    }
                }
                tab.activate();

                me.activeTab = tab;
                me.fireEvent('change', me, tab, tab.card);

                // Ensure that after the currently in progress layout, the active tab is scrolled into view
                me.needsScroll = true;
                me.updateLayout();
            }
        }
    });