/**
 * @author luimm
 * 
 * There are some Ext cross-browser issues that I take care of here.
 * Also, some extensions to components that make life easier.
 */
 
/* This is some spacer image that was going against extjs.com */
Ext.BLANK_IMAGE_URL='/globalassets/ext/s.gif';

/* These are for field validation */
Ext.apply(Ext.form.VTypes, {
	// 123-123-123 Ext. 123
	phoneRegExp: /^([0-9]{3}[-]){2}([0-9]{4})/,
	phone: function(v) {
		return this.phoneRegExp.test(v);
	},
	phoneMask: /[\da-zA-Z. -]/,
	phoneText: 'Not a valid phone number. Must be in the format 123-456-7890 Ext.123'
});

Ext.override(Ext.form.Layout, {
	getFields: function() {
		var stack = this.stack;
		var fields = [];
		for(var i=0; i < stack.length; i++) {
			if(stack[i].isFormField) fields.push(stack[i]);
			else if(stack[i].stack) {
				fields = fields.concat(stack[i].getFields());
			}
		}
		return fields;
	},
	isValid: function() {
		var fields = this.getFields();
		var valid = true;
		for (var i=0; i<fields.length; i++) {
			if (!fields[i].validate()) valid = false;
		}
		return valid;
	}
});

/**
 * This is an extension to Ext.
 * This allows ComboBox to filter its underlying datastore.
 * @param {Object} field
 * @param {Object} value
 */
/**
Ext.override(Ext.form.ComboBox, {
	filter: function(field, value) {
		var ds = this.store;
		// ignore '*' b/c that's for everyone
		ds.filterBy(function (record, id) {
			var val = record.get(field);
			if (val=='*') return true;
			return (val==value);
		});
		
		ds.realSnapshot = ds.snapshot;
		ds.snapshot = ds.data;
		
		// default selection if there's only 1 record
		if (this.store.getCount() == 1) {
			var rec = this.store.getAt(0);
			this.setValue(rec.get(this.valueField));
		}
	},
	clearFilter: function(suppressEvent) {
		var ds = this.store;
		if (ds.realSnapshot && ds.realSnapshot != ds.snapshot) {
			ds.snapshot = ds.realSnapshot;
			delete ds.realSnapshot;
		}
		ds.clearFilter(suppressEvent);
	}
});
**/

/* Extensions to all field objects */
Ext.override(Ext.form.Field, {
	/**
	 *	Change default validation message target to under the element
	 */
	msgTarget:'under',
	labelSeparator:':', //I don't have access to the value in fieldset
	
	/**
	 *	Hides the field and label (no idea why this is not default behavior)
	 */
	hideAll: function() {
		var container = this.el.up('.x-form-item');
		container.enableDisplayMode();
		container.hide();
		this.hidden=true;
		this.reset();
		this.disable();
		if (this.errorEl) this.errorEl=null;
	},
	
	/**
	 *	Shows the field and label
	 */
	showAll: function() {
		var container = this.el.up('.x-form-item');
		container.show();
		this.hidden=false;
		this.enable();
	},
	
	/**
	 *	Updates the field's label
	 */
	updateLabel: function(newLabel) {
		if (newLabel) {
			var label = this.el.up('.x-form-item').down('label');
			label.update(newLabel+this.labelSeparator);
		}
	},
	
	/**
	 * sets allowBlank to the boolean passed in
	 */
	setRequired: function(required) {
		this.allowBlank = required;
	}
});

/* Extensions to the Ext view */
Ext.override(Ext.View, {
	/**
	 *	Updates the view's template
	 */
	updateTemplate: function(newTpl) {
		var template = new Ext.Template(newTpl);
		template.compile;
		this.tpl = template;
		this.refresh();
	}
});

/**
 * @class Ext.form.CheckSelectboxList
 * @extends Ext.form.Field
 * Grouping field.  Can be used as a direct replacement for traditional checkbox fields.
 * @constructor
 * Creates a new CheckSelectboxList
 * @param {Object} config Configuration options
 */
Ext.form.CheckSelectboxList = function(config){
    Ext.form.CheckSelectboxList.superclass.constructor.call(this, config);
    this.addEvents({
    	/**
         * @event select
         * Fires when a list item is selected
	     * @param {Ext.form.CheckSelectboxList} selectlist this Ext.form.CheckSelectboxList
	     * @param {String} the value of the item selected
	     * @param {Boolean} if checkbox/radiobox was checked
	     */
        'select': true
    });
};

Ext.extend(Ext.form.CheckSelectboxList, Ext.form.Field,  {
    /**
     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to 'x-form-check-focus')
     */
    focusClass : "x-form-checklist-focus",
    /**
     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
     */
    fieldClass: "x-form-checklist",

    // private
    defaultAutoCreate : { tag: 'div' },
    /**
     * @cfg {String} boxLabel The text that appears beside the checkbox
     */
    store: undefined,
	nameValue: undefined,
	valueField: undefined,
	labelField: undefined,
	defaultField: undefined,
	inputType: 'checkbox',
	listStyle: 'vertical',
	fieldHeight: undefined,
	allowBlank: true,
	blankText: "You must make at least one selection",
	validator: undefined,
	validateOnBlur: false,
	loadingText: 'Loading...',
	starFilter: true,
    /**
     * @cfg {String} inputValue The value that should go into the generated input element's value attribute
     */

    // private
    onRender: function(ct, position){
        Ext.form.CheckSelectboxList.superclass.onRender.call(this, ct, position);
        this.el.dom.removeAttribute('name');
		this.el.setWidth(this.fieldWidth);
		if(this.fieldHeight!==undefined) this.el.setHeight(this.fieldHeight);

		// build template for checkbox input and its label
		this.generateTemplate();
		// connect the view to the store
		this.view = new Ext.View(this.el, this.tpl, {
            singleSelect:false, store:this.store
        });
		this.view.on('click', this.onViewClick, this);
		
		this.store.on('beforeload', this.onStoreBeforeLoad, this);
		this.store.on('datachanged', this.onStoreChange, this);
		this.store.on('load', this.onStoreLoad, this);
		this.selectedValues = this.getSelectedValues(true);
    },
    
    generateTemplate: function() {
    	var listStyleClass = (this.listStyle=='horizontal')?'x-form-cb-li x-form-cb-li-h':'x-form-cb-li';
    	if (this.valueField == 'ASM')
    	{
    	   		this.tpl = '<div class="'+listStyleClass+'">'
   				+ '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="'+this.inputType+'" class="x-form-field" id="'+this.nameValue+'-{'+this.valueField+'}" name="'+this.nameValue+'" value="{'+this.valueField+'}" {'+this.defaultField+'} />'
				+ '<label class="x-form-cb-label" for="'+this.nameValue+'-{'+this.valueField+'}">{'+this.displayField+'}</label></div>';
    	
    	}
    	if (this.valueField != 'ASM')
    	{
	   		this.tpl = '<div class="'+listStyleClass+'">'
	   		+ '<input type="'+this.inputType+'" class="x-form-field" id="'+this.nameValue+'-{'+this.valueField+'}" name="'+this.nameValue+'" value="{'+this.valueField+'}" {'+this.defaultField+'} />'
			+ '<label class="x-form-cb-label" for="'+this.nameValue+'-{'+this.valueField+'}">{'+this.displayField+'}</label></div>';
		}
    },
    
    onViewClick: function(vw, index, node, e) {
    	var box = e.getTarget();
    	if (box.type!= undefined) {
	    	this.selectedValues = this.getSelectedValues(true);
	    	this.validate();
    		this.fireEvent('select', this, box.value, box.checked);
    	}
    },
    
    onStoreBeforeLoad : function(){
        this.el.update(this.loadingText ?
               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
    },
    
	onStoreChange: function(store) {
		this.selectedValues = this.getSelectedValues(true);
	},
	
	onStoreLoad: function(store) {
		this.defaultSelect();
	},
	
	defaultSelect: function() {
		// default select if this field is required, and only one selection available
		// this is mainly to default-select aviation and marine brands
		if (this.allowBlank === false && this.store.getCount()==1) {
			var nodes = this.view.getNodes();
			if (nodes && nodes[0]) {
				var node = Ext.fly(nodes[0]);
				if (node) {
					var box = node.down('input').dom;
					if (box) {
						box.checked = true;
						this.selectedValues = this.getSelectedValues(true);
						this.fireEvent('select', this, box.value, box.checked);
					}
				}
			}
		}
	},

    // private
    initValue: Ext.emptyFn,

    /**
     * Returns array of input values that were checked in the select list
     * It will give back a cached array, and only retrieves a fresh version if
     * refresh is passed.
     * @return {Array} empty array if nothing was found
     */
    getSelectedValues: function(refresh){
    	if (refresh===true) {
	    	var values = [];
	        var nodes = this.view.getNodes();
	        for (var i=0; i<nodes.length; i++) {
	        	var node = Ext.fly(nodes[i]);
	        	if (node) {
		        	var box = node.down('input').dom;
		        	if (box.checked==true) {
		        		values.push(box.value);
		        	}
		        }
	        }
	        return values;
	    }
	    return this.selectedValues;
    },
	
	clearValues : function() {
		this.view.refresh();
	},
	
	/**
	 * Resets the field to original values (last time store was loaded)
	 */
	reset: function() {
		Ext.form.CheckSelectboxList.superclass.reset.call(this);
		this.clearValues();
	},
	
	/**
	 * This is a very sepcial filter, that I've made as a default.
	 * Starfilter is on by default (meaning when filtering, the store
	 * will ignore asterisk "*" and not filter it out.
	 * This is useful for records that span across all possible filtered keys.
	 */
	filter: function(field, value) {
		var isStarFilter = (this.starFilter===true);
		this.store.filterBy(function (record, id) {
			var val = record.get(field);
			if (isStarFilter==true && val=='*') return true;
			if (value instanceof Array) {
				for (var i=0; i<value.length; i++) {
					if (val==value[i]) return true;
				}
				return false;
			} else {
				return (val==value);
			}
		});
		this.defaultSelect();
	},
	
	clearFilter: function(suppressEvent) {
		this.store.clearFilter(suppressEvent);
	},
	
	/**
	 * This allows you to change between say radio and checkbox on the fly
	 */
	changeInputType: function(inputType) {
		this.inputType = inputType;
		this.generateTemplate();
		this.view.updateTemplate(this.tpl);
	},
	
	/**
	 * To enforce single selections, we change to radio boxes
	 */
	enableSingleSelect: function() {
		this.changeInputType('radio');
	},
	
	/**
	 * To allow multiple selections, we change to check boxes
	 */
	disableSingleSelect: function() {
		this.changeInputType('checkbox');
	},
	
	getValue: function() {
		return this.getSelectedValues();
	},
	
	getRawValue: function() {
		return this.getSelectedValues();
	},
	
	setValue: function(value) {
		if (!value || value.length<1) return;
		var nodes = this.view.getNodes();
		for (var i=0; i<nodes.length; i++) {
			var box = Ext.fly(nodes[i]).down('input').dom;
			box.checked = false;
			for (var j=0; j<value.length; j++) {
				if (box.value==value[j]) box.checked = true;
			}
			
		}
		this.selectedValues = this.getSelectedValues(true);
		this.fireEvent('select', this, box.value, box.checked);
	},
	
	setRawValue: Ext.emptyFn,
	
	/**
     * This is the main validation routine called when the fieldset or form is requesting
     * for validatoin.
     * @return True if valid
     */
    validateValue : function(value){
    	if(value.length < 1){ // if it's blank
			if(this.allowBlank){
				this.clearInvalid();
				return true;
			}else{
				this.markInvalid(this.blankText);
				return false;
			}
        }
        if(typeof this.validator == "function"){
            var msg = this.validator(value);
            if(msg !== true){
                this.markInvalid(msg);
                return false;
            }
        }
        return true;
    }
});


/**
 * @class Ext.form.CheckboxList
 * @extends Ext.form.Field
 * Single checkbox field.  Can be used as a direct replacement for traditional checkbox fields.
 * @constructor
 * Creates a new CheckBoxList
 * @param {Object} config Configuration options
 */
Ext.form.CheckboxList = function(config){
    Ext.form.CheckboxList.superclass.constructor.call(this, config);
    this.addEvents({
    	/**
         * @event select
         * Fires when a list item is selected
	     * @param {Ext.form.CheckboxList} selectlist this Ext.form.CheckboxList
	     * @param {String} the value of the item selected
	     * @param {Boolean} if checkbox/radiobox was checked
	     */
        'select': true
    });
};
Ext.extend(Ext.form.CheckboxList, Ext.form.Field,  {
    /**
     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to 'x-form-check-focus')
     */
    focusClass : "x-form-checklist-focus",
    /**
     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
     */
    fieldClass: "x-form-checklist",

    // private
    defaultAutoCreate : { tag: 'div' },
    /**
     * @cfg {String} boxLabel The text that appears beside the checkbox
     */
    store: undefined,
	nameValue: undefined,
	valueField: undefined,
	labelField: undefined,
	defaultField: undefined,
	inputType: 'checkbox',
	listStyle: 'vertical',
	fieldHeight: undefined,
	allowBlank: true,
	blankText: "You must make at least one selection",
	validator: undefined,
	validateOnBlur: false,
	loadingText: 'Loading...',
	starFilter: true,
    /**
     * @cfg {String} inputValue The value that should go into the generated input element's value attribute
     */

    // private
    onRender: function(ct, position){
        Ext.form.CheckboxList.superclass.onRender.call(this, ct, position);
        this.el.dom.removeAttribute('name');
		this.el.setWidth(this.fieldWidth);
		if(this.fieldHeight!==undefined) this.el.setHeight(this.fieldHeight);

		// build template for checkbox input and its label
		this.generateTemplate();
		// connect the view to the store
		this.view = new Ext.View(this.el, this.tpl, {
            singleSelect:false, store:this.store
        });
		this.view.on('click', this.onViewClick, this);
		
		this.store.on('beforeload', this.onStoreBeforeLoad, this);
		this.store.on('datachanged', this.onStoreChange, this);
		this.store.on('load', this.onStoreLoad, this);
		this.selectedValues = this.getSelectedValues(true);
    },
    
    generateTemplate: function() {
    	var listStyleClass = (this.listStyle=='horizontal')?'x-form-cb-li x-form-cb-li-h':'x-form-cb-li';
   		this.tpl = '<div class="'+listStyleClass+'">'
   		+ '<input type="'+this.inputType+'" class="x-form-field" id="'+this.nameValue+'-{'+this.valueField+'}" name="'+this.nameValue+'" value="{'+this.valueField+'}" {'+this.defaultField+'} />'
		+ '<label class="x-form-cb-label" for="'+this.nameValue+'-{'+this.valueField+'}">{'+this.displayField+'}</label></div>';
    },
    
    onViewClick: function(vw, index, node, e) {
    	var box = e.getTarget();
    	if (box.type!==undefined) {
	    	this.selectedValues = this.getSelectedValues(true);
	    	this.validate();
    		this.fireEvent('select', this, box.value, box.checked);
    	}
    },
    
    onStoreBeforeLoad : function(){
        this.el.update(this.loadingText ?
               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
    },
    
	onStoreChange: function(store) {
		this.selectedValues = this.getSelectedValues(true);
	},
	
	onStoreLoad: function(store) {
		this.defaultSelect();
	},
	
	defaultSelect: function() {
		// default select if this field is required, and only one selection available
		// this is mainly to default-select aviation and marine brands
		if (this.allowBlank === false && this.store.getCount()==1) {
			var nodes = this.view.getNodes();
			if (nodes && nodes[0]) {
				var node = Ext.fly(nodes[0]);
				if (node) {
					var box = node.down('input').dom;
					if (box) {
						box.checked = true;
						this.selectedValues = this.getSelectedValues(true);
						this.fireEvent('select', this, box.value, box.checked);
					}
				}
			}
		}
	},

    // private
    initValue: Ext.emptyFn,

    /**
     * Returns array of input values that were checked in the select list
     * It will give back a cached array, and only retrieves a fresh version if
     * refresh is passed.
     * @return {Array} empty array if nothing was found
     */
    getSelectedValues: function(refresh){
    	if (refresh===true) {
	    	var values = [];
	        var nodes = this.view.getNodes();
	        for (var i=0; i<nodes.length; i++) {
	        	var node = Ext.fly(nodes[i]);
	        	if (node) {
		        	var box = node.down('input').dom;
		        	if (box.checked==true) {
		        		values.push(box.value);
		        	}
		        }
	        }
	        return values;
	    }
	    return this.selectedValues;
    },
	
	clearValues : function() {
		this.view.refresh();
	},
	
	/**
	 * Resets the field to original values (last time store was loaded)
	 */
	reset: function() {
		Ext.form.CheckboxList.superclass.reset.call(this);
		this.clearValues();
	},
	
	/**
	 * This is a very sepcial filter, that I've made as a default.
	 * Starfilter is on by default (meaning when filtering, the store
	 * will ignore asterisk "*" and not filter it out.
	 * This is useful for records that span across all possible filtered keys.
	 */
	filter: function(field, value) {
		var isStarFilter = (this.starFilter===true);
		this.store.filterBy(function (record, id) {
			var val = record.get(field);
			if (isStarFilter==true && val=='*') return true;
			if (value instanceof Array) {
				for (var i=0; i<value.length; i++) {
					if (val==value[i]) return true;
				}
				return false;
			} else {
				return (val==value);
			}
		});
		this.defaultSelect();
	},
	
	clearFilter: function(suppressEvent) {
		this.store.clearFilter(suppressEvent);
	},
	
	/**
	 * This allows you to change between say radio and checkbox on the fly
	 */
	changeInputType: function(inputType) {
		this.inputType = inputType;
		this.generateTemplate();
		this.view.updateTemplate(this.tpl);
	},
	
	/**
	 * To enforce single selections, we change to radio boxes
	 */
	enableSingleSelect: function() {
		this.changeInputType('radio');
	},
	
	/**
	 * To allow multiple selections, we change to check boxes
	 */
	disableSingleSelect: function() {
		this.changeInputType('checkbox');
	},
	
	getValue: function() {
		return this.getSelectedValues();
	},
	
	getRawValue: function() {
		return this.getSelectedValues();
	},
	
	setValue: function(value) {
		if (!value || value.length<1) return;
		var nodes = this.view.getNodes();
		for (var i=0; i<nodes.length; i++) {
			var box = Ext.fly(nodes[i]).down('input').dom;
			box.checked = false;
			for (var j=0; j<value.length; j++) {
				if (box.value==value[j]) box.checked = true;
			}
			
		}
		this.selectedValues = this.getSelectedValues(true);
		this.fireEvent('select', this, box.value, box.checked);
	},
	
	setRawValue: Ext.emptyFn,
	
	/**
     * This is the main validation routine called when the fieldset or form is requesting
     * for validatoin.
     * @return True if valid
     */
    validateValue : function(value){
    	if(value.length < 1){ // if it's blank
			if(this.allowBlank){
				this.clearInvalid();
				return true;
			}else{
				this.markInvalid(this.blankText);
				return false;
			}
        }
        if(typeof this.validator == "function"){
            var msg = this.validator(value);
            if(msg !== true){
                this.markInvalid(msg);
                return false;
            }
        }
        return true;
    }
});

/**
* A SelectBox is a simple <select> element with all the Ext goodies. ComboBox
* was too heavy, and had some UI quirks. So I decided to go native.
*/
Ext.form.SelectBox = function(config){
    Ext.form.SelectBox.superclass.constructor.call(this, config);
    this.addEvents({
    	/**
         * @event select
         * Fires when a list item is selected
	     * @param {Ext.form.CheckboxList} selectlist this Ext.form.CheckboxList
	     * @param {String} the value of the item selected
	     * @param {Boolean} if checkbox/radiobox was checked
	     */
        'select': true
    });
};
Ext.extend(Ext.form.SelectBox, Ext.form.Field,  {

    // private
    defaultAutoCreate: {tag:'select', autocomplete:'off', style:'background-color:#fff !important;'},
    /**
     * @cfg {String} boxLabel The text that appears beside the checkbox
     */
    store: undefined,
	valueField: undefined,
	displayField: undefined,
	defaultField: undefined,
	allowBlank: true,
	blankText: "This field is required",
	validator: undefined,
	starFilter: true,
    /**
     * @cfg {String} inputValue The value that should go into the generated input element's value attribute
     */

    // private
    onRender: function(ct, position){
        Ext.form.SelectBox.superclass.onRender.call(this, ct, position);
		// set the width
		//if (Ext.isIE) this.el.setWidth(this.width+5);
		//else this.el.setWidth(this.width);
		// build the options
		this.refresh();
		// we should rebuild options when store changes
		this.store.on('datachanged', this.refresh, this);
		// when user makes a selection change, we fire onchange event
		this.el.on('change', this.onChange, this);
    },
    
    refresh : function(){
		var records = this.store.getRange();
		var box = this.el.dom;
		box.options.length=0; // clear options
		if (this.emptyText) box.options[0] = new Option(this.emptyText,'');
		if (this.disabled) return; // don't populate options if we're disabled.
		
		for(var i = 0, len = records.length; i < len; i++){
			var record = records[i];
			box.options[box.length] = new Option(record.get(this.displayField),record.get(this.valueField));
		}
    },
    
    initValue: Ext.emptyFn,
    
	getValue: function() {
		return this.el.dom.value;
	},
	
	getRawValue: function() {
		return this.el.dom.value;
	},
	
	setValue: function(value) {
		if (!value) return;
		var box = this.el.dom;
		for (var i=0; i<box.options.length; i++) {
			if (box.options[i].value==value) {
				box.selectedIndex = i;
				this.fireEvent('select', this, this.store.getAt(i), i);
			}
		}
	},
	
	onChange: function() {
		var index = this.el.dom.selectedIndex;
		if (this.emptyText) index--;
		//console.log(this.store.getAt(index));
		this.fireEvent('select', this, this.store.getAt(index), index);
	},
	
	/**
     * This is the main validation routine called when the fieldset or form is requesting
     * for validatoin.
     * @return True if valid
     */
    validateValue : function(value){
    	if(value.length < 1){ // if it's blank
			if(this.allowBlank){
				this.clearInvalid();
				return true;
			}else{
				this.markInvalid(this.blankText);
				return false;
			}
        }
        if(typeof this.validator == "function"){
            var msg = this.validator(value);
            if(msg !== true){
                this.markInvalid(msg);
                return false;
            }
        }
        return true;
    },
	
	/**
	 * This is a very sepcial filter, that I've made as a default.
	 * Starfilter is on by default (meaning when filtering, the store
	 * will ignore asterisk "*" and not filter it out.
	 * This is useful for records that span across all possible filtered keys.
	 */
	filter: function(field, value) {
		var isStarFilter = (this.starFilter===true);
		this.store.filterBy(function (record, id) {
			var val = record.get(field);
			if (isStarFilter==true && val=='*') return true;
			else {
				return (val==value);
			}
		});
		
		// default selection if there's only 1 record
		if (this.store.getCount() == 1) {
			var rec = this.store.getAt(0);
			this.setValue(rec.get(this.valueField));
		}
	},
	
	clearFilter: function(suppressEvent) {
		this.store.clearFilter(suppressEvent);
	}
});

/**
 * The DWRProxy allows us to make stores that are backed by DWR function calls
 * Use with DWRReader.
 */
Ext.data.DWRProxy = function(dwrCall) {
	Ext.data.DWRProxy.superclass.constructor.call(this);
	this.dwrCall = dwrCall;
};
Ext.extend(Ext.data.DWRProxy, Ext.data.DataProxy, {
	/**
	 * The load function is invoked automatically by the store using this proxy.
	 * For example when you call store.load({params:[1,2,3]});
	 */
	load : function(params, reader, callback, scope, arg) {
		if(this.fireEvent("beforeload", this, params) !== false) {
			var delegate = this.loadResponse.createDelegate(this, [reader, callback, scope, arg], 1);
			// this is the arguments passed to the dwr call
			var callParams = new Array();
			if (params.args!==undefined)
				callParams = params.args.slice();
			// this is our callback function to load data
			callParams.push(delegate);
			if (params.dwrCall!==undefined) params.dwrCall.apply(this, callParams);
			else this.dwrCall.apply(this, callParams);
		} else {
			callback.call(scope || this, null, arg, false);
		}
	},

	loadResponse : function(dataList, reader, callback, scope, arg) {
		var result;
		try {
			result = reader.read(dataList);
		} catch(e) {
			this.fireEvent("loadexception", this, null, response, e);
			callback.call(scope, null, arg, false);
			return;
		}
		callback.call(scope, result, arg, true);
	},
	
	update : function(dataSet){},
	
	updateResponse : function(dataSet){}
});

/**
 * This reader is designed to work with DWRProxy, and does not handle nested objects.
 */
Ext.data.DWRReader = function(meta, recordType){
    Ext.data.DWRReader.superclass.constructor.call(this, meta, recordType);
    this.recordType = recordType;
};
Ext.extend(Ext.data.DWRReader, Ext.data.DataReader, {
	read : function(o){
		var recordType = this.recordType;
		var root = o;
		var records = new Array(root.length);
		for(var i = 0; i < root.length; i++){
			records[i] = new recordType(root[i], null);
		}
		return {
			records: records,
			totalRecords: records.length
		};
	}
});

Ext.form.HtmlContainer = function(config){
    Ext.form.HtmlContainer.superclass.constructor.call(this, config);
};
Ext.extend(Ext.form.HtmlContainer, Ext.Component,  {
	domId: undefined,
	onRender: function(ct, position){
		if (this.domId) this.el = Ext.get(this.domId);
		ct.dom.insertBefore(this.el.dom, position);
	}
});

Ext.filterKeys = function(e){
	var k = e.getKey();
	if(!Ext.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
	    return;
	}
	if(Ext.isIE && (k == e.BACKSPACE || k == e.DELETE || e.isNavKeyPress() || k == e.HOME || k == e.END)){
	    return;
	}
	var c = e.getCharCode();
	if(!this.maskRe.test(String.fromCharCode(c) || '')){
	    e.stopEvent();
	}
};
