/**
 * This plugin enables user-defined filters for a grid.
 * @since 6.7.0
 *
 * In general an gridfilters plugin will be passed to the grid:
 *
 *     @example
 *     var store = Ext.create('Ext.data.Store', {
 *         fields: ['firstname', 'lastname', 'seniority', 'department', 'hired', 'active'],
 *         data: [
 *             {
 *                  firstname:"Michael",
 *                  lastname:"Scott",
 *                  seniority:7,
 *                  department:"Management",
 *                  hired:"01/10/2004",
 *                  active: true
 *             },
 *             {
 *                  firstname:"Dwight",
 *                  lastname:"Schrute",
 *                  seniority:2,
 *                  department:"Sales",
 *                  hired:"04/01/2004",
 *                  active: true
 *             },
 *             {
 *                  firstname:"Jim",
 *                  lastname:"Halpert",
 *                  seniority:3,
 *                  department:"Sales",
 *                  hired:"02/22/2006",
 *                  active: false
 *             },
 *             {
 *                  firstname:"Kevin",
 *                  lastname:"Malone",
 *                  seniority:4,
 *                  department:"Accounting",
 *                  hired:"06/10/2007",
 *                  active: true
 *             },
 *             {
 *                  firstname:"Angela",
 *                  lastname:"Martin",
 *                  seniority:5,
 *                  department:"Accounting",
 *                  hired:"10/21/2008",
 *                  active: false
 *             }
 *         ]
 *     });
 *
 *     Ext.create({
 *         xtype: 'grid',
 *         title: 'Filter Grid Demo',
 *         itemConfig: {
 *             viewModel: true
 *         },
 *         plugins: {
 *              gridfilters: true
 *         },
 *         store: store,
 *         columns: [
 *             {text: 'First Name',  dataIndex:'firstname'},
 *             {text: 'Last Name',  dataIndex:'lastname'},
 *             {text: 'Hired Month',  dataIndex:'hired'},
 *             {
 *                 text: 'Department',
 *                 width: 200,
 *                 cell: {
 *                    bind: '{record.department} ({record.seniority})'
 *                 }
 *             }
 *         ],
 *         width: 500,
 *         fullscreen: true
 *     });
 *
 * # Convenience Subclasses
 *
 * There are several menu subclasses that provide default rendering for various data types
 *
 *  - {@link Ext.grid.filters.menu.Boolean}: Renders for boolean input fields
 *  - {@link Ext.grid.filters.menu.Date}: Renders for date input fields
 *  - {@link Ext.grid.filters.menu.Number}: Renders for numeric input fields
 *  - {@link Ext.grid.filters.menu.String}: Renders for string input fields
 *  
 *  These subclasses can be configured in columns as such:
 *
 *
 *      columns: [
 *          {text: 'First Name',  dataIndex:'firstname'},
 *          {text: 'Last Name',  dataIndex:'lastname', filter: 'string'},
 *          {text: 'seniority', dataIndex: 'seniority', filter: 'number'},
 *          {text: 'Hired Month',  dataIndex:'hired', filter: 'date'},
 *          {text: 'Active',  dataIndex:'active', filter: 'boolean'}
 *      ]
 *
 *
 *  Menu items can also be customised as shown below:
 *
 *
 *      columns: [
 *          {
 *              text: 'First Name',
 *              dataIndex:'firstname'
 *          },
 *          {
 *              text: 'Last Name',
 *              filter: {
 *                  type: 'string',
 *                  menu: {
 *                      items: {
 *                          like: {
 *                              placeholder: 'Custom Like...'
 *                          }
 *                      }
 *                  }
 *              }
 *         },
 *         {
 *            text: 'Hired Month',
 *            filter: {
 *              type: 'date',
 *              menu: {
 *                  items: {
 *                      lt: {
 *                          label: 'Custom Less than',
 *                          placeholder: 'Custom Less than...',
 *                          dateFormat: 'd-m-y'
 *                      },
 *                      gt: {
 *                          label: 'Custom Greater than',
 *                          placeholder: 'Custom Greater than...',
 *                          dateFormat: 'd-m-y'
 *                      },
 *                      eq: {
 *                          label: 'Custom On',
 *                          placeholder: 'Custom On...',
 *                          dateFormat: 'd-m-y'
 *                      }
 *                  }
 *              }
 *            }
 *         },
 *         {
 *              text: 'seniority'
 *              filter: {
 *                  type: 'number',
 *                  menu: {
 *                      items: {
 *                          lt: {
 *                              label: 'Custom Less than',
 *                              placeholder: 'Custom Less than...',
 *                          },
 *                          gt: {
 *                              label: 'Custom Greater than',
 *                              placeholder: 'Custom Greater than...',
 *                          },
 *                          eq: {
 *                              label: 'Custom Equal to',
 *                              placeholder: 'Custom Equal to...',
 *                          }
 *                      }
 *                  }
 *              }
 *          },
 *          {
 *              text: 'Active',
 *              filter: {
 *                  type: 'boolean',
 *                  menu: {
 *                      items: {
 *                          yes: {
 *                              text: 'Custom True'
 *                          },
 *                          no: {
 *                              text: 'Custom False'
 *                          }
 *                      }
 *                  }
 *              }             
 *          }
 *      ]
 *
 */
Ext.define('Ext.grid.filters.Plugin', {
    extend: 'Ext.plugin.Abstract',
    alias: 'plugin.gridfilters',
 
    requires: [
        'Ext.grid.filters.menu.*',
        'Ext.grid.filters.Column',  // an override that extends Column w/filter config
        'Ext.data.Query',
        'Ext.util.Filter'
    ],
 
    mixins: [
        'Ext.state.Stateful',
        'Ext.mixin.StoreWatcher'
    ],
 
    config: {
        /**
         * @cfg {String/Object} activeFilter
         * This config holds the current filter. This config is stateful.
         * @private
         */
        activeFilter: null,
 
        query: {
            type: 'default',
            format: 'filters'
        }
    },
 
    stateful: [
        'activeFilter'
    ],
 
    init: function(grid) {
        this.setOwner(grid);
 
        grid.on({
            beforeshowcolumnmenu: 'onBeforeShowColumnMenu',
            scope: this
        });
    },
 
    destroy: function() {
        this.setOwner(null);
 
        this.callParent();
    },
 
    // activeFilter
 
    updateActiveFilter: function(filter) {
        var query = this.getQuery();
 
        if (Ext.isString(filter)) {
            query.setSource(filter);
        }
        else {
            query.setFilters(filter);
        }
    },
 
    // query
 
    applyQuery: function(config, query) {
        return Ext.Factory.query.update(query, config);
    },
 
    updateQuery: function(query) {
        if (query) {
            // eslint-disable-next-line vars-on-top
            var me = this,
                fn = query.compile;
 
            query.compile = function() {
                fn.call(query);
                me.queryModified(query);
            };
        }
    },
 
    // store (StoreWatcher)
 
    updateStore: function(store, oldStore) {
        var me = this,
            query = me.getQuery();
 
        me.mixins.storewatcher.updateStore.call(me, store, oldStore);
 
        if (oldStore && !(oldStore.destroying || oldStore.destroyed)) {
            oldStore.getFilters().remove(query);
        }
 
        if (store) {
            store.getFilters().add(query);
        }
    },
 
    //--------------------------------------------
 
    onSetFilter: function(menuItem) {
        this.setActiveFilter(menuItem.rec.data.query);
    },
 
    privates: {
        onBeforeShowColumnMenu: function(grid, column, menu) {
            var me = this,
                filterMenuItem = menu.getComponent('filter'),
                menuConfig;
 
            if (!filterMenuItem) {
                // This method is provided by our Column override:
                menuConfig = column.createFilter({
                    itemId: 'filter',
                    plugin: me,
                    column: column
                });
 
                filterMenuItem = menuConfig && menu.add(Ext.Factory.gridFilters(menuConfig));
 
                if (filterMenuItem) {
                    filterMenuItem.setCheckHandler(me.onFilterItemCheckChange.bind(me));
                }
            }
 
            if (filterMenuItem) {
                filterMenuItem.syncFilter();
            }
        },
 
        onFilterItemCheckChange: function(item) {
            item.syncQuery();
        },
 
        queryModified: function() {
            var filters = this.cmp.getStore();
 
            filters = filters && filters.getFilters();
 
            if (filters) {
                filters.beginUpdate();
                ++filters.generation;
                filters.endUpdate();
            }
        }
    }
});