/**
  * AJAX Request Class w processing & dialog
  *
  * @author  Marc Mignonsin
  * @version 2010-12-16
  *
  */

AjaxRequest = function(panelID, controller, script, method, dataResponseType)
{
	//window.log('AjaxRequest', arguments);
	$('#'+panelID+'.panel').panel('addExternalResource', this, null);
	
	this.reset(); // just in case

	this.setScript(script);
    this.setMethod(method); // GET? POST?
	if (dataResponseType)
    {
        this.setResponseType(dataResponseType); // xml? html? script? jsonp? text?
    }
    else
    {
        this.setResponseType('json');
    }
	
	// display processing message?
	this.processingDialog(false, '');
	
	// display success message? (+text, button label + timeout)
	this.successDialog(false, '', '', 1500);
	
	// display errors in dialog? - short error messages?
	this.errorDialog(false, false);

	//display internal (AJAX) errors in dialog? - short error messages?
	this.internalErrorDialog(false, false);
	
	// display warnings in dialog? - short warning messages?
	this.warningDialog(false, false);
	
	// display info message?
	this.infoDialog(true);
	
	this.config.staticData = {};
	this.config.staticData.panelID = panelID;
	this.config.staticData.tabSessionID = $(controller).panelslider('getTabSessionID');
	this.config.staticData.language = $(controller).panelslider('getLanguageID');

	//window.log(this);

	return this;
};

AjaxRequest.prototype.config = { };
AjaxRequest.prototype.data2Send = { };
AjaxRequest.prototype.files2Upload = [ ];
AjaxRequest.prototype.XMLHttpRequest = null;
AjaxRequest.prototype.successCallback = null;
AjaxRequest.prototype.errorCallback = null;
AjaxRequest.prototype.dialog = null;

AjaxRequest.prototype.reset = function()
{
	//window.log('AjaxRequest.reset', arguments);
	this.config = { };
    this.data2Send = { };
    this.files2Upload = [ ];
	this.XMLHttpRequest = null;
	this.successCallback = null;
	this.errorCallback = null;
	this.dialog = null;
};

AjaxRequest.prototype.destroy = function()
{
	//window.log('AjaxRequest.destroy', arguments);
	if ((typeof this.XMLHttpRequest !== 'undefined') && (this.XMLHttpRequest !== null))
	{
		this.XMLHttpRequest.abort();
		delete this.XMLHttpRequest;
		this.XMLHttpRequest = null;
	}
};

AjaxRequest.prototype.abort = function()
{
	//window.log('AjaxRequest.abort', arguments);
	if (this.XMLHttpRequest)
	{
		this.XMLHttpRequest.abort();
		this.XMLHttpRequest = null;
	}
};

/* *** */

AjaxRequest.prototype.processingDialog = function(trueFalse, processingText)
{
	//window.log('AjaxRequest.processingDialog', arguments);
	this.config.displayProcessingDialog = trueFalse;
	this.config.processingMsg = processingText;
};

AjaxRequest.prototype.successDialog = function(trueFalse, successText, buttonLabel, timeOut)
{
	//window.log('AjaxRequest.successDialog', arguments);
	this.config.displaySuccessDialog = trueFalse;
	this.config.successMsg = successText;
	this.config.successButtonLabel = buttonLabel;
	this.config.successTimeOut = timeOut;
};

AjaxRequest.prototype.infoDialog = function(trueFalse)
{
	//window.log('AjaxRequest.infoDialog', arguments);
	this.config.displayInfoDialog = trueFalse;
};

AjaxRequest.prototype.errorDialog = function(dialogTrueFalse, shortMsgsTrueFalse)
{
	//window.log('AjaxRequest.errorDialog', arguments);
	this.config.displayErrorDialog = dialogTrueFalse;
	this.config.shortErrorMsgs = shortMsgsTrueFalse;
};

AjaxRequest.prototype.warningDialog = function(dialogTrueFalse, shortMsgsTrueFalse)
{
	//window.log('AjaxRequest.warningDialog', arguments);
	this.config.displayWarningDialog = dialogTrueFalse;
	this.config.shortErrorMsgs = shortMsgsTrueFalse;
};

AjaxRequest.prototype.internalErrorDialog = function(dialogTrueFalse, shortMsgsTrueFalse)
{
	//window.log('AjaxRequest.internalErrorDialog', arguments);
	this.config.displayInternalErrorDialog = dialogTrueFalse;
	this.config.shortErrorMsgs = shortMsgsTrueFalse;
};

AjaxRequest.prototype.setScript = function(script)
{
	//window.log('AjaxRequest.setScript', arguments);
	this.config.script = script;
};

AjaxRequest.prototype.setResponseType = function(type)
{
	//window.log('AjaxRequest.setResponseType', arguments);
	this.config.responseDataType = type;
};

AjaxRequest.prototype.setMethod = function(method)
{
	//window.log('AjaxRequest.setMethod', arguments);
	this.config.method = method;
};

AjaxRequest.prototype.setData = function(data)
{
    //window.log('AjaxRequest.setData', arguments);
    if (data) this.data2Send = data;
    //window.log(this.data2Send);
};

AjaxRequest.prototype.addData = function(key, value)
{
    //window.log('AjaxRequest.addData', arguments);
    this.data2Send[key] = value;
    //window.log(this.data2Send);
};

AjaxRequest.prototype.addFile = function(key)
{
    //window.log('AjaxRequest.addFile', arguments);
    if (key) this.files2Upload.push(key);
    //window.log(this.files2Upload);
};

AjaxRequest.prototype.setFiles = function(filesKeys)
{
    //window.log('AjaxRequest.setFiles', arguments);
    if (filesKeys) this.files2Upload = filesKeys;
};

AjaxRequest.prototype.onSuccess = function(callback)
{
	//window.log('AjaxRequest.onSuccess', arguments);
	this.successCallback = callback;
    return this;
};

AjaxRequest.prototype.onError = function(callback)
{
	//window.log('AjaxRequest.onError', arguments);
	this.errorCallback = callback;
    return this;
};

AjaxRequest.prototype.send = function(data)
{
    //window.log('AjaxRequest.send', arguments);
	if ((this.config.script == '') || (this.config.script == null))
	{
		this.notifyApplicationError('Communication failed : script is undefined!');
		return;
	}
	
	if (data)
	{
		this.setData(data);
	}
	
	for (var key in this.config.staticData)
	{
		this.addData(key, this.config.staticData[key]);
	}
	
	// cancel previous request
	this.abort();
	
	this.showProcessingDialog();
	
    //window.log(this.data2Send);
	//window.log(this.files2Upload);
	
   try
   {     
	    if (this.files2Upload.length > 0)
	    {        
	        return this._sendAndUpload();
	    }
	
	    // cosmetics
	    var script = this.config.script;
	    if (this.data2Send.panelURI)
	    {
	    	var c = (script.indexOf('?') == -1) ? '?' : '&';
	    	script += c + 'panelURI=' + this.data2Send.panelURI;
	    }    
    
	    if ((this.config.responseDataType == 'xml') || (this.config.responseDataType == 'html'))
	    {
	        return this._send4XML(script);
	    }
	
		this.XMLHttpRequest = $.ajax({
			type : this.config.method,
			url : script,
			data : this.data2Send,
			dataType : this.config.responseDataType,
	
			success : delegate(this, function(response){
				//window.log(arguments);
				if (!response)
				{
					response = {
						message : 'No response?!',
						status : 'noresponse'
					};
				}
				
				switch (response.status)
				{
					case 'success':
						this.notifySuccess(response);
						break;
						
					case 'info':
						this.notifyInfo(response);
						break;
						
					case 'warning':
						this.notifyWarning(response);
						break;
						
					case 'noresponse':
						break;
						
					default:
						response.errType = 'script';
						response.message = this.formatErrorMessage(response);
	                	this.notifyApplicationError(response);
						break;
				}
	
				//delete this.XMLHttpRequest;
				this.XMLHttpRequest = null;
			}),
	
			error : delegate(this, function (XMLHttpRequest) {  
				window.warn(XMLHttpRequest);
				
				XMLHttpRequest.errType = 'ajax';
				XMLHttpRequest.message = this.formatInternalErrorMessage(XMLHttpRequest);
	            this.notifyInternalError(XMLHttpRequest);
	
	            //delete this.XMLHttpRequest;
				this.XMLHttpRequest = null;
			})
		});
    }
	catch (e)
	{
		window.group('Exception caught executing request!');
		e = { message : e }; // cosmetics to see the whole message in the console
		window.warn(e);
		window.trace();
		window.groupEnd();
		
		this.createDialog('<strong>Application error (request)!</strong>');
		this.dialog.setStatusMessage('<strong>'+e.message+'</strong><br /><br />'+'Check console log for more details.');
		this.dialog.show();
	};

    return false;
};

AjaxRequest.prototype._send4XML = function(script)
{
    //window.log('AjaxRequest.send4XML', arguments);
	this.XMLHttpRequest = $.ajax({
		type : this.config.method,
		url : script,
		data : this.data2Send,
        dataType : this.config.responseDataType,

		success : delegate(this, function(response){
			//window.log(arguments);
			if (!response)
			{
				response = ''; // no response?!
			}
			else
			{
	            // basic error detection
				if ((response.indexOf(' error</b>') == -1) &&	// PHP
						(response.indexOf('Error: ') == -1) && 	// dev : custom
						(response.indexOf('ERROR: ') == -1))	// dev : custom
				{
					this.notifySuccess(response);
				}
				else
				{
					this.notifyApplicationError(response);
				}
			}
			
			//delete this.XMLHttpRequest;
			this.XMLHttpRequest = null;
		}),

		error : delegate(this, function (XMLHttpRequest) {            
			window.warn(XMLHttpRequest);
			
			XMLHttpRequest.errType = 'ajax';
			XMLHttpRequest.message = this.formatInternalErrorMessage(XMLHttpRequest);
            this.notifyInternalError(XMLHttpRequest);

            //delete this.XMLHttpRequest;
			this.XMLHttpRequest = null;
		})
	});

    return false;
};

AjaxRequest.prototype._sendAndUpload = function()
{
    //window.log('AjaxRequest.sendAndUpload', arguments);
    //window.log(this.files2Upload);
    //window.log(this.data2Send);
    
    this.XMLHttpRequest = $.ajaxFileUpload({
        secureuri : false,
        type : this.config.method,
        url : this.config.script,        
        filesIDs : this.files2Upload,
        data : this.data2Send,
        dataType : 'json',

		success : delegate(this, function(response){
			//window.log(arguments);
			if (!response)
			{
				response = {
					message : 'No response?!',
					status : 'noresponse'
				};
			}
			
			switch (response.status)
			{
				case 'success':
					this.notifySuccess(response);
					break;
					
				case 'info':
					this.notifyInfo(response);
					break;
					
				case 'warning':
					this.notifyWarning(response);
					break;
					
				case 'noresponse':
					break;
					
				default:
					response.errType = 'script';
					response.message = this.formatErrorMessage(response);
                	this.notifyApplicationError(response);
					break;
			}

			//delete this.XMLHttpRequest;
			this.XMLHttpRequest = null;
		}),

		error : delegate(this, function (XMLHttpRequest) {
			//window.warn(XMLHttpRequest);
			
			XMLHttpRequest.errType = 'ajax';
			XMLHttpRequest.message = this.formatInternalErrorMessage(XMLHttpRequest);
            this.notifyInternalError(XMLHttpRequest);

            //delete this.XMLHttpRequest;
			this.XMLHttpRequest = null;
		})
	});

    return false;
};

AjaxRequest.prototype.formatErrorMessage = function(response)
{
	//window.log('AjaxRequest.formatErrorMessage', arguments);
	var errorMsg = '';

	if (this.config.shortErrorMsgs == true)
	{
		errorMsg = '<span class="text-error">Application error!</span>';
	}
	else
	{
		errorMsg = 'An unexpected application error occured!';
		errorMsg += '<br /><br /><strong>'+response.message+'</strong><br />';
		errorMsg += "<br />Please try again.";

	}

	return errorMsg;
};

AjaxRequest.prototype.formatInternalErrorMessage = function(XMLHttpRequest)
{
	//window.log('AjaxRequest.formatInternalErrorMessage', arguments);
	var errorMsg = '';

	if (this.config.shortErrorMsgs == true)
	{
		if (XMLHttpRequest.status == 0)
		{
			errorMsg = '<span class="text-error">AJAX error (no connection)!</span>';
		}
		else if (XMLHttpRequest.status == 200) // OK
        {
            errorMsg = '<span class="text-error">PHP error!</span>';
        }
        else
		{
			errorMsg = '<span class="text-error">AJAX error ('+XMLHttpRequest.status+')!</span>';
		}
	}
	else
	{
		if (XMLHttpRequest.status == 0)
		{
			errorMsg = 'AJAX error : no connection!';
			errorMsg += '<br/>Your connection was reset, please try again.';
		}
		else if (XMLHttpRequest.status == 200) // OK
        {
            errorMsg = 'PHP error :<br />'+XMLHttpRequest.responseText+'<br /><br />('+this.config.script+')';
        }
		else
		{
			errorMsg = 'AJAX error : '+XMLHttpRequest.statusText+' ('+XMLHttpRequest.status+')!<br /><br />('+this.config.script+')';
		}
	}

	return errorMsg;
};

//TODO : remove and change NotificationDialog which should not remove the dialogs elements from DOM when destroyed => reusable
AjaxRequest.prototype.createDialog = function(title) 
{
	//window.log('AjaxRequest.createDialog', arguments);
	// dialog is removed from DOM when NotificationDialog is closed, so we have to delete the object and recreate it... (no comment)
	if (this.dialog)
	{
		this.dialog.hide();
		delete this.dialog;
		this.dialog = null
	}
	this.dialog = new NotificationDialog('');
	this.dialog.setTitle(title);
};

AjaxRequest.prototype.showProcessingDialog = function()
{
	//window.log('AjaxRequest.showProcessingDialog', arguments);
	if (this.config.displayProcessingDialog == true)
	{
		// dialog is removed from DOM when NotificationDialog is closed
		this.createDialog('Operation in progress');
		this.dialog.setProcessingMessage(this.config.processingMsg);
		this.dialog.show();
	}
};

AjaxRequest.prototype.notifySuccess = function(response)
{
	//window.log('AjaxRequest.notifySuccess', arguments);
	if (this.config.displaySuccessDialog == true)
	{
		var msg = (this.config.successMsg) ? this.config.successMsg : response.message;
		
		// dialog is removed from DOM when NotificationDialog is closed
		this.createDialog('<strong>Operation successful!</strong>');
		this.dialog.setStatusMessage(msg, this.config.successButtonLabel);
		this.dialog.show(this.config.successTimeOut);
	}
	else
	{
		if ((this.config.displayProcessingDialog == true) && (this.dialog))
		{
			this.dialog.hide();
		}
	}
	
	// user callback
	if (this.successCallback)
	{
		try
		{
			this.successCallback(response);
		}
		catch (e)
		{
			window.group('Exception caught executing request callback!');
			e = { message : e }; // cosmetics to see the whole message in the console
			window.warn(e);
			window.trace();
			window.groupEnd();
			
			this.createDialog('<strong>Application error (callback)!</strong>');
			this.dialog.setStatusMessage('<strong>'+e.message+'</strong><br /><br />'+'Check console log for more details.');
			this.dialog.show();
		};
	}
};

AjaxRequest.prototype.notifyInfo = function(response)
{
	//window.log('AjaxRequest.notifyInfo', arguments);
	if (this.config.displayInfoDialog == true)
	{
		var msg = 'The operation has been successfully executed. The following information has been received: ';
		msg += '<br /><br /><strong>'+response.message+'</strong>';
		
		// dialog is removed from DOM when NotificationDialog is closed
		this.createDialog('<strong>Operation info</strong>');
		this.dialog.setStatusMessage(msg, 'Close');
		this.dialog.show();
	}
	else
	{
		if ((this.config.displayProcessingDialog == true) && (this.dialog))
		{
			this.dialog.hide();
		}
	}
	
	// user callback
	if (this.successCallback)
	{
		try
		{
			this.successCallback(response);
		}
		catch (e)
		{
			window.group('Exception caught executing request callback!');
			e = { message : e }; // cosmetics to see the whole message in the console
			window.warn(e);
			window.trace();
			window.groupEnd();
			
			this.createDialog('<strong>Application error (callback)!</strong>');
			this.dialog.setStatusMessage('<strong>'+e.message+'</strong><br /><br />'+'Check console log for more details.');
			this.dialog.show();
		};
	}
};

AjaxRequest.prototype.notifyWarning = function(response)
{
	//window.log('AjaxRequest.notifyWarning', arguments);
	if (typeof response === 'string')
	{
		var msg = response;
		response = { message : msg };
	}
	
	window.group('Application warning!');
	window.warn(response.message);
	window.log(response);
	window.groupEnd();
	
	if (this.config.displayWarningDialog == true)
	{		
		// dialog is removed from DOM when NotificationDialog is closed
		this.createDialog('<strong>Application warning!</strong>');
		this.dialog.setStatusMessage(response.message, 'Close');
		this.dialog.show();
	}
	else
	{
		if ((this.config.displayProcessingDialog == true) && (this.dialog))
		{
			this.dialog.hide();
		}
	}
	
	// user callback
	if (this.errorCallback)
	{
		try
		{
			this.errorCallback(response);
		}
		catch (e)
		{
			window.group('Exception caught executing request error callback!');
			e = { message : e }; // cosmetics to see the whole message in the console
			window.warn(e);
			window.trace();
			window.groupEnd();
			
			this.createDialog('<strong>Application error (error callback)!</strong>');
			this.dialog.setStatusMessage('<strong>'+e.message+'</strong><br /><br />'+'Check console log for more details.');
			this.dialog.show();
		};
	}
};

AjaxRequest.prototype.notifyApplicationError = function(response)
{
	//window.log('AjaxRequest.notifyApplicationError', arguments);
	if (typeof response === 'string')
	{
		var msg = response;
		response = { message : msg };
	}
	
	window.group('Application error!');
	window.warn(response.message);
	window.log(response);
	window.groupEnd();
	
	if (this.config.displayErrorDialog == true)
	{		
		// dialog is removed from DOM when NotificationDialog is closed
		this.createDialog('<strong>Application error!</strong>');
		this.dialog.setStatusMessage(response.message, 'Close');
		this.dialog.show();
	}
	else
	{
		if ((this.config.displayProcessingDialog == true) && (this.dialog))
		{
			this.dialog.hide();
		}
	}
	
	// user callback
	if (this.errorCallback)
	{
		try
		{
			this.errorCallback(response);
		}
		catch (e)
		{
			window.group('Exception caught executing request error callback!');
			e = { message : e }; // cosmetics to see the whole message in the console
			window.warn(e);
			window.trace();
			window.groupEnd();
			
			this.createDialog('<strong>Application error (error callback)!</strong>');
			this.dialog.setStatusMessage('<strong>'+e.message+'</strong><br /><br />'+'Check console log for more details.');
			this.dialog.show();
		};
	}
};

AjaxRequest.prototype.notifyInternalError = function(XMLHttpRequest)
{
	//window.log('AjaxRequest.notifyInternalError', arguments);
	if (this.config.displayInternalErrorDialog == true)
	{
		// dialog is removed from DOM when NotificationDialog is closed
		this.createDialog('<strong>Server error!</strong>');
		this.dialog.setStatusMessage(XMLHttpRequest.message, 'Close');
		this.dialog.show();
	}
	else
	{
		if ((this.config.displayProcessingDialog == true) && (this.dialog))
		{
			this.dialog.hide();
		}
	}
	
	// user callback
	if (this.errorCallback)
	{	
		try
		{
			this.errorCallback(XMLHttpRequest);
		}
		catch (e)
		{
			window.group('Exception caught executing request error callback!');
			e = { message : e }; // cosmetics to see the whole message in the console
			window.warn(e);
			window.trace();
			window.groupEnd();
			
			this.createDialog('<strong>Application error (internal callback)!</strong>');
			this.dialog.setStatusMessage('<strong>'+e.message+'</strong><br /><br />'+'Check console log for more details.');
			this.dialog.show();
		};
	}
};