Ext.namespace('Ext.ux.grid');

/**
 * <p>
 * Row Disable plugin provides the ability to visually disable a grid row and prevent any further selections.
 * </p>
 * <p>
 * <b>Notes:</b><ul>
 * <li>This plugin only applies to grids that are using a RowSelectionModel or a CheckboxSelectionModel.</li>
 * </ul>
 * </p>
 * <pre>
 * var grid = new Ext.grid.EditorGrid({plugins:new Ext.ux.grid.DisableRow(), ...})
 * var record = grid.getStore().getAt(0);
 * var id = record.id;
 * //applies load mask to row and prevents any further selection.
 * grid.disableRow(id); 
 * ...
 * //removes the existing load mask and allows for row selection.
 * grid.enableRow(id); 
 * ...
 * //determine if a row is disabled.
 * var isDisabled = grid.isRowDisabled(id); 
 * </pre>
 * 
 * @class Ext.ux.grid.DisableRow
 * @extends Ext.util.Observable
 * @author Phil Crawford
 * @license Licensed under the terms of the Open Source <a href="http://www.gnu.org/licenses/lgpl.html">LGPL 3.0 license</a>.  Commercial use is permitted to the extent that the code/component(s) do NOT become part of another Open Source or Commercially licensed development library or toolkit without explicit permission.
 *  
 * @version 0.5 (January 12, 2009)
 * @ version 0.4 (December 16, 2008)
 * @ version 0.3 (December 15, 2008)
 * @ version 0.2 (December 15, 2008)
 * @ version 0.1 (December 12, 2008)
 * @constructor
 * @param {Object} config 
 */
Ext.ux.grid.DisableRow = function(config) {
    Ext.apply(this, config);
    Ext.ux.grid.DisableRow.superclass.constructor.call(this);
    
    this.addEvents({
       /**
         * Fires when the plugin is initialized
         * @event initialize
         * @param {Ext.Component} this
         * @param {Ext.Component} The component that contains this plugin
         */
        'initialize': true
        /**
         * Fires after the plugin is destroyed.
         * @event destroy
         * @param {Ext.Component} this
         */
        ,'destroy': true
    });    
}; // eo constructor

Ext.extend(Ext.ux.grid.DisableRow, Ext.util.Observable, {
    //configurables
    /**
     * @cfg {Boolean} preventSelection True to prevent selection of a row that is disabled. Default true.
     */
    preventSelection: true

    
    /**
     * @private
     */
    ,init: function(grid) {
        //Our collection of disabled rows and associated masks.
        var rows = new Ext.util.MixedCollection();
        
        this.grid = grid;
        grid.on('destroy', this.destroy, this, {single: true});
        //prevent the selection of disabled rows
        if (this.preventSelection) {
            grid.getSelectionModel().on('beforerowselect', function(sm, row, keep, record) {
                if (rows.containsKey(record.id)) {
                    //cancel the row select b/c this row is disabled
                    return false;
                }
            }, this);
        }
        
        //expose new methods to the grid
        Ext.apply(grid, {
            /**
             * Disable all rows in the grid.
             */
            disableAllRows: function() {
                var g = this.grid;
                g.getStore().each(function(record) {
                    g.disableRow(record.id);
                });
                
            }.createDelegate(this)
            
            /**
             * Disable a row in the grid and if configured, prevent any selection.
             * @param {String} id The record id to be disabled (if not already)
             */
            ,disableRow: function(id) {
                //make sure the row is not already disabled
                if (rows.containsKey(id)) { return; }
                
                var g = this.grid;
                //lookup the row index for the record
                var row = g.getStore().indexOfId(id);
                if (row === -1) { return; } //not found
                //get the html el for attaching the mask
                var el = g.getView().getRow(row);
                if (!el) { return; }
                //use a simple mask without a message to visually indicate the row is disabled
                var m = new Ext.LoadMask(el, {msg: undefined});
                m.show();
                if (this.preventSelection) {
                    //make sure the row is no longer selected once disabled
                    g.getSelectionModel().deselectRow(row);
                }
                //add index as key and mask as object
                rows.add(id, m);
            }.createDelegate(this)
            
            /**
             * Enable all rows in the grid.
             */
            ,enableAllRows: function() {
                //no rows means nothing to do
                if (rows.length === 0) { return; }
                var g = this.grid;
                g.getStore().each(function(record) {
                    g.enableRow(record.id);
                });
                
            }.createDelegate(this)
            
            
            /**
             * Enable a row in the grid and allow selection again.
             * @param {String} id The record id to be enabled.
             */
            ,enableRow: function(id) {
                //we can not enable a row that is not already disabled
                if (!rows.containsKey(id)) { return; }
                //ensure our associated mask gets destroyed
                var m = rows.get(id);
                m.hide();
                m.destroy();
                rows.removeKey(id);
            }.createDelegate(this)
            
            /**
             * Determine if a row is already disabled
             * @param {String} The record id to test.
             */
            ,isRowDisabled: function(id) {
                return rows.containsKey(id);
            }.createDelegate(this)
        });
        
        //each time the store loads, clear any disabled rows; defined after the functions are added to grid
        grid.getStore().on('beforeload', grid.enableAllRows, this);

        this.fireEvent('initialize', this, grid);
        this.onInit(grid);
    } // eof init

    
    /**
     * Destroy the plugin.  Called automatically when the grid is destroyed.
     */
    ,destroy: function() {
        //destroy any masks we created
        this.grid.enableAllRows();
        //destroy our ref to the grid
        this.grid = null;
        this.onDestroy();
        this.fireEvent('destroy', this);
        this.purgeListeners();
    }

    
    //available to override
    ,onInit: Ext.emptyFn
    
    //available to override
    ,onDestroy: Ext.emptyFn
});
