/** 
Grid state manager. 
Restores state using the column id as the restore reference. 

API notes: id used rather than dataIndex because the required id methods are public, 
some of the dataIndex methods are private. 
The "config" property is misleadingly described as "The config passed into the constructor", 
when in fact it gets updated every time the columns change.     

Stores the following: 
1. lock state 
2. hidden state 
3. column widths 
4. order of columns 
5. column to sort by, and sort direction. 
   
TODO : 
1. This could be made more efficient, particularly for large grids, by only saving 
changes to the original config. However, the original config is not readily available, 
so we would need to store the orignal config or a reference to it.   

2. Store state for a paging grid. 

3. Automatically sort if a local grid during initialisation. (Not for a remote grid.) 

@constructor 
*/ 
Ext.grid.GridStateManager2 = function(){ 
    this.state = {}; 
}; 

/** 
Initialises <code>grid</code> with states in <code>provider</code>. 
   
@param {Grid} grid 
@param {Provider} provider 
*/ 
Ext.grid.GridStateManager2.prototype = {
    init : function(grid, provider) { 
    this.provider = provider; 
    this.grid = grid; 
 
    this.cm = grid.getColumnModel(); 
    this.ds = grid.getDataSource(); 
    //save a copy of the default config object. There has GOT to be a better way to clone an object...
    this.origConfig = Ext.util.JSON.decode(Ext.util.JSON.encode(this.cm.config));
    // Get the state to be restored to the grid. // 
    var state = provider.get(this.getStateKey()); 
     
    if ( state ) { 
        this.restoreState(state);
    } 

    // Set listeners on all events that relate to grid changes. 
    // Hence, state should be updated every time the grid changes. 
    // You might want to do this differently. E.g. save state when a user presses a button; when the page unloads, etc. 
    // 
    function setState() { 
        this.updateState(); 
        this.storeState(); 
    } 
    // NB: widthchange event on ColumnModel does not fire when columns are resized. Must use grid columnresize event. 
    grid.on("columnresize", setState, this); 
    this.cm.on("hiddenchange", setState, this); 
    this.cm.on("columnlockchange", setState, this); 
    this.cm.on("columnmoved", setState, this); 
    //this.ds.on("datachanged", setState, this); 
  },
  storeState : function() { 
    this.provider.set(this.getStateKey(), this.state); 
  },
    restoreState : function(state){
        var col, colConfig, config, i, sort;
        if ( "config" in state ) { 
            config = state.config; 
         
            // Restore Column Model config. 
            for (i = 0; i < config.length; i++) { 
                colConfig = config[i]; 
                col = this.cm.getIndexById(colConfig.id); 
                if (col != -1) { 
                    if (col != i) { 
                        this.cm.moveColumn(col, i); 
                    } 
                    if ( "hidden" in colConfig ) { 
                        this.cm.setHidden(i, colConfig.hidden); 
                    } else {
                        this.cm.setHidden(i, false);
                                        }
                    if ( "locked" in colConfig ) { 
                        this.cm.setLocked(i, colConfig.locked); 
                    }  else {
                        this.cm.setLocked(i, 'false');
                                        }
                    if ( "width" in colConfig ) { 
                        this.cm.setColumnWidth(i, colConfig.width); 
                    } 
                } 
            } 
        } 
     /*
        if ( "sortInfo" in state ) { 
            var sortInfo = state.sortInfo; 
            if ( ("field" in sortInfo) && ("direction" in sortInfo) ) { 
                this.ds.setDefaultSort(sortInfo.field, sortInfo.direction); 
                // If local, might want to sort straight away as well... 
            } 
        } 
      */
    },
    resetState: function(){
             this.state.config = this.origConfig;
             this.restoreState(this.state);
    },
           getStateKey : function() { 
             return this.grid.id + "-grid-state";  
    } ,  
    updateState : function() { 
             var cm = this.grid.getColumnModel(); 
             var ds = this.grid.getDataSource(); 
             var state = this.state; 

    // Copy the current sort column/direction. 
    var sortState = ds.getSortState(); // {field: "..dataIndex of sort field..", direction: "ASC"|"DESC"} 
    if ( typeof(sortState) == "object" ) { 
        if ( ("field" in sortState) && ("direction" in sortState) ) { 
            state.sortInfo = {}; 
            state.sortInfo.field = sortState.field; 
            state.sortInfo.direction = sortState.direction;  
        } 
    } 
     
    // Copy column model config array. 
    var c = [];
        for (var i = 0; i < cm.config.length; i++) {
            c.push({id:cm.config[i].id,
                hidden:cm.config[i].hidden,
                width:cm.config[i].width,
                locked:cm.config[i].locked
            });
        }
        var obj = Ext.encode(c); 
    state.config = Ext.decode(obj); 
    }
}; 

Ext.apply(Ext.grid.Grid.prototype, {
  restoreState: function (provider) {
    if (!provider) {
      provider = Ext.state.Manager;
    }
    this.sm = new Ext.grid.GridStateManager2();
    this.sm.init(this, provider);    
  },
    getStateManager : function(){
        return this.sm;
    }
});  

	var GridAction =function(config){	
		if(!config.confirm)
		{	config.confirm=false;
		}
		if(config.minSelectable==undefined)
		{	config.minSelectable=1;
		}
		if(config.maxSelectable==undefined)
		{	config.maxSelectable=1;
		}
		this.grid = config.grid;
		this.urlTemplate = config.urlTemplate;
		this.multiUrlTemplateBase = config.multiUrlTemplateBase;
		this.multiUrlTemplateSuffix = config.multiUrlTemplateSuffix;
		this.maxSelectable = config.maxSelectable;
		this.minSelectable = config.minSelectable;
		this.confirm = config.confirm;
		this.confirmTitle = config.confirmTitle;
		this.confirmText = config.confirmText;
		this.multiConfirmTitle = config.multiConfirmTitle;
		this.multiConfirmText = config.multiConfirmText;
		this.triggerEls = config.triggerEls;
		
		if(this.triggerEls)
		{	for(var i=0,len=this.triggerEls.length;i<len;i++)
			{	if(this.triggerEls[i].setHandler)
				{	this.triggerEls[i].setHandler(this.perform,this);
				}
				else if(this.triggerEls[i].on)
				{	this.triggerEls[i].on('click',this.perform,this);
				}
			}
			
		}		
		this.grid.getSelectionModel().on('rowselect',function(){
			if(this.triggerEls)
			{	var count = this.grid.getSelectionModel().getCount();
				if((this.minSelectable>0 && count<this.minSelectable)||(this.maxSelectable>0 && count>this.maxSelectable))
				{	for(var i=0,len=this.triggerEls.length;i<len;i++)
					{	if(this.triggerEls[i].disable)
						{	this.triggerEls[i].disable();
						}
					}
				}
				else
				{	for(var i=0,len=this.triggerEls.length;i<len;i++)
					{	if(this.triggerEls[i].enable)
						{	this.triggerEls[i].enable();
						}
					}
				}
				
			}
		},this);
	
		GridAction.superclass.constructor.call(this, null, config);
	};
	Ext.extend(GridAction, Ext.util.Observable, {
		perform: function(){
			var count = this.grid.getSelectionModel().getCount();
			if(this.minSelectable>0&&count<this.minSelectable)
			{	return; //too few rows
			}
			if(this.maxSelectable>0&&count>this.maxSelectable)
			{	return; //too many rows
			}
			if(this.maxSelectable!=1)
			{	var records = this.grid.getSelectionModel().getSelections();
				if(this.confirm)
				{	Ext.MessageBox.confirm(this.multiConfirmTitle,this.multiConfirmText,function(btn){	if(btn=='yes')
					{	this.handlerMultiple(records);
					}
					},this);
				}
				else
				{	this.handlerMultiple(records);
				}
			}
			else
			{	var record = this.grid.getSelectionModel().getSelected();
				if(this.confirm)
				{	var text = this.confirmText.applyTemplate?this.confirmText.applyTemplate(record.data):this.confirmText;
					var title = this.confirmTitle.applyTemplate?this.confirmTitle.applyTemplate(record.data):this.confirmTitle;
					Ext.MessageBox.confirm(title,text,function(btn){	if(btn=='yes')
					{	this.handler(record);
					}
					},this);
				}
				else
				{	this.handler(record);
				}
			}
		}
	});

	var urlButtonHandle =function(config){	
		urlButtonHandle.superclass.constructor.call(this, config);
	};
	Ext.extend(urlButtonHandle, GridAction, {
		handler: function(record){
			var url = this.urlTemplate.applyTemplate(record.data);
			window.location = url;
		},
		handlerMultiple: function(records)
		{	var url = this.multiUrlTemplateBase;
			for(i=0,len=records.length;i<len;i++)
			{	url += this.multiUrlTemplateSuffix.applyTemplate(records[i].data);
			}
			window.location = url;
		}

	});
	var AjaxEvalActionHandle =function(config){	
		AjaxEvalActionHandle.superclass.constructor.call(this, config);
	};
	Ext.extend(AjaxEvalActionHandle, GridAction, {
		handler: function(record){
			var url = this.urlTemplate.applyTemplate(record.data);
			var conn = new Ext.Ajax({'url':url});
			conn.request({callback:function(o,s,r){if(s)
				{	eval(r.responseText);
				}
			}});
		},
		handlerMultiple: function(records)
		{	var url = this.multiUrlTemplateBase;
			for(i=0,len=records.length;i<len;i++)
			{	url += this.multiUrlTemplateSuffix.applyTemplate(records[i].data);
			}
			Ext.Ajax.request({'url':url,callback:function(o,s,r){if(s)
				{	eval(r.responseText);
				}
			}});
		}

	});