pcwa.core.scope('pcwa.ext.model');
pcwa.ext.model.UpdateMgr = {
	currReqCount: 0,
	waitMsg: function waitMsg(){
		if ( this.currReqCount == 0 ){
			if ( Ext.Msg.isVisible() ){
				Ext.Msg.hide();
			}
		}else{
			if ( this.currReqCount == 1 && !Ext.Msg.isVisible() ){
		    	Ext.Msg.wait("", "Saving Changes");
			}
			Ext.Msg.updateText(this.currReqCount + (this.currReqCount == 1?" record ":" records ") + "updating, please wait");
		}
	},
	isDirty: function isDirty() {
		var retval = false;
		var storeCount = Ext.StoreMgr.getCount();
		for ( var idx = 0; idx < storeCount; idx++ ){
			if ( Ext.StoreMgr.get(idx).getModifiedRecords().length > 0 ) {
				retval = true;
				break;
			}
		}
		return retval;
	},
	queryUnload: function queryUnload() {
		// This function is an event handler for the window object,
		// therefore, when it is executed, the this keyword refers to window
		if ( dataUpdateManager.isDirty() ) {
			var message = 'You have pending changes that need to be saved. ' +
						  'To discard your changes and continue, press OK. ' +
						  'To save your changes, press Cancel and then save your changes.';
			event.returnValue = message;
		}
	},
	updateRecord: function updateRecord(o){
		/***
		 * 
		 * record:			The Ext.data.Record to update (required)
		 * reset:			A boolean that specifies whether or not to call commitChanges()
		 *					on the parent store upon a successful update.
		 * callback:		The callback to notify when the update is complete.
		 * params:			A parameters object to pass to the callback.
		 * scope:			The context for the callback.
		 * 					If no eTag is present the request is handled as a CREATE operation,
		 *					otherwise it is handled as an UPDATE.
		 */
		if ( !o.record ){ return;}
		
		try{
			if ( typeof o.reset != 'boolean' ){
				o.reset = true;
			}
		}catch(e){
			o.reset = true;
		}

		if ( typeof o.callback == 'function' ){
			if ( !o.params || typeof o.params != "object" ){
				o.params = {};
			}
			if ( !o.scope ){
				o.scope = window;
			}
		}
		
		var url = o.record.store.proxy.conn.url;
		var json = '{' + o.record.store.root + ':[' + Ext.util.JSON.encode(o.record.data) + ']}';
		
		var etagField = o.record.store.reader.meta.etagField;
		if ( etagField.length == 0 ){
			throw ('Unable to update without a defined etagField');
		}
		var etag = o.record.get(etagField);
		var method;
		var headers = {'accept':'application/json',
					   'content-type':'application/json',
					   'content-length':json.length};
		if ( etag ){
			headers['if-match'] = etag;
			method = 'PUT';
			if ( url.substr(url.lastIndexOf('/') + 1) != o.record.get(o.record.store.id) ){
				url += '/' + o.record.get(o.record.store.id);
			}
		} else {
			method = 'POST';
		}
		o.__updateType = 'update';
		
		this.currReqCount++;
		this.waitMsg();
		
		var rr = new pcwa.ext.ajax.RestRequester({
				'headers':headers,
				'method':method,
				'url':url,
				'callback':this.processUpdateResult,
				'callbackParams':o,
				'scope':this,
				'entity':json
				});
				
		rr.sendRequest();

	},	
	processUpdateResult: function processUpdateResult(b, Xhr, o){
		var updateErrors = [[]];
		
		if ( !b ){
			updateErrors = this.buildErrors(Xhr, o.record.store.storeId);
		}else{
			if ( o.__updateType == 'update' ){
				eval('var jsonObj = ' + Xhr.responseText);
				for ( var e in jsonObj[o.record.store.root][0]){
					o.record.set(e, (jsonObj[o.record.store.root][0])[e]);
				}
				if ( o.record.store.id.length > 0 ){
					o.record.id = o.record.get(o.record.store.id);
				}
			}
			if ( o.reset ){
				o.record.store.commitChanges();
			}
		}
		this.currReqCount--;
		this.waitMsg();
		if ( o.callback && typeof o.callback == 'function' ){
			o.callback.call(o.scope, b, Xhr, o.params, updateErrors);
		}
	},	
	deleteRecord: function deleteRecord(o){
		/***
		 * record:			The Ext.data.Record to delete (required)
		 * reset:			A boolean that specifies whether or not to call commitChanges()
		 *					on the parent store upon a successful update.
		 * callback:		The callback to notify when the update is complete.
		 * params:			A parameters object to pass to the callback.
		 * scope:			The context for the callback.
		 */
		if ( !o.record ){ return;}
	
		try{
			if ( typeof o.reset != 'boolean' ){
				o.reset = true;
			}
		}catch(e){
			o.reset = true;
		}

		if ( typeof o.callback == 'function' ){
			if ( !o.params || typeof o.params != "object" ){
				o.params = {};
			}
			if ( !o.scope ){
				o.scope = window;
			}
		}
		
		var url = o.record.store.proxy.conn.url;
		if ( url.substr(url.lastIndexOf('/') + 1) != o.record.get(o.record.store.id) ){
			url += '/' + o.record.get(o.record.store.id);
		}

		var etagField = o.record.store.reader.meta.etagField;
		if ( etagField.length == 0 ){
			throw ('Unable to update without a defined etagField');
		}		
		var etag = o.record.get(etagField);
		if ( etagField.length == 0 ){
			throw ('Unable to update without a defined etag');
		}
		var headers = {
			'if-match':	etag,
			'accept':	'application/json'
		}

		this.currReqCount++;
		this.waitMsg();
		
		o.__updateType = 'delete';
		var rr = new pcwa.ext.ajax.RestRequester({
				'headers':headers,
				'method':'DELETE',
				'url':url,
				'callback':this.processUpdateResult,
				'callbackParams':o,
				'scope':this
				});
				
		rr.sendRequest();

	},
	commitChanges: function commitChanges() {
		var storeCount = Ext.StoreMgr.getCount();
		for ( var idx = 0; idx < storeCount; idx++ ){
			if ( Ext.StoreMgr.get(idx).getModifiedRecords().length > 0 ) {
				Ext.StoreMgr.get(idx).commitChanges();
			}
		}
	},
	buildErrors: function buildErrors(xhr, sid){
		var errors = [[]];
		var cType = '';
		
		errors[0][0] = xhr.status;
		errors[0][1] = xhr.statusText;
		errors[0][2] = sid || '';
		
		try {
			if ( xhr.getResponseHeader ) {
				if ( typeof xhr.getResponseHeader == 'function' ){
					cType = xhr.getResponseHeader('Content-Type');
				}else{
					cType = xhr.getResponseHeader['content-type'];
				}
			}
		}
		catch(e) {}
		
		if ((cType == "" || !cType) && xhr.responseText.charAt(0) == "{")
			cType = 'application/json';
		
		if ( cType == 'application/json' ){
			eval('var jsonObj = ' + xhr.responseText);
			
			var i = 2;
			for ( var e in jsonObj.databaseerror){
				errors[0][++i] = typeof jsonObj.databaseerror[e] == 'undefined' ? '' : jsonObj.databaseerror[e];
			}
		}else{
			errors[0][3] = "htmlResponse";
			errors[0][6] = xhr.responseText ? xhr.responseText : xhr.statusText;
		}
		
		return errors;
	},
	showErrors: function(errors, animateTarget){
		var errWin = new pcwa.ext.model.UpdateErrorWindow({
			errors:			errors,
			animateTarget:	animateTarget
		});
		errWin.show();
	}
};
var dataUpdateManager = pcwa.ext.model.UpdateMgr;


pcwa.ext.model.UpdateErrorHtmlPanel = function( config )
{
	var config = config || {};
	
	Ext.applyIf( config, {
		frame: true,
		bodyStyle: 'padding:5px 5px 0',
		autoScroll: true
	});
	
	pcwa.ext.model.UpdateErrorHtmlPanel.superclass.constructor.call( this, config );
}
Ext.extend( pcwa.ext.model.UpdateErrorHtmlPanel, Ext.Panel );

pcwa.ext.model.UpdateErrorFormPanel = function( config )
{
	var config = config || {};
	
	Ext.applyIf( config, {
		labelAlign: 'top',
		frame: true,
		bodyStyle: 'padding: 5px 5px 0',
		width: 600,
        items: [{
            layout:'column',
            items:[{
                columnWidth:.15,
                layout: 'form',
                items: [{
                    xtype:'textfield',
					readOnly: true,
				    fieldLabel: 'Error Code',
					name: 'errorcode',
                    anchor:'95%'
                }]
            },{
                columnWidth:.15,
                layout: 'form',
                items: [{
                    xtype:'textfield',
					readOnly: true,
	                fieldLabel: 'Native Error',
					name: 'nativeerrorcode',
                    anchor:'95%'
                }]
            },{
                columnWidth:.7,
                layout: 'form',
                items: [{
                    xtype:'textfield',
					readOnly: true,
	                fieldLabel: 'Message',
					name: 'message',
                    anchor:'100%'
                }]
            }]
        },{
            xtype:'textarea',
			readOnly: true,
	        fieldLabel: 'Detail',
			name: 'detail',
            anchor:'100%'
        },{
            layout:'column',
            items:[{
                columnWidth:.15,
                layout: 'form',
                items: [{
		            xtype:'textfield',
					readOnly: true,
			        fieldLabel: 'SQL State',
					name: 'sqlstate',
		            anchor:'95%'
                }]
            },{
                columnWidth:.85,
                layout: 'form',
                items: [{
		            xtype:'textarea',
					readOnly: true,
		            fieldLabel: 'SQL Statement',
					name: 'sqlstatement',
		            anchor:'100%'
                }]
            }]
        }]

	});
	
	pcwa.ext.model.UpdateErrorFormPanel.superclass.constructor.call( this, config );
}
Ext.extend( pcwa.ext.model.UpdateErrorFormPanel, Ext.FormPanel );

pcwa.ext.model.UpdateErrorWindow = function UpdateErrorWindow(config)
{	
	this.win = null;
	this.store = null;
	this.panel = null;
	this.htmlResponse = false;
	this.title = 'An error occurred while attempting to perform an update';
	
	if ( !config ){ config = {};}
	if ( !config.errors ){ config.errors = [];}
	Ext.apply(this, config);
};
pcwa.ext.model.UpdateErrorWindow.prototype = {
	UPDATE_ERR_FIELDS: [
	   {name: 'status'},
	   {name: 'statusText'},
	   {name: 'store'},
	   {name: 'errorcode'},
	   {name: 'nativeerrorcode'},
	   {name: 'message'},
	   {name: 'detail'},
	   {name: 'sqlstate'},
	   {name: 'sqlstatement'}
	],
	
	createWindow: function createWindow(){
		if ( this.win ){ delete this.win;}
		
	    var reader = new Ext.data.ArrayReader({}, this.UPDATE_ERR_FIELDS);

        this.store = new Ext.data.Store({
            reader: reader,
            data: this.errors
        });
        
        this.htmlResponse = this.store.getAt(0).get('errorcode') == 'htmlResponse'; 
        if ( this.htmlResponse ){
        	this.panel = new pcwa.ext.model.UpdateErrorHtmlPanel({
		        title: this.title,
		        html: this.store.getAt(0).get('detail')
        	});
        }else{
			this.panel = new pcwa.ext.model.UpdateErrorFormPanel({
		        title: this.title
			});
        }
        
        this.win = new Ext.Window( this.getWindowCfg() );
	},
	
	close: function() 
	{
		if( this.win ) this.win.close();
	},
	
	getWindowCfg: function()
	{
		return {
			title: 'Update Error',
			layout:'fit',
			width: this.htmlResponse ? 800: 600,
			height: this.htmlResponse ? 500: 340,
			plain: true,
			modal: true,
			shadow: true,
			resizable: this.htmlResponse,
			items: this.panel,
			buttons: [
				{
					text: 'Close',
					handler: function(){
						this.close();
					},
					scope: this
				}
			]
		};
	},
	
	postInit: function postInit(){
		if ( this.store ){
			var record = this.store.getAt(0);
			if ( record && this.panel && !this.htmlResponse ){
				this.panel.getForm().loadRecord(record);
			}
		}
	},
	
	// PUBLIC
	show: function show(animateTarget){
		if ( !this.win ){ this.createWindow();}
		this.win.show(animateTarget, this.postInit, this);
	}
};

