Ext.CellSelectionModelWithoutNav = Ext.extend(Ext.grid.CellSelectionModel, {
    initEvents : function(){
        Ext.CellSelectionModelWithoutNav.superclass.initEvents.call(this);
        this.grid.getGridEl().un(Ext.isIE || Ext.isSafari3 ? "keydown" : "keypress", this.handleKeyDown, this);
    }
});


Ext.form.ActionsField = Ext.extend(Ext.form.Field,  {
    validationEvent : false,
    validateOnBlur : false,
    defaultAutoCreate : {tag: "div"},

    fieldClass : "x-grid3-cell-inner",

    htmlEncode: false,

    // private
    initEvents : Ext.emptyFn,

    isValid : function(){
        return true;
    },

    validate : function(){
        return true;
    },

    getRawValue : function(){
        return '';
        var v = this.rendered ? this.el.dom.innerHTML : Ext.value(this.value, '');
        if(v === this.emptyText){
            v = '';
        }
        if(this.htmlEncode){
            v = Ext.util.Format.htmlDecode(v);
        }
        return v;
    },

    getValue : function(){
        return this.getRawValue();
    },

    getName: function() {
        return this.name;
    },

    setRawValue : function(v){
        var gridName = this.rowEditor.grid.gridObj.name;
        v='<a href="javascript:void(0)" onclick="gridArray[\''+gridName+'\'].gridObj.inlineRowAction(\'save\')" ><img ext:qtip="'+((this.rowEditor.newRecord)?'Add':'Update')+'" src="'+globalConstants.homeSite+'img/accept.gif" /></a><a href="javascript:void(0)" onclick="gridArray[\''+gridName+'\'].gridObj.inlineRowAction(\'cancel\')"><img ext:qtip="Cancel" src="'+globalConstants.homeSite+'img/reject.gif" /></a>';
        if(this.htmlEncode){
            v = Ext.util.Format.htmlEncode(v);
        }
        return this.rendered ? (this.el.dom.innerHTML = (Ext.isEmpty(v) ? '' : v)) : (this.value = v);
    },

    setValue : function(v){
        this.setRawValue(v);
        return this;
    }

});

Ext.reg('actionsfield', Ext.form.ActionsField);


Ext.form.BlankField = Ext.extend(Ext.form.Field,  {
    validationEvent : false,
    validateOnBlur : false,
    defaultAutoCreate : {tag: "div"},

/**
     * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-display-field")
     */
    fieldClass : "x-form-display-field",

/**
     * @cfg {Boolean} htmlEncode false to skip HTML-encoding the text when rendering it (defaults to
     * false). This might be useful if you want to include tags in the field's innerHTML rather than
     * rendering them as string literals per the default logic.
     */
    htmlEncode: false,

    // private
    initEvents : Ext.emptyFn,

    isValid : function(){
        return true;
    },

    validate : function(){
        return true;
    },

    getRawValue : function(){
        var v = this.rendered ? this.el.dom.innerHTML : Ext.value(this.value, '');
        if(v === this.emptyText){
            v = '';
        }
        if(this.htmlEncode){
            v = Ext.util.Format.htmlDecode(v);
        }
        return v;
    },

    getValue : function(){
        return this.getRawValue();
    },

    getName: function() {
        return this.name;
    },

    setRawValue : function(v){
        v='';
        if(this.htmlEncode){
            v = Ext.util.Format.htmlEncode(v);
        }
        return this.rendered ? (this.el.dom.innerHTML = (Ext.isEmpty(v) ? '' : v)) : (this.value = v);
    },

    setValue : function(v){
        this.setRawValue(v);
        return this;
    }
});

Ext.reg('blankfield', Ext.form.BlankField);

var DevxGrid = function(settings){
    var s = this;
    if (!settings) {
        settings = {};
    };
    if (settings.name) {
        this.name = settings.name;
    } else {
        this.name = 'grid';
    };
    if (settings.extForm) {
        this.extForm = settings.form;
    } else {
        this.extForm = Ext.form;
    };
    if (settings.gridRecord) {
        this.gridRecord = settings.gridRecord;
    }
    if (settings.saveUrl) {
        this.saveUrl = settings.saveUrl;
    }
    if (settings.massSaveUrl) {
        this.massSaveUrl = settings.massSaveUrl;
    }
    if (settings.saveCaption) {
        this.saveCaption = settings.saveCaption;
    }
    if (settings.customButtons) {
        this.customButtons = settings.customButtons;
    }
    if (settings.insertUrl) {
        this.insertUrl = settings.insertUrl;
    }
    if (settings.deleteUrl) {
        this.deleteUrl = settings.deleteUrl;
    }
    if (settings.viewOnly) {
        this.viewOnly = settings.viewOnly;
    }
    if (settings.form) {
        this.form = settings.form;
    } else if (settings.formName){
        this.form = new DevxForm({id:settings.formName+'Form'});
        this.form.afterSave = function () {gridArray[this.name].store.reload();}
    };
    if (settings.rowEditor) {
        this.rowEditor = settings.rowEditor;
        this.rowEditor.addListener('validateedit',function(obj, changes, r, rowIndex){ return s.form.gridSaveRow(obj, changes, r, rowIndex);})
    }
    if (settings.showAddRow) {
        this.showAddRow = settings.showAddRow;
        this.rowEditor.addAtTop = false;
        this.rowEditor.addListener('canceledit',function(obj){ return s.addRow();})
    } else {
        this.showAddRow = false;
    }
    if (settings.confirmDelete) {
        this.confirmDelete = settings.confirmDelete;
    } else {
        this.confirmDelete = 'Confirm delete record';
    };
    this.messages = {selectRow:"Please Select Row"};
    this.reLoad();
}
DevxGrid.prototype.reLoad = function(){
    this.saveStatus = true;
    this.elements = new Array();
    this.deletedRecords = new Array();
    this.extendedVars=new Object();
    this.oldCellRowNumber = -1;
    this.oldCellColNumber = -1;
    this.selCellRowNumber = -1;
    this.selCellColNumber = -1;
    this.edit_mode = false;
}
DevxGrid.prototype.init = function() {
    var c = this;
    var grid = gridArray[this.name];
    var store = grid.getStore();
    var view = grid.getView();
	if(Ext.isIE) {
		store.on("load", function(){
			var elems=Ext.DomQuery.select("div[unselectable=on]", grid.dom);
			for(var i=0, len=elems.length; i<len; i++){
				elems[i].unselectable = "off";
			}
		});
	}

    if (this.customButtons) {
        for (var b in this.customButtons) {
            gridArray[this.name].addButton(this.customButtons[b]);
        }
    }
    
    if (this.saveUrl && !this.rowEditor) {
        gridArray[this.name].addButton({id: this.name+'_save',qtip: this.saveCaption, text:this.saveCaption} , this.saveAll, this);
    }

    view.on('refresh', c.renderAllElements, c);
    store.addListener('load', c.reloadEmptyStore, c);
    if (!gridArray[this.name].drag_n_drop){
        grid.addListener('cellclick', c.cellEdit, c);
        grid.addListener(Ext.isIE || Ext.isSafari3 ? "keydown" : "keypress", c.keyPress, c);
    }

    this.initFilters();
    if (this.showAddRow) {
        store.addListener("load", function(){
            c.addRow();
        });
    }
    if (this.afterInit) {
       this.afterInit();
    }
}

DevxGrid.prototype.keyPress = function(e) {
    var newRow = this.selCellRowNumber;
    var newCol = this.selCellColNumber;
    if (this.edit_mode){
        if (!this.elements[newRow][newCol]) return true;
        if ((e.getKey() == e.TAB) && (!e.shiftKey)){
            while (true){
                newCol++;
                if (newCol ==  this.elements[newRow].length){
                    newCol = 0;
                    newRow++;
                }
                if (newRow == this.elements.length) newRow = 0;
                if (!this.elements[newRow][newCol]) continue;
                if (this.elements[newRow][newCol].el.disabled) continue;
                if (this.elements[newRow][newCol].type == 'Checkbox') continue;
                break;
            }
            this.cellEdit(this, newRow, newCol, e);
            e.stopEvent();
        }else if ((e.getKey() == e.TAB) && (e.shiftKey)){
            while (true){
                newCol--;
                if (newCol ==  -1){
                    newRow--;
                    if (newRow == -1) newRow = this.elements.length -1 ;
                    newCol = this.elements[newRow].length - 1;
                }
                if (!this.elements[newRow][newCol]) continue;
                if (this.elements[newRow][newCol].el.disabled) continue;
                if (this.elements[newRow][newCol].type == 'Checkbox') continue;
                break;
            }
            this.cellEdit(this, newRow, newCol, e);
            e.stopEvent();
        }else if ((e.getKey() == e.ENTER) && (e.ctrlKey) && (!e.shiftKey)){
            while (true){
                newRow++;
                if (newRow == this.elements.length) newRow = 0;
                if (!this.elements[newRow][newCol]) continue;
                if (this.elements[newRow][newCol].el.disabled) continue;
                if (this.elements[newRow][newCol].type == 'Checkbox') continue;
                break;
            }
            this.cellEdit(this, newRow, newCol, e);
            e.stopEvent();
        }else if ((e.getKey() == e.ENTER) && (e.ctrlKey) && (e.shiftKey)){
            while (true){
                newRow--;
                if (newRow == -1) newRow = this.elements.length - 1;
                if (!this.elements[newRow][newCol]) continue;
                if (this.elements[newRow][newCol].el.disabled) continue;
                if (this.elements[newRow][newCol].type == 'Checkbox') continue;
                break;
            }
            this.cellEdit(this, newRow, newCol, e);
            e.stopEvent();
        }else if ((e.getKey() == e.ENTER) && (!e.ctrlKey && !e.shiftKey && !e.altKey)){
            this.cellClearEdit(this, newRow, newCol, e);
            this.selCellRowNumber = newRow;
            this.selCellColNumber = newCol;
            gridArray[this.name].getSelectionModel().select(newRow, newCol);
            e.stopEvent();
        }
    }else{ //navigation in non edit mode
        if (e.getKey() == e.BACKSPACE) e.stopEvent();
        if(!e.isNavKeyPress() && (e.getKey() != e.ENTER)) return;
        var cell;
        var stop = true;
        switch(e.getKey()){
            case e.UP:
                newRow = this.nextCell(newRow, newCol, 0);
                break;
            case e.DOWN:
                newRow = this.nextCell(newRow, newCol, 1);
                break;
            case e.ENTER:
                if ((e.ctrlKey) && (e.shiftKey)) newRow = this.nextCell(newRow, newCol, 0);
                else if (e.ctrlKey) newRow = this.nextCell(newRow, newCol, 1);
                else if (!e.ctrlKey && !e.shiftKey && !e.altKey){
                    if ((this.elements[newRow]) && (this.elements[newRow][newCol])
                        && !this.elements[newRow][newCol].el.disabled
                        && (this.elements[newRow][newCol].type != 'Checkbox'))
                        this.cellEdit(this, newRow, newCol, e);
                    else stop = false;
                }
                break;
            case e.LEFT:
                cell = this.nextCell(newRow, newCol, 2);
                newRow = cell.row;
                newCol = cell.col;
                break;
            case e.RIGHT:
                cell = this.nextCell(newRow, newCol, 3);
                newRow = cell.row;
                newCol = cell.col;
                break;
            case e.TAB:
                if (e.shiftKey){
                    cell = this.nextCell(newRow, newCol, 2);
                }else{
                    cell = this.nextCell(newRow, newCol, 3);
                }
                newRow = cell.row;
                newCol = cell.col;
                break;
        }
        this.selCellRowNumber = newRow;
        this.selCellColNumber = newCol;
        gridArray[this.name].getSelectionModel().select(newRow, newCol);
        if (stop) e.stopEvent();
    }
}

/*
 * Direction: 0 - up, 1 - down, 2 - left, 3 - right
 */
DevxGrid.prototype.nextCell = function(row, col, dir){
    cell = function(col, row){ this.col = col; this.row = row};
    switch(dir){
        case 0: // up
            row--;
            if (row == -1) row = gridArray[this.name].getStore().getCount() - 1;
            return row;
        case 1: // down
            row++;
            if (row == gridArray[this.name].getStore().getCount()) row = 0;
            return row;
        case 2: //left
            while (true){
                col--;
                if (col ==  -1){
                    row--;
                    if (row == -1) row = gridArray[this.name].getStore().getCount() - 1 ;
                    col = gridArray[this.name].getColumnModel().getColumnCount()-1;
                }
                if (gridArray[this.name].getColumnModel().getColumnById(col) && gridArray[this.name].getColumnModel().getColumnById(col).hidden) continue;
                break;
            }
            return new cell(col, row);
        case 3: //left
            while (true){
                col++;
                if (col == gridArray[this.name].getColumnModel().getColumnCount()){
                    row++;
                    if (row == gridArray[this.name].getStore().getCount()) row = 0;
                    col = 0;
                }
                if (gridArray[this.name].getColumnModel().getColumnById(col) && gridArray[this.name].getColumnModel().getColumnById(col).hidden) continue;
                break;
            }
            return new cell(col, row);
    }
}

DevxGrid.prototype.cellClearEdit = function(grid, rowNumber, colNumber, e) {
    this.edit_mode = false;
    if (!this.elements[rowNumber]) return false;
    if (this.viewOnly) return false;
    if ((this.rowNumber != -1) && (this.colNumber != -1)){
        var i = rowNumber;
        var j = colNumber;
        if (this.elements[i][j] && !this.elements[i][j].el.disabled){
            var element = this.elements[i][j];
            if ((element.type == 'TextField') && element.editable )
                element.el.fireEvent('change', element.el, element.el.getValue());
            if ((element.type == 'DateField') && element.editable )
                element.el.fireEvent('change', element.el, element.el.getValue());
            if ((element.type == 'ComboBox') && element.editable)
                element.el.fireEvent('change', element.el, element.el.getValue());
            if (element.type != 'Checkbox') element.editable = false;
            this.renderCell(i, j);
        }
    }
}

DevxGrid.prototype.cellEdit = function(grid, rowNumber, colNumber, e) {
    this.selCellRowNumber = rowNumber;
    this.selCellColNumber = colNumber;
    if (!this.elements[rowNumber]) return false;
    if (this.viewOnly) return false;
    if ((this.oldCellColNumber != -1) && (this.oldCellRowNumber != -1) &&
       ((this.oldCellColNumber != colNumber) || (this.oldCellRowNumber != rowNumber))){
        var i = this.oldCellRowNumber;
        var j = this.oldCellColNumber;
        if (this.elements[i][j] && !this.elements[i][j].el.disabled){
            var element = this.elements[i][j];
            if ((element.type == 'TextField') && element.editable )
                element.el.fireEvent('change', element.el, element.el.getValue());
            if ((element.type == 'DateField') && element.editable )
                element.el.fireEvent('change', element.el, element.el.getValue());
            if ((element.type == 'ComboBox') && element.editable)
                element.el.fireEvent('change', element.el, element.el.getValue());
            if (element.type != 'Checkbox'){
                element.editable = false;
                this.renderCell(i, j);
            }
        }
    }
    if ((this.oldCellRowNumber == rowNumber) && (this.oldCellColNumber == colNumber) && this.edit_mode){
        this.elements[rowNumber][colNumber].el.focus(false, 100);
        return false;
    }
    gridArray[this.name].getSelectionModel().select(rowNumber, colNumber);
    this.oldCellRowNumber = rowNumber;
    this.oldCellColNumber = colNumber;
    if (this.elements[rowNumber][colNumber]){
        var element = this.elements[rowNumber][colNumber];
        if (element.el.disabled){
            this.edit_mode = false;
            return false;
        }
        this.edit_mode = true;
        element.editable = true;
        this.renderCell(rowNumber, colNumber);
    }else{
        this.edit_mode = false;
    }
}

DevxGrid.prototype.renderCell = function(rowNumber, colNumber){
    if (!this.elements[rowNumber]) return false;

    var gridName = this.name;
    var i = rowNumber;
    if (this.elements[i][colNumber]) {
        var element = this.elements[i][colNumber];
        var record = element.record;
        var cm = gridArray[this.name].getColumnModel();
        var dataIndex = cm.getDataIndex(colNumber);

        if ( Ext.get(gridName+'_cell_'+record.id+'_'+dataIndex) ) {
            var params = element.params;
            var value = element.value;

            if (element.editable){
                if (element.type == 'TextField') {
                    el = new Ext.form.TextField(params);
                    el.addListener('change', element.listener, this);
                    el.setValue(record.get(dataIndex,value));
                } else if (element.type == 'ComboBox') {
                    params['editable'] = false;
                    el = new Ext.form.ComboBox(params);
                    el.parent_element = element;
                    el.addListener('change', element.listener, this);
                    el.setValue(record.get(dataIndex,value));
                } else if (element.type == 'DateField') {
                    params['readOnly'] = true;
                    el = new Ext.form.DateField(params);
                    el.addListener('change', element.listener, this);
                    el.setValue(record.get(dataIndex,value));
                } else if (element.type == 'Checkbox') {
                    el = new Ext.form.Checkbox(params);
                    el.addListener('check', element.listener, this);
                }
            }else{
                el = new Ext.form.Label(params);
                if ((element.type == 'TextField') || (element.type == 'DateField')) {
                    el.setText(record.get(dataIndex,value));
                } else if (element.type == 'ComboBox') {
                    el.setText(element.htmlvalue);
                }
                if (record.isModified(dataIndex))
                    Ext.get(gridName+'_cell_'+record.id+'_'+dataIndex).addClass('x-grid3-dirty-cell');
            }
            if (this.addExternalListener) el = this.addExternalListener(i, colNumber, el);
            this.elements[i][colNumber].el = el;
            /*
            if (element.editable){
                this.elements[i][j].el = this.elements[i][j].el_edit;
            }else{
                this.elements[i][j].el = this.elements[i][j].el_view;
            }
            */
            $('#'+gridName+'_cell_'+record.id+'_'+dataIndex).html('');
            this.elements[i][colNumber].el.render(Ext.get(gridName+'_cell_'+record.id+'_'+dataIndex));
            if (element.editable) this.elements[i][colNumber].el.focus(false, 100);
        }
    }
}

DevxGrid.prototype.initFilters = function() {
    var c = this;
    var grid = gridArray[this.name];
    var store = grid.getStore();
    var view = grid.getView();
    //$(window).load(function(){
    $("input[gridFilter][gridId='"+c.name+"']").each(function() {
        var name = this.getAttribute('gridFilter');
        var gridId = this.getAttribute('gridId');
        if (this.type == 'checkbox') {
            if (!this.checked) {
                eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\'\';');
            } else {
                eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
            }
        } else if (this.type == 'radio') {
            if (this.checked) {eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');};
        } else {
            eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
        }

        if (this.type == 'checkbox') {
            $('#'+this.id).bind('click',function() {
                if (!this.checked) {
                    eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\'\';');
                } else {
                    eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
                }
                gridArray[gridId].store.load({params:{start:0, limit:gridArray[gridId].getBottomToolbar().pageSize}});
            });
        } else if (this.type == 'radio') {
            $('#'+this.id).bind('click',function() {
                eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
                gridArray[gridId].store.load({params:{start:0, limit:gridArray[gridId].getBottomToolbar().pageSize}});
            });
        } else {
            $('#'+this.id).bind('change',function() {
                eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
                gridArray[gridId].store.load({params:{start:0, limit:gridArray[gridId].getBottomToolbar().pageSize}});
            });
        }
    });

    $("select[gridFilter][gridId='"+c.name+"']").each(function() {
        var name = this.getAttribute('gridFilter');
        var gridId = this.getAttribute('gridId');
        eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
        $('#'+this.id).bind('change',function() {
            eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
            gridArray[gridId].store.load({params:{start:0, limit:gridArray[gridId].getBottomToolbar().pageSize}});
        });
    });

    $("input[gridSearchButton][gridId='"+c.name+"']").each(function() {
        var gridId = this.getAttribute('gridId');
        $("input[gridSearch][gridId='"+c.name+"']").each(function() {
            var name = this.getAttribute('gridSearch');
            if (this.type == 'checkbox') {
                if (!this.checked) {
                    eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\'\';');
                } else {
                    eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
                }
            } else if (this.type == 'radio') {
                if (this.checked) {eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';'); }
            } else {
                eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
            }
        });
        $("select[gridSearch][gridId='"+c.name+"']").each(function() {
            var name = this.getAttribute('gridSearch');
            eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
        });

        $(this).unbind('click');
        $(this).bind('click',function() {
            $("input[gridSearch][gridId='"+c.name+"']").each(function() {
                var name = this.getAttribute('gridSearch');
                if (this.type == 'checkbox') {
                    if (!this.checked) {
                        eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\'\';');
                    } else {
                        eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
                    }
                } else if (this.type == 'radio') {
                    if (this.checked) eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
                } else {
                    eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
                }
            });

            $("select[gridSearch][gridId='"+c.name+"']").each(function() {
                var name = this.getAttribute('gridSearch');
                eval('gridArray[\''+gridId+'\'].store.baseParams.'+name+'=\''+this.value+'\';');
            });
            gridArray[gridId].store.load({params:{start:0, limit:gridArray[gridId].getBottomToolbar().pageSize}});
        });
   });
   //});
}
DevxGrid.prototype.addRecord = function() {
    var grid = gridArray[this.name];

    var store = grid.getStore();
    var view = grid.getView();
    var record = new Array();
    var params = new Array();
    var keys = this.gridRecord.prototype.fields.keys;
    for (var i=0; i<keys.length; i++) {
        record[i] = new Object();
        record[i].name = keys[i];
    }
    for (var i=0; i<keys.length; i++) {
        params[keys[i]]=null;
    }

    var rec = new this.gridRecord(params);
    store.add(rec);
    if (store.getCount()){
        //store.insert(store.getCount(), rec);
    } else {
        //store.insert(0, rec);
    }
    var i = store.getCount()-1;
    store.getAt(i).beginEdit();
    var c = this;
    view.addListener('rowupdated',function(){c.renderRow(store, store.getAt(i),i);},this);
    c.renderRow(store, store.getAt(i),i);
    //this.renderAllElements();
    if (this.afterAddRecord) this.afterAddRecord(store, i);
}
DevxGrid.prototype.afterEdit = function(oGridEvent) {
    fieldName = oGridEvent.field;
    cellValue = oGridEvent.value;
    var r = oGridEvent.grid.getStore().getAt(oGridEvent.row);
}
DevxGrid.prototype.saveRecord = function(record, rowNumber, last) {
    var id = record.get('id');
    if (record.get('id')) {
        var saveUrl = this.saveUrl;
    } else {
        var saveUrl = this.insertUrl;
    }
    var str='';
    var keys = record.fields.keys;
    for(var i=0;i<keys.length;i++) {
        if (keys[i] != 'data') {
            eval("tmp=record.data."+keys[i]);
            if ( tmp!=null ) {
                eval("str=str+'&'+keys[i]+'='+record.data."+keys[i]);
            }
        }
    }
    if (this.addSaveParam) {
        str=str+this.addSaveParam;
    }
    var c = this;
    $.ajax({
        type:"POST",
        url:saveUrl,
        data:str,
        dataType:'json',
        success:function(response){c.afterSaveRecord(response, rowNumber, last, record);},
        error:function(response){c.saveError(response, rowNumber);}
    });
}
DevxGrid.prototype.saveAll = function() {
    if (this.beforeSave) {
        if (!this.beforeSave()) return;    
    }

    this.oldCellRowNumber = -1;
    this.oldCellColNumber = -1;
    this.selCellRowNumber = -1;
    this.selCellColNumber = -1;
    this.loadMask = new Ext.LoadMask(Ext.getBody(), {msg:"Saving..."});
    this.loadMask.show();
    var store = gridArray[this.name].getStore();
    var n = this.deletedRecords.length;
    var c = this;
    if (n!=0) {
        $.ajax({
            type:"POST",
            url:this.deleteUrl,
            data:'id='+this.deletedRecords.pop(),
            dataType:'json',
            success:function(response){c.saveAll();},
            error:function(response){c.saveError(response, rowNumber);}
        });
    } else {
        var records = store.getRange();
        this.saveStatus = true;
        if (records.length) {
            var dirty_records = new Array();
            var dirty_rows = new Array();
            var j = 0;
            for (var i=0; i<records.length; i++){
                if (!records[i].dirty) continue;
                dirty_records[j] = records[i];
                dirty_rows[j] = i;
                j++;
            }
            if (dirty_records.length){
                if (this.massSaveUrl) {
                    var qs = '';
                    var store = gridArray[this.name].getStore();
                    if (store && store.baseParams) {
                        for (var p in store.baseParams) qs += '&' + p +'=' + store.baseParams[p];
                    }

                    for(var i=0; i<dirty_records.length;i++) {
                        var obj = dirty_records[i];
                        for (var p in obj.data) qs += '&items[' + obj.id + ']['+ p +']=' + obj.data[p];
                    }
                    
                    var c = this;
                    $.ajax({
                        type:"POST",
                        url:this.massSaveUrl,
                        data:qs,
                        dataType:'json',
                        success:function(response){c.afterMassSave(response);},
                        error:function(response){c.saveError(response, 1);}
                    });
                } else {
                    for(var i=0; i<dirty_records.length;i++) {
                        window.setTimeout(function(i, dirty_records) {return function() {
                                c.saveRecord(dirty_records[i], dirty_rows[i], i==dirty_records.length-1);
                            } } (i, dirty_records), 500*i);
                    }
                }
            }else{
                this.loadMask.hide();
                if ( this.afterSave ) {
                    this.afterSave();
                } else {
                    gridArray[this.name].store.load({params:{start:gridArray[this.name].getBottomToolbar().cursor, limit:gridArray[this.name].getBottomToolbar().pageSize}});
                }
            }
        } else {
            this.loadMask.hide();
            if ( this.afterSave ) {
                this.afterSave();
            } else {
                gridArray[this.name].store.load({params:{start:gridArray[this.name].getBottomToolbar().cursor, limit:gridArray[this.name].getBottomToolbar().pageSize}});
            }
        }
    }
}
DevxGrid.prototype.afterSaveRecord = function(response, rowNumber, last, record) {
    var store = gridArray[this.name].getStore();
    var view = gridArray[this.name].getView();
    var div = view.getRow(rowNumber);
    var row = div.getElementsByTagName('tr')[0];
    if (response.status == 'OK') {
        if (row) {
            $(row).removeClass('grid-row-error');
            for (colIndex=0; colIndex < this.elements[rowNumber].length; colIndex++){
                if (Ext.get(this.name+'_cell_'+record.id+'_'+record.fields.keys[colIndex]))
                    Ext.get(this.name+'_cell_'+record.id+'_'+record.fields.keys[colIndex]).removeClass('x-grid3-dirty-cell');
            }
            record.endEdit();
            this.renderRow(store, store.getRange(), rowNumber);
        }
    } else if (response.errormessage) {
        if (row) {
            this.saveStatus = false;

            $(row).addClass('grid-row-error');
            for (var i=0;i<row.cells.length;i++) {
                row.cells[i].setAttribute('title',response.errormessage);
                /*Ext.QuickTips.register({
                    target: Ext.get(row.cells[i]),
                    title: response.errormessage,
                    width: 100
                });*/
            }
        }
    }
    
    if (last) {
        this.loadMask.hide();
        if (this.saveStatus) {
            if ( this.afterSave ) {
                this.afterSave();
            } else {
                    gridArray[this.name].store.load({params:{start:gridArray[this.name].getBottomToolbar().cursor, limit:gridArray[this.name].getBottomToolbar().pageSize}});
            }
        }
    }
}
DevxGrid.prototype.afterMassSave = function(response) {
    var store = gridArray[this.name].getStore();
    var view = gridArray[this.name].getView();
    if (response.result) {
        var res = response.result;
        for (var id in res) {
            var res_mess = res[id];
            var record = store.getById(id);
            var rowNumber = store.indexOf(record);
            if (-1 != rowNumber) {
                var div = view.getRow(rowNumber);
                var row = div.getElementsByTagName('tr')[0];
                if ('OK' == res_mess) {
                    if (row) {
                        $(row).removeClass('grid-row-error');
                        for (colIndex=0; colIndex < this.elements[rowNumber].length; colIndex++){
                            if (Ext.get(this.name+'_cell_'+id+'_'+record.fields.keys[colIndex]))
                                Ext.get(this.name+'_cell_'+id+'_'+record.fields.keys[colIndex]).removeClass('x-grid3-dirty-cell');
                        }
                    }
                } else {
                    if (row) {
                        var mess = '';
                        for (var field in res_mess) {
                            if (res_mess[field]) {
                                for (var err_id in res_mess[field]) mess = res_mess[field][err_id];
                            }
                        }
                        
                        this.saveStatus = false;
                        $(row).addClass('grid-row-error');
                        for (var i=0;i<row.cells.length;i++) {
                            row.cells[i].setAttribute('title', mess);
                        }
                    }
                }
            } 
        }
    }
    
    this.loadMask.hide();
    if (this.saveStatus) {
        if ( this.afterSave ) this.afterSave(response);
        else gridArray[this.name].store.load({params:{start:gridArray[this.name].getBottomToolbar().cursor, limit:gridArray[this.name].getBottomToolbar().pageSize}});
    }
}
DevxGrid.prototype.saveError = function(response, rowNumber) {
    this.saveStatus = false;
    alert('Connection problem');
}
DevxGrid.prototype.validateRecord = function() {

}
DevxGrid.prototype.afterDelete = function(rowNumber) {
    gridArray[this.name].getStore().remove(gridArray[this.name].getStore().getAt(rowNumber));
}
DevxGrid.prototype.deleteRecord = function (recId, id, deleteUrl, confirmMsg, successFunction) {
    var store = gridArray[this.name].getStore();
    
    if (id) {
        var records = store.query('id', id);
        if (records.get(0)) {
            var record = records.get(0);
            var rowNumber = store.indexOfId(record.id);
        }
    } else {
        var rowNumber = store.indexOfId(recId);
    }

    if (!confirmMsg) {
        confirmMsg = this.confirmDelete;
    }
    if ( confirm(confirmMsg) ) {
        if ( id ) {
            this.deletedRecords.push(id);
        }
        store.remove(gridArray[this.name].getStore().getAt(rowNumber));
    }
}
DevxGrid.prototype.enableLoading = function() {
}

DevxGrid.prototype.renderAllElements = function() {
    var gridName = this.name;
    var store = gridArray[this.name].getStore();
    var n = store.getCount();
    var m = gridArray[this.name].getColumnModel().getColumnCount();
    for (var i=0;i<n;i++) {
        var c = this;
        c.renderRow(store, store.getAt(i),i);
    }
}

DevxGrid.prototype.renderRow = function(store, records, rowNumber) {
    var gridName = this.name;
    var n = gridArray[this.name].getStore().getCount();
    var m = gridArray[this.name].getColumnModel().getColumnCount();
    var i = rowNumber;
    if (this.elements[i]) {
        for (var j=0;j<m;j++) {
            if (this.elements[i][j]) this.renderCell(i, j);
        }
    }

}
DevxGrid.prototype.renderComboBox = function (params, value, metadata, record, rowIndex, colIndex, store) {
    var gridName = this.name;
    var view = gridArray[this.name].getView();
    var cm = gridArray[this.name].getColumnModel();
    var dataIndex = cm.getDataIndex(colIndex);
//    colIndex = view.cm.config[colIndex].id;
    record.beginEdit();

    if (this.viewOnly) {
        if (params.transform) {
            params.store = new Array();
            var sel=document.getElementById(params.transform);
            var optionIndex = 0;
            for (var i=0;i<sel.options.length; i++) {
                if (value == sel.options[i].value) {
                    return sel.options[i].innerHTML;
                }
            }
        }
        return value;
    }
    if (!Ext.get(this.name+'_cell_'+rowIndex+'_'+colIndex)) {
        if (params.transform) {
            params.store = new Array();
            var sel=document.getElementById(params.transform);
            var optionIndex = 0;
            var htmlvalue = value;
            var option_labels = new Array();
            for (var i=0;i<sel.options.length; i++) {
                if (!value && 
                    (!params.defaultValue || (params.defaultValue != null && params.defaultValue == sel.options[i].text))) {
                    value = sel.options[i].value;
                    record.set(dataIndex,value);
                }
                if (value == sel.options[i].value) {
                    htmlvalue = sel.options[i].innerHTML;
                }
                option_labels[sel.options[i].value] = sel.options[i].innerHTML;

                if (!(params.excludeField && record.data[params.excludeField] == sel.options[i].value)) {
                    params.store[optionIndex++] = new Array(sel.options[i].value, sel.options[i].innerHTML);
                }
            }
            params.transform = null;
        }
        
        if (!this.elements) {
            this.elements = new Array();
        }
        if (!this.elements[rowIndex]) {
            this.elements[rowIndex] = new Array();
        }
        var element = new Object();
        element.type = 'ComboBox';
        element.record = store.getAt(rowIndex);
        element.params = params;
        element.value = value;
        element.htmlvalue = htmlvalue;
        element.editable = false;
        element.option_labels = option_labels;
        element.listener = function (el, value) {
                var element = el.parent_element;
                if (gridArray[gridName].getStore().getAt(rowIndex).get(dataIndex) == value) return;
                element.htmlvalue = element.option_labels[value];
                gridArray[gridName].getStore().getAt(rowIndex).set(dataIndex, value);
            };
        this.elements[rowIndex][colIndex] = element;
    }

    return '<div id='+this.name+'_cell_'+record.id+'_'+dataIndex+' ></div>';
}
DevxGrid.prototype.renderTextField = function (params, value, metadata, record, rowIndex, colIndex, store) {
    if (this.viewOnly) {
        return value;
    }
    var gridName = this.name;
    var view = gridArray[this.name].getView();
    var cm = gridArray[this.name].getColumnModel();
    var dataIndex = cm.getDataIndex(colIndex);
//    colIndex = view.cm.config[colIndex].id;

    if (!Ext.get(this.name+'_cell_'+rowIndex+'_'+colIndex)) {
        record.beginEdit();
        if (!this.elements) {
            this.elements = new Array();
        }
        if (!this.elements[rowIndex]) {
            this.elements[rowIndex] = new Array();
        }
        var element = new Object();
        element.type = 'TextField';
        element.record = store.getAt(rowIndex);

        element.params = params;
        element.value = value;
        element.editable = false;
        element.listener = function (el, value) {
                gridArray[this.name].getStore().getAt(rowIndex).set(dataIndex,value);
            };
        this.elements[rowIndex][colIndex] = element;

    }

    return '<div id='+this.name+'_cell_'+record.id+'_'+dataIndex+' ></div>';
}
DevxGrid.prototype.renderDateField = function (params, value, metadata, record, rowIndex, colIndex, store) {
    if (this.viewOnly) {
        return value;
    }
    var gridName = this.name;
    var view = gridArray[this.name].getView();
    var cm = gridArray[this.name].getColumnModel();
    var dataIndex = cm.getDataIndex(colIndex);
//    colIndex = view.cm.config[colIndex].id;

    if (!Ext.get(this.name+'_cell_'+rowIndex+'_'+colIndex)) {
        record.beginEdit();
        if (!this.elements) {
            this.elements = new Array();
        }
        if (!this.elements[rowIndex]) {
            this.elements[rowIndex] = new Array();
        }
        var element = new Object();
        element.type = 'DateField';
        element.record = store.getAt(rowIndex);

        params['format'] = 'Y-m-d';
        element.params = params;
        element.value = value;
        element.editable = false;
        element.listener = function (el, value) {
                if (el.isValid(false)){
                    gridArray[this.name].getStore().getAt(rowIndex).set(dataIndex,value.format('Y-m-d'));
                }
            };
        this.elements[rowIndex][colIndex] = element;

    }

    return '<div id='+this.name+'_cell_'+record.id+'_'+dataIndex+' ></div>';
}
DevxGrid.prototype.renderCheckbox = function (params, value, metadata, record, rowIndex, colIndex, store) {
    var gridName = this.name;
    var view = gridArray[this.name].getView();
    var cm = gridArray[this.name].getColumnModel();
    var dataIndex = cm.getDataIndex(colIndex);
//    colIndex = view.cm.config[colIndex].id;

    if (this.viewOnly) {
        var checkedValue = params.checkedValue;
        params.checkedValue = null;

        var uncheckedValue = params.uncheckedValue;
        params.uncheckedValue = null;

        if (value == checkedValue) {
            return '<img src="'+globalConstants.homeSite+'img/check.gif" />';
        } else {
            return '';
        }
    }
    record.beginEdit();
    if (!Ext.get(this.name+'_cell_'+rowIndex+'_'+colIndex)) {
        if (!this.elements) {
            this.elements = new Array();
        }
        if (!this.elements[rowIndex]) {
            this.elements[rowIndex] = new Array();
        }
        
        var checkedValue = params.checkedValue;
        params.checkedValue = null;
        
        var uncheckedValue = params.uncheckedValue;
        params.uncheckedValue = null;
        
        if (value == checkedValue) {
            params.checked = true;
            record.set(dataIndex,checkedValue);
        } else {
            record.set(dataIndex,uncheckedValue);
        }

        var element = new Object();
        element.type = 'Checkbox';
        element.record = store.getAt(rowIndex);
        element.params = params;
        element.value = value;
        element.editable = true;
        element.listener =function (el, value) {
            if ( el.checked ) {
                gridArray[gridName].getStore().getAt(rowIndex).set(dataIndex,checkedValue);
            } else {
                gridArray[gridName].getStore().getAt(rowIndex).set(dataIndex,uncheckedValue);
            }
            Ext.get(gridName+'_cell_'+record.id+'_'+dataIndex).addClass('x-grid3-dirty-cell');
        };

        this.elements[rowIndex][colIndex] = element;
    }
    return '<div id='+this.name+'_cell_'+record.id+'_'+dataIndex+' ></div>';
}

DevxGrid.prototype.renderRecordNumber = function (params, value, metadata, record, rowIndex, colIndex, store) {
    var gridName = this.name;
    var cm = gridArray[this.name].getColumnModel();
    var dataIndex = cm.getDataIndex(colIndex);

    record.beginEdit();
    var order = rowIndex+1;
    record.set(dataIndex, order);
    return '<div id='+this.name+'_cell_'+record.id+'_'+dataIndex+' >'+order+'</div>';
}
DevxGrid.prototype.renderAction = function (params, value, metadata, record, rowIndex, colIndex, store) {
    var gridName = this.name;
    var cm = gridArray[this.name].getColumnModel();
    var dataIndex = cm.getDataIndex(colIndex);

    record.beginEdit();
    if (params) {
        var str = '';
        if (params.del) {
            str+='<a onclick="gridArray[\''+this.name+'\'].gridObj.deleteRecord('+record.id+','+record.get('id')+',\''+globalConstants.homeSite+params.delUrl+record.get('id')+'\');" href="javascript:void(0);"><img src="'+globalConstants.homeSite+'img/delete.gif" /></a>';
        }
    }

    return '<div id='+this.name+'_cell_'+record.id+'_'+dataIndex+' >'+str+'</div>';
}
DevxGrid.prototype.renderNoRender = function (params, value, metadata, record, rowIndex, colIndex, store) {
    var gridName = this.name;
    var cm = gridArray[this.name].getColumnModel();
    var dataIndex = cm.getDataIndex(colIndex);

    record.beginEdit();
    return '<div id='+this.name+'_cell_'+record.id+'_'+dataIndex+' ></div>';
}

DevxGrid.prototype.renderWithQtip = function (params, value, metadata, record, rowIndex, colIndex, store) {
    var data = record.data;
    if (params.length) {
        if ( value.length >= params.length ) {
            //var qtip = this.qtipTpl.apply(value);
            return '<div qtip="' + value +'">' + value + '</div>';
        }
    }
    return value;
}

DevxGrid.prototype.reloadEmptyStore = function (s, r, o) {
    if (0 == s.getCount() && o && o.params) {
        var p = o.params;
        if (p.start && p.limit && p.start - p.limit >= 0) {
            o.params.start = p.start - p.limit;
            s.load(o);
        }
    }
    return;
}

DevxGrid.prototype.addRow = function (e) {
    if (!e) {
        e = new this.addRowElement();
    }
    this.rowEditor.stopEditing(false);
    var rowNumber = 0;
    if (this.showAddRow) {
        rowNumber = gridArray[this.name].getStore().getCount();
        gridArray[this.name].getStore().add(e);
    } else {
        gridArray[this.name].getStore().insert(rowNumber, e);
    }


    gridArray[this.name].getView().refresh();
    //gridArray[this.name].getSelectionModel().select(rowNumber,0);
    this.rowEditor.newRecord = true;
    this.rowEditor.startEditing(rowNumber,true);
}
DevxGrid.prototype.deleteRow = function (id) {
    this.rowEditor.stopEditing(false);
    var store = gridArray[this.name].getStore();
    var rowNumber = null;
    if (id) {
        rowNumber = store.indexOf(store.getById(id));
    } else {
        var s = gridArray[this.name].getSelectionModel().getSelectedCell();
        if (s!=null && s[0]!=null) {
            var r = gridArray[this.name].getStore().getAt(s[0]);
            if (r.data.id){
                id = r.data.id;
                rowNumber = s[0];
            }
        }
    }
    if ( id!=null && rowNumber!=null ) {
        if (this.form.gridDeleteRow(this.deleteUrl+'id/'+id+'/ajax/Y/', this.confirmDelete, this.rowEditor)) {
            this.removeRow(rowNumber);
        } else if (this.showAddRow) {
            this.addRow();
        }
    } else {
        alert(this.messages.selectRow);
    }

}
DevxGrid.prototype.editRow = function (id) {
    this.rowEditor.stopEditing(false);
    var store = gridArray[this.name].getStore();
    var rowNumber = null;
    if (id) {
        rowNumber = store.indexOf(store.getById(id));
    } else {
        var s = gridArray[this.name].getSelectionModel().getSelectedCell();
        if (s!=null && s[0]!=null) {
            var r = store.getAt(s[0]);
            if (r.data.id){
                id = r.data.id;
                rowNumber = s[0];
            }
        }
    }

    if ( id!=null && rowNumber!=null ) {
        this.rowEditor.startEditing(rowNumber, false);
    } else {
        alert(this.messages.selectRow);
    }
}
DevxGrid.prototype.removeRow = function (i) {
    var store = gridArray[this.name].getStore();
    store.removeAt(i);
    if (store.getCount()==0) {
        this.reloadEmptyStore(store, null, {params:store.lastOptions.params});
    }
}
DevxGrid.prototype.inlineRowAction = function (action) {
    if (action=='save') {
        this.rowEditor.stopEditing(true);
    } else {
        this.rowEditor.cancelButtonPressed();
    }
}
