/**
 * A special type of Grid {@link Ext.grid.column.Column} that provides automatic
 * row numbering.
 *
 * Usage:
 *
 *     columns: [
 *         {xtype: 'rownumberer'},
 *         {text: "Company", flex: 1, sortable: true, dataIndex: 'company'},
 *         {text: "Price", width: 120, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'},
 *         {text: "Change", width: 120, sortable: true, dataIndex: 'change'},
 *         {text: "% Change", width: 120, sortable: true, dataIndex: 'pctChange'},
 *         {text: "Last Updated", width: 120, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
 *     ]
 *
 */
Ext.define('Ext.grid.column.RowNumberer', {
    extend: 'Ext.grid.column.Column',
    alternateClassName: 'Ext.grid.RowNumberer',
    alias: 'widget.rownumberer',
 
    /**
     * @property {Boolean} isRowNumberer 
     * `true` in this class to identify an object as an instantiated RowNumberer, or subclass thereof.
     */
    isRowNumberer: true,
 
    /**
     * @cfg {String} text 
     * Any valid text or HTML fragment to display in the header cell for the row number column.
     */
    text: " ",
 
    /**
     * @cfg {Number} width 
     * The default width in pixels of the row number column.
     */
    width: 30,
 
    /**
     * @cfg {Boolean} sortable 
     * @hide
     */
    sortable: false,
 
    /**
     * @cfg {Boolean} [draggable=false]
     * False to disable drag-drop reordering of this column.
     */
    draggable: false,
 
    // Flag to Lockable to move instances of this column to the locked side. 
    autoLock: true,
 
    // May not be moved from its preferred locked side when grid is enableLocking:true 
    lockable: false,
 
    align: 'right',
 
    /**
     * @cfg {Boolean} producesHTML 
     * @inheritdoc
     */
    producesHTML: false,
 
    ignoreExport: true,
 
    constructor: function (config) {
        var me = this;
 
        // Copy the prototype's default width setting into an instance property to provide 
        // a default width which will not be overridden by Container.applyDefaults use of Ext.applyIf 
        me.width = me.width;
 
        me.callParent(arguments);
 
        // Override any setting from the HeaderContainer's defaults 
        me.sortable = false;
 
        me.scope = me;
    },
 
    resizable: false,
    hideable: false,
    menuDisabled: true,
    dataIndex: '',
    cls: Ext.baseCSSPrefix + 'row-numberer',
    tdCls: Ext.baseCSSPrefix + 'grid-cell-row-numberer ' + Ext.baseCSSPrefix + 'grid-cell-special',
    innerCls: Ext.baseCSSPrefix + 'grid-cell-inner-row-numberer',
    rowspan: undefined,
 
    onAdded: function() {
        var me = this;
        
        // Coalesce multiple item mutation events by routing them to a buffered function 
        me.renumberRows = Ext.Function.createBuffered(me.renumberRows, 1, me);
 
        me.callParent(arguments);
 
        me.storeListener = me.getView().on({
            itemadd: me.renumberRows,
            itemremove: me.renumberRows,
            destroyable: true
        });
    },
 
    onRemoved: function() {
        var me = this;
 
        me.callParent(arguments);
        
        if (me.storeListener) {
            me.storeListener = me.storeListener.destroy();
        }
        
        if (me.renumberRows.timer) {
            clearTimeout(me.renumberRows.timer);
        }
        
        me.renumberRows = null;
        delete me.renumberRows;
    },
 
    defaultRenderer: function(value, metaData, record, rowIdx, colIdx, dataSource, view) {
        var me = this,
            rowspan = me.rowspan,
            page = dataSource.currentPage,
            result = record ? view.store.indexOf(record) : value - 1;
 
        if (metaData && rowspan) {
            metaData.tdAttr = 'rowspan="' + rowspan + '"';
        }
 
        if (page > 1) {
            result += (page - 1) * dataSource.pageSize;
        }
        return result + 1;
    },
 
    updater: function(cell, value, record, view, dataSource) {
        var cellInner = cell && cell.querySelector(this.getView().innerSelector);
        
        if (cellInner) {
            cellInner.innerHTML = this.defaultRenderer(value, null, record, null, null, dataSource, view);
        }
    },
 
    renumberRows: function() {
        if (this.destroying || this.destroyed) {
            return;
        }
        
        var me = this,
            view = me.getView(),
            dataSource = view.dataSource,
            recCount = dataSource.getCount(),
            context = new Ext.grid.CellContext(view).setColumn(me),
            rows = me.getView().all,
            index = rows.startIndex;
 
        while (index <= rows.endIndex && index < recCount) {
            context.setRow(index);
            me.updater(context.getCell(true), ++index, null, view, dataSource);
        }
    }
});