/**
 * This plugin allows users to change summaries on grid columns using:
 *
 * - a context menu on the summary row cell
 * - a header menu entry
 *
 * On each column of the grid you can define what summary functions are available
 * to the user by configuring {@link Ext.grid.column.Column#summaries}. They will
 * be displayed in the context menu on the summary cell.
 *
 * This plugin adds a docked summary row to the grid.
 *
 * **Note** To be used with a {@link Ext.grid.TreeGrouped}
 */
Ext.define('Ext.grid.plugin.Summaries', {
    extend: 'Ext.grid.plugin.BaseSummaries',
 
    alias: [
        'plugin.summaries',
        'plugin.gridsummaries'
    ],
 
    requires: [
        'Ext.grid.row.Summary'
    ],
 
    mixins: [
        'Ext.mixin.Bufferable',
        'Ext.mixin.StoreWatcher'
    ],
 
    config: {
        row: {
            lazy: true,
            $value: {
                xtype: 'groupedgridsummaryrow',
                docked: 'bottom',
                scrollable: {
                    x: false,
                    y: false
                }
            }
        },
        /**
         * @cfg {Boolean} [enableContextMenu=true]
         * True to enable the summary grid cell context menu.
         */
        enableContextMenu: true,
        /**
         * @cfg {Boolean} [enableSummaryMenu=true]
         * True to enable the summary menu items in the header menu.
         */
        enableSummaryMenu: true,
 
        headerListeners: {
            synreservespace: 'syncReserveSpace'
        },
 
        gridListeners: {
            childlongpress: 'onSummaryGridCellContextMenu',
            childcontextmenu: 'onSummaryGridCellContextMenu',
            columnadd: 'onGridColumnAdd',
            beforeshowcolumnmenu: 'onBeforeShowColumnMenu',
            summaryPositionChange: 'onSummaryPositionChanged'
        },
        summaryRowListeners: {
            longpress: 'onSummaryCellContextMenu',
            contextmenu: 'onSummaryCellContextMenu'
        },
 
        /**
         * @private
         */
        summaryPosition: null
    },
 
    inheritUi: true,
 
    storeListeners: {
        add: 'syncSummary',
        clear: 'syncSummary',
        remove: 'syncSummary',
        datachanged: 'syncSummary',
        update: 'syncSummary',
        summarieschanged: 'onSummariesChanged'
    },
 
    bufferableMethods: {
        // buffer updates to reduce re-summarization passes over the entire store.
        syncSummary: 5
    },
 
    summaryRowSelector: '.' + Ext.baseCSSPrefix + 'summaryrow',
    summaryGroupSelector: '.' + Ext.baseCSSPrefix + 'grid-group',
 
    destroy: function() {
        var me = this;
 
        me.setOwner(null);
        me.setRow(null);
        me.lastSummaryMenuItem = Ext.destroy(me.lastSummaryMenuItem);
 
        me.callParent();
    },
 
    createRow: function(config) {
        return Ext.apply({
            viewModel: this.getGrid().getItemConfig().viewModel
        }, config);
    },
 
    applyRow: function(row) {
        if (row) {
            row = this.createRow(row);
            row = this.cmp.add(row);
        }
 
        return row;
    },
 
    updateRow: function(row, oldRow) {
        Ext.destroy(oldRow);
 
        if (row && row.element) {
            row.element.on(
                Ext.apply({
                    scope: this
                }, this.getSummaryRowListeners())
            );
        }
    },
 
    updateStore: function(store, oldStore) {
        var source = store && store.isMultigroupStore ? store.getSource() : store;
 
        this.mixins.storewatcher.updateStore.call(this, source, oldStore);
 
        if (source && source.isLoaded()) {
            // if the store is already loaded then we update summaries
            this.syncSummary();
        }
    },
 
    updateGrid: function(grid, oldGrid) {
        var me = this,
            listeners = me.getHeaderListeners(),
            row = me.getRow(),
            scrollable;
 
        me.listenersHeader = Ext.destroy(me.listenersHeader);
 
        if (row && oldGrid) {
            scrollable = oldGrid.getScrollable();
 
            if (scrollable) {
                scrollable.removePartner(row.getScrollable());
            }
        }
 
        if (grid) {
            scrollable = grid.getScrollable();
 
            if (row && scrollable) {
                scrollable.addPartner(row.getScrollable(), 'x');
            }
 
            me.setOwner(grid);
 
            me.setSummaryPosition(grid.getSummaryPosition());
 
            grid.addCls(Ext.baseCSSPrefix + 'grid-has-summaryrow');
 
            if (listeners) {
                me.listenersHeader = grid.getHeaderContainer().on(Ext.apply(listeners, {
                    scope: me,
                    destroyable: true
                }));
            }
 
            me.parseSummariesFromColumns(grid, grid.getColumns());
        }
 
        me.callParent([grid, oldGrid]);
    },
 
    updateSummaryPosition: function(position) {
        var row = this.getRow();
 
        row.setHidden(position !== 'docked');
    },
 
    onSummaryPositionChanged: function(grid, position) {
        this.setSummaryPosition(position);
    },
 
    onGridColumnAdd: function(grid, column) {
        this.parseSummariesFromColumns(grid, [column]);
    },
 
    parseSummariesFromColumns: function(grid, columns) {
        var len = columns.length,
            store = grid.getStore(),
            changed = false,
            values = {},
            i, column, summary;
 
        if (!store || store.isDestroyed) {
            return;
        }
 
        if (store.isMultigroupStore) {
            store = store.getSource();
        }
 
        for (= 0; i < len; i++) {
            column = columns[i];
            summary = column.getSummary();
 
            if (summary) {
                values[column.getDataIndex()] = summary;
                column.setSummary(null);
                changed = true;
            }
        }
 
        if (changed) {
            store.setFieldsSummaries(values);
        }
    },
 
    onSummariesChanged: function(store) {
        var grid = this.getGrid(),
            dataItems = grid ? grid.innerItems : [],
            len = dataItems.length,
            i, row;
 
        for (= 0; i < len; i++) {
            row = dataItems[i];
 
            if (row.isSummaryRows) {
                row.syncSummary();
            }
        }
    },
 
    onSummaryGridCellContextMenu: function(grid, location) {
        this.showMenu(this.getParams(location.event));
    },
 
    onSummaryCellContextMenu: function(event, cell) {
        this.showMenu(this.getParams(event));
    },
 
    getDataIndex: function(column) {
        return column.getDataIndex();
    },
 
    canShowMenu: function(params) {
        var row = params.row;
 
        return row && (row.isGroupRow || row.isSummaryRows || row.isSummaryRow) &&
            this.callParent([params]);
    },
 
    getParams: function(event) {
        var rowEl = event.getTarget(this.summaryRowSelector) ||
            event.getTarget(this.summaryGroupSelector),
            summaryRow = Ext.fly(rowEl),
            cell = Ext.fly(event.getTarget('.' + Ext.baseCSSPrefix + 'gridcell')),
            params = {
                e: event,
                row: summaryRow && summaryRow.component
            };
 
        if (summaryRow && cell && cell.component) {
            cell = cell.component;
            params.cell = cell;
            params.column = cell.getColumn();
        }
 
        return params;
    },
 
    createMenu: function(menu) {
        menu.xtype = 'menu';
 
        return Ext.create(menu);
    },
 
    onBeforeShowColumnMenu: function(grid, column, menu) {
        var menuItem = menu.down('#summaryMenuItem');
 
        if (!menuItem) {
            menuItem = menu.add({
                text: this.summaryText,
                itemId: 'summaryMenuItem',
                iconCls: Ext.baseCSSPrefix + 'summaries-icon'
            });
        }
 
        menuItem.setHidden(column.isGroupsColumn);
        menuItem.setMenu(this.getSummaryMenu(column));
        // let's save a reference to the menu item
        // so we can remove it when the plugin is destroyed
        this.lastSummaryMenuItem = menuItem;
    },
 
    syncReserveSpace: function(header, value) {
        var row = this.getRow();
 
        if (row) {
            row.cellsElement.setStyle('padding-right', value);
        }
    },
 
    privates: {
        doSyncSummary: function() {
            var row = this.getRow();
 
            if (row) {
                row.syncSummary();
            }
        }
    }
 
});