/**
 * This feature can display summaries for all nested groups and a grand summary
 * for the entire store assigned to the grid panel.
 */
Ext.define('Ext.grid.feature.AdvancedGroupingSummary', {
    extend: 'Ext.grid.feature.AdvancedGrouping',
    alias: 'feature.advancedgroupingsummary',
 
    groupSummaryPosition: 'bottom',
    /**
     * @cfg summaryPosition
     * @inheritdoc
     * @localdoc
     *  * `'docked'`: Show the summary row docked at the top/bottom
     *  of the grid. Used together with the {@link dock} config
     */
    summaryPosition: 'docked',
 
    /**
     * @cfg {String} dock
     * Configure `'top'` or `'bottom'` to create a fixed summary row
     * either above or below the scrollable table.
     *
     */
    dock: 'bottom',
 
    dockedSummaryCls: Ext.baseCSSPrefix + 'docked-grid-summary',
    summaryCls: Ext.baseCSSPrefix + 'grid-summary',
    summarySelector: '.' + Ext.baseCSSPrefix + 'grid-summary',
    summaryTableCls: Ext.baseCSSPrefix + 'grid-item',
 
    init: function(grid) {
        var me = this;
 
        me.refreshBarTask = new Ext.util.DelayedTask(me.onStoreUpdate, me);
 
        me.callParent([grid]);
 
        grid.headerCt.on({
            columnschanged: me.refreshBar, // this includes columns visibility
            afterlayout: me.afterHeaderCtLayout,
            scope: me
        });
        grid.on({
            beforerender: me.onBeforeGridRendered,
            afterrender: me.onAfterGridRendered,
            scope: me,
            single: true
        });
    },
 
    destroy: function() {
        var me = this;
 
        me.refreshBarTask.cancel();
        me.summaryBar = Ext.destroy(me.summaryBar);
 
        me.callParent();
    },
 
    /**
     * @inheritDoc
     */
    setSummaryPosition: function(value) {
        var me = this,
            lockingPartner = me.lockingPartner,
            bar = me.getSummaryBar(),
            dock = me.dock;
 
        me.showSummary = (value === 'docked' && (dock === 'top' || dock === 'bottom'));
        bar.setHidden(!me.showSummary);
 
        if (lockingPartner) {
            lockingPartner.getSummaryBar().setHidden(!me.showSummary);
        }
 
        me.callParent([value]);
    },
 
    onBeforeGridRendered: function() {
        var me = this,
            view = me.view,
            grid = me.grid,
            dock = me.dock,
            pos = me.summaryPosition,
            tableCls = [me.summaryTableCls],
            showSummary;
 
        me.showSummary = showSummary = (pos === 'docked' && (dock === 'top' || dock === 'bottom'));
 
        if (view.columnLines) {
            tableCls[tableCls.length] = view.ownerCt.colLinesCls;
        }
 
        me.summaryBar = grid.addDocked({
            focusable: true,
            childEls: ['innerCt', 'item'],
            renderTpl: [
                '<div id="{id}-innerCt" data-ref="innerCt" role="presentation">',
                // eslint-disable-next-line max-len
                '<table id="{id}-item" data-ref="item" cellPadding="0" cellSpacing="0" class="' + tableCls.join(' ') + '">',
                '<tr class="' + me.summaryCls + '"></tr>',
                '</table>',
                '</div>'
            ],
            scrollable: {
                x: false,
                y: false
            },
            itemId: 'summaryBar',
            hidden: !showSummary,
            cls: [me.dockedSummaryCls, me.dockedSummaryCls + '-' + dock],
            xtype: 'component',
            dock: dock,
            weight: 10000000
        })[0];
 
    },
 
    onAfterGridRendered: function() {
        var me = this,
            bar = me.summaryBar;
 
        me.view.getScrollable().addPartner(bar.getScrollable(), 'x');
        me.onStoreUpdate();
 
        bar.innerCt.on({
            click: 'onBarEvent',
            dblclick: 'onBarEvent',
            contextmenu: 'onBarEvent',
            delegate: '.' + Ext.baseCSSPrefix + 'grid-cell',
            scope: me
        });
    },
 
    getSummaryBar: function() {
        var me = this;
 
        if (!me.summaryBar) {
            me.onBeforeGridRendered();
            me.onAfterGridRendered();
        }
 
        return me.summaryBar;
    },
 
    setupRowValues: function(rowValues, renderData) {
        this.callParent([rowValues, renderData]);
 
        if (renderData.isSummary && this.showSummary) {
            Ext.Array.remove(rowValues.rowClasses, this.eventCls);
            rowValues.rowClasses.push('x-grid-row', this.summaryCls);
        }
    },
 
    onStoreUpdate: function() {
        var me = this,
            view = me.view,
            selector = me.summarySelector,
            record, newRowDom, oldRowDom, p, data;
 
        if (!view || !view.rendered || !me.showSummary) {
            return;
        }
 
        record = view.getStore().getSummaryRecord();
        data = me.dataSource.renderData[record.getId()] = {
            isSummary: true
        };
 
        me.setRenderers(data);
        newRowDom = Ext.fly(view.createRowElement(record, -1)).down(selector, true);
        me.resetRenderers();
 
        if (!newRowDom) {
            return;
        }
 
        // Summary row is inside the docked summaryBar Component
        p = me.summaryBar.item.dom.firstChild;
        oldRowDom = p.firstChild;
 
        p.insertBefore(newRowDom, oldRowDom);
        p.removeChild(oldRowDom);
    },
 
    refreshBar: function() {
        this.refreshBarTask.delay(10);
    },
 
    // Synchronize column widths in the docked summary Component or the inline summary row
    // depending on whether we are docked or not.
    afterHeaderCtLayout: function(headerCt) {
        var me = this,
            view = me.view,
            columns = view.getVisibleColumnManager().getColumns(),
            len = columns.length,
            summaryEl, el, width, innerCt, column, i;
 
        if (me.showSummary && view.refreshCounter) {
            summaryEl = me.summaryBar.el;
            width = headerCt.getTableWidth();
            innerCt = me.summaryBar.innerCt;
 
            // Stretch the innerCt of the summary bar upon headerCt layout
            me.summaryBar.item.setWidth(width);
 
            // headerCt's tooNarrow flag is set by its layout if the columns overflow.
            // Must not measure+set in after layout phase, this is a write phase.
            if (headerCt.tooNarrow) {
                width += Ext.getScrollbarSize().width;
            }
 
            innerCt.setWidth(width);
 
            // If the layout was in response to a clearView, there'll be no summary element
            if (summaryEl) {
                for (= 0; i < len; i++) {
                    column = columns[i];
                    el = summaryEl.down(view.getCellSelector(column), true);
 
                    if (el) {
                        Ext.fly(el).setWidth(column.width ||
                            (column.lastBox ? column.lastBox.width : 100));
                    }
                }
            }
        }
    },
 
    onBarEvent: function(e, cell) {
        var me = this,
            view = me.view,
            grid = view.ownerGrid,
            record = view.getStore().getSummaryRecord(),
            fireArg = Ext.apply({
                record: record,
                column: view.getHeaderByCell(cell),
                cell: cell,
                row: me.summaryBar.getEl(),
                grid: grid,
                feature: me,
                e: e
            }, me.dataSource.getRenderData(record));
 
        return grid.fireEvent('summary' + e.type, grid, fireArg);
    },
 
    privates: {
        getOwnerGridListeners: function() {
            var listeners = this.callParent();
 
            return Ext.apply(listeners, {
                columnmove: this.onStoreUpdate
            });
        },
 
        getStoreListeners: function() {
            var me = this,
                listeners = me.callParent();
 
            return Ext.apply(listeners, {
                update: me.refreshBar,
                datachanged: me.refreshBar,
                remotesummarieschanged: me.refreshBar,
                summarieschanged: me.refreshBar
            });
        }
    }
 
});