/**
 * This class is a grid {@link Ext.plugin.Abstract plugin} that adds a filter bar
 * below the grid column headers.
 *
 * # Example Usage
 *
 *     @example
 *     var shows = Ext.create('Ext.data.Store', {
 *         fields: ['id','show'],
 *         data: [
 *             {id: 0, show: 'Battlestar Galactica'},
 *             {id: 1, show: 'Doctor Who'},
 *             {id: 2, show: 'Farscape'},
 *             {id: 3, show: 'Firefly'},
 *             {id: 4, show: 'Star Trek'},
 *             {id: 5, show: 'Star Wars: Christmas Special'}
 *         ]
 *     });
 *
 *     Ext.create('Ext.grid.Panel', {
 *         renderTo: Ext.getBody(),
 *         title: 'Sci-Fi Television',
 *         height: 250,
 *         width: 250,
 *         store: shows,
 *         plugins: {
 *             gridfilterbar: true
 *         },
 *         columns: [{
 *             dataIndex: 'id',
 *             text: 'ID',
 *             width: 50
 *         },{
 *             dataIndex: 'show',
 *             text: 'Show',
 *             flex: 1,
 *             filterType: 'string'
 *         }]
 *     });
 *
 *     Ext.create('Ext.grid.Panel', {
 *         renderTo: Ext.getBody(),
 *         title: 'Sci-Fi Television',
 *         height: 250,
 *         width: 250,
 *         store: shows,
 *         plugins: {
 *             gridfilterbar: true
 *         },
 *         columns: [{
 *             dataIndex: 'id',
 *             text: 'ID',
 *             width: 50
 *         },{
 *             dataIndex: 'show',
 *             text: 'Show',
 *             flex: 1,
 *             filterType: {
 *                 // required configs
 *                 type: 'string',
 *                 // optional configs
 *                 value: 'star',  // setting a value makes the filter active.
 *                 fieldDefaults: {
 *                     // any Ext.form.field.Text configs accepted
 *                 }
 *             }
 *         }]
 *     });
 *
 * # Features
 *
 * ## Filtering implementations
 *
 * Currently provided filter types are:
 *
 *   * `{@link Ext.grid.plugin.filterbar.filters.Boolean boolean}`
 *   * `{@link Ext.grid.plugin.filterbar.filters.Date date}`
 *   * `{@link Ext.grid.plugin.filterbar.filters.List list}`
 *   * `{@link Ext.grid.plugin.filterbar.filters.Number number}`
 *   * `{@link Ext.grid.plugin.filterbar.filters.String string}`
 *
 *
 * ## Grid functions
 *
 * The following functions are added to the grid:
 * - showFilterBar - will make the filter bar visible
 * - hideFilterBar - will hide the filter bar
 *
 *
 */
Ext.define('Ext.grid.plugin.filterbar.FilterBar', {
    extend: 'Ext.grid.plugin.BaseFilterBar',
    alias: 'plugin.gridfilterbar',
 
    requires: [
        'Ext.grid.plugin.filterbar.filters.String',
        'Ext.grid.plugin.filterbar.filters.Date',
        'Ext.grid.plugin.filterbar.filters.Number',
        'Ext.grid.plugin.filterbar.filters.Boolean',
        'Ext.grid.plugin.filterbar.filters.None',
        'Ext.grid.plugin.filterbar.filters.List',
        'Ext.grid.plugin.filterbar.filters.InList'
    ],
 
    headerListeners: {
        columnshow: 'onColumnShow',
        columnhide: 'onColumnHide',
        add: 'onColumnAdd',
        remove: 'onColumnRemove',
        afterlayout: 'onHeaderLayout'
    },
 
    gridListeners: {
        storeChange: 'onGridStoreChanged'
    },
 
    /**
     *  `"both"` (the default) - The plugin is added to both grids
     *  `"top"` - The plugin is added to the containing Panel
     *  `"locked"` - The plugin is added to the locked (left) grid
     *  `"normal"` - The plugin is added to the normal (right) grid
     *
     * @private
     */
    lockableScope: 'both',
 
    createFilterBar: function() {
        var me = this,
            bar;
 
        bar = me.getGrid().addDocked({
            weight: 100,
            xtype: 'container',
            hidden: me.getHidden(),
            layout: {
                type: 'hbox',
                align: 'stretch'
            },
            childEls: ['innerCt'],
            scrollable: {
                x: false,
                y: false
            },
            listeners: {
                afterrender: 'onBarRender',
                scope: me
            }
        })[0];
 
        bar.addCls([me.filterBarCls, Ext.baseCSSPrefix + 'grid-header-ct']);
 
        me.setBar(bar);
    },
 
    updateGrid: function(grid, oldGrid) {
        var me = this,
            listeners = me.getHeaderListeners();
 
        me.callParent([grid, oldGrid]);
 
        me.listenersHeader = Ext.destroy(me.listenersHeader);
 
        if (grid && listeners) {
            me.listenersHeader = grid.headerCt.on(Ext.apply(listeners, {
                scope: me,
                destroyable: true
            }));
        }
    },
 
    setupGridFunctions: function() {
        var me = this,
            grid = me.getGrid(),
            mainGrid;
 
        if (grid) {
            if (grid.isLocked) {
                mainGrid = grid.ownerGrid;
                mainGrid.showFilterBar = Ext.bind(me.showFilterBarPartners, me);
                mainGrid.hideFilterBar = Ext.bind(me.hideFilterBarPartners, me);
            }
 
            grid.showFilterBar = Ext.bind(me.showFilterBar, me);
            grid.hideFilterBar = Ext.bind(me.hideFilterBar, me);
        }
    },
 
    showFilterBar: function() {
        var me = this;
 
        if (me.isDestroyed) {
            return;
        }
 
        me.callParent();
        me.getBar().getScrollable().syncWithPartners();
    },
 
    showFilterBarPartners: function() {
        this.showFilterBar();
        this.lockingPartner.showFilterBar();
    },
 
    hideFilterBarPartners: function() {
        this.hideFilterBar();
        this.lockingPartner.hideFilterBar();
    },
 
    onBarRender: function(bar) {
        var grid = this.getGrid();
 
        grid.getView().getScrollable().addPartner(bar.getScrollable(), 'x');
        this.initializeFilters(grid.columnManager.getColumns());
    },
 
    onHeaderLayout: function() {
        this.resizeFilters();
        this.adjustFilterBarSize();
    },
 
    onGridStoreChanged: function(grid, store) {
        this.setStore(store);
        this.resetFilters();
    },
 
    onColumnAdd: function() {
        var me = this,
            // get all the columns excepts group header
            columns = me.getGridColumns(),
            i, column, filter;
 
        // reposition all the filter bar items
        // otherwise, nested column filters will not be positioned
        for (= 0; i < columns.length; i++) {
            column = columns[i];
 
            filter = column.getFilterType();
 
            if (!filter || !filter.isGridFilter) {
                filter = me.createColumnFilter(column);
            }
 
            me.getBar().insert(i, filter.getField());
        }
 
        me.adjustFilterBarSize();
    },
 
    onColumnRemove: function() {
        this.adjustFilterBarSize();
    },
 
    onColumnShow: function(header, column) {
        this.setFilterVisibility(column, true);
    },
 
    onColumnHide: function(header, column) {
        this.setFilterVisibility(column, false);
    },
 
    setFilterVisibility: function(column, visible) {
        // Update the column filter component visibility for the nested columns
        if (column.isGroupHeader) {
            column.items.each(function(subColumn) {
                this.setFilterVisibility(subColumn, visible);
            }, this);
        }
 
        this.callParent(arguments);
    },
 
    adjustFilterBarSize: function() {
        var bar = this.getBar(),
            headerCt = this.getGrid().headerCt,
            innerCt = headerCt.layout.innerCt;
 
        if (bar.rendered && innerCt) {
            // Synchronize the width of the bars' inner container with that of the column headers'.
            bar.innerCt.setWidth(innerCt.getWidth());
        }
    },
 
    createColumnFilter: function(column) {
        if (column.filter) {
            column.setFilterType(column.filter);
            delete column.filter;
        }
 
        return this.callParent([column]);
    },
 
    getGridColumns: function() {
        return this.getGrid().columnManager.getColumns();
    }
});