// ----------------------------------------------
// PRAjax - JavaScript code
// (C) Maarten Balliauw
// http://prajax.sf.net
// Version: PRAjax v$PRAJAXVER$
// ----------------------------------------------
var PRAjax = new ( function () {
	// Used as a boundary for client-side script in server-side response
	this.strClientStart = '****startclientside****';
	this.strClientStop = '****endclientside****';
	
	// PRAjax script URI
	this.strUri = '';

	// Show busy message?
	this.blnShowBusyMessage = false;

	// Busy message
	this.strBusyMessage = '';

	// DOM element to display status in
	this.strStatusElement = '';
	this.objStatusElement = null;

	// Hidden IFRAME reference for IE overlay bug
	this.ifrOverlay = null;

	// Show wait cursor?
	this.blnShowWaitCursor = false;
	
	// Open calls (for status)
	this.iOpenCallCount = 0;

	// Initialize
	this.Initialize = function () {
		// Do initialisations
		PRAjax.blnShowBusyMessage = false;
		PRAjax.strStatusElement = '';
		PRAjax.objStatusElement = null;
		
		// Attach listeners to cleanup PRAjax
		PRAjaxUtil.addEvent(window, 'unload', PRAjaxUtil.deleteAllEvents, false);
	}
	
	// Transfer object factory
	this.CreateTransfer = function () {
		return new PRAjaxTransport();
	}
	
	// Execute request
	this.ExecuteRequest = function (uri, post_data, callbackFunction) {
		PRAjax.Busy(1);
		
		var objTransport = this.CreateTransfer();
		objTransport.PerformRequest(uri, post_data, function (data) { PRAjax.ReceiveData(callbackFunction, data); }, function () { PRAjax.Busy(2); }, this.iOpenCallCount++ );
	}
	
	// Create a call
	this.Call = function (func_name, args, obj) {
		// Helper variables
		var i = 0;
		var cnt = 0;
		var aArgs = new Array();
		
		// Copy args array to Array
		cnt = args.length;
		for (i = 0; i < cnt; i++) {
			aArgs.push(args[i]);
		}
		
		// URI to post to
		var uri = PRAjax.strUri;

		// Set options if they are given
		if (aArgs.length > 0) {
			if (typeof(aArgs[aArgs.length - 1]) == 'string' && aArgs[aArgs.length - 1].indexOf('setPRAjax') > -1) {
				// Pop off the options...
				var aOptions = aArgs.pop().split(';');
				
				// Set options
				cnt = aOptions.length;
				var keyValue = null;
				for (i = 0; i < cnt; i++) {
					keyValue = aOptions[i].split(':');
					
					switch (keyValue[0].toLowerCase()) {
						case 'setprajaxtarget':
							uri = keyValue[1];
							break;
					}
				}
			}
		}

		// Callback function
		var callbackFunction = PRAjax.Nothing;
		if (typeof(aArgs[aArgs.length - 1]) == 'function') {
			callbackFunction = aArgs.pop();
		}
			
		// Data for the post action
		var post_data;

		// Add function name to call
		post_data = "rs=" + encodeURIComponent(func_name);
	
		// Add arguments data
		cnt = aArgs.length;
		for (i = 0; i < cnt; i++) {
			post_data = post_data + "&rsargs[" + i + "]=" + encodeURIComponent(PRAjax.ConvertValue(aArgs[i]));
		}
		
		// Add object data?
		if (obj) {
			post_data = post_data + "&rsobj=" + encodeURIComponent(PRAjax.ConvertValue(obj));
		}
		
		// Add a random value for caching issues...
		post_data = post_data + "&random=" + encodeURIComponent(Math.floor(Math.random()*9999999));

		// Execute request
		PRAjax.ExecuteRequest(uri, post_data, callbackFunction);
	}

	// Receive data
	this.ReceiveData = function (func_name, data) {
		if (data.indexOf("[PRAjax]") != -1) {
			// Messages having [PRAjax] in the return value don't mean any good...
			// They are used for sending error messages from server to client.
			PRAjax.Busy(2);
			alert(data);
		} else {
			// Clean the data...
			if (data != null) {
				if (data.indexOf(PRAjax.strClientStart) > -1) {
					data = data.substr(0, data.length - 4);	// It seems '' is always at the end of the string when client script is present...
				}
			}
			
			// First, check if a JS command is given from server to client. If so, execute it.
			if (data != null && data.indexOf(PRAjax.strClientStart) > -1) {
				// It is possible that multiple scripts are present... Execute them one by one.
				var tmpStart = 0;
				var tmpStop = 0;
				var clientScript = '';
				while (data.indexOf(PRAjax.strClientStart) > -1) {
					// Split out the client script
					tmpStart = data.indexOf(PRAjax.strClientStart) + PRAjax.strClientStart.length;
					tmpStop	= data.indexOf(PRAjax.strClientStop);
					
					// Get the client script
					clientScript = data.substr(tmpStart, tmpStop - tmpStart);
					
					// Remove the client script from data
					data = data.replace(PRAjax.strClientStart, '');
					data = data.replace(clientScript, '');
					data = data.replace(PRAjax.strClientStop, '');
					
					// Add a ; in case someone forgot...
					clientScript = clientScript + ';';

					// Execute the client script
					PRAjax.ExecuteScript(clientScript);
				}				
			}
			
			// Second, return data to the client callback script
			if (func_name == null) {
				if (data != null) {
					eval(PRAjaxUtil.stripSlashes(data));
				}
			} else if (typeof(func_name) == "function") {
				func_name(PRAjaxUtil.stripSlashes(data).parseJSON());
			}
			
			// Stop being busy...
			this.iOpenCallCount--;
			PRAjax.Busy(0);
		}
	}
	
	// Execute a JavaScript script
	this.ExecuteScript = function (pScript) {
		eval(pScript);
	}
	
	// Add a JavaScript script
	this.AddScript = function (pScript) {
		// Find HTML "head" tag
		var elemHead = document.getElementsByTagName("head").item(0);
		
		// Create script tag
		var elemScript = document.createElement("script");
		
		// Add script object attributes
		elemScript.setAttribute("type", "text/javascript");
		elemScript.setAttribute("src", pScript);
		
		// Add the script tag to the document
		elemHead.appendChild(elemScript);
	}

	// Create iframe overlay
	this.CreateIframeOverlay = function() {
		if (PRAjax.ifrOverlay == null) {
			PRAjax.ifrOverlay = document.createElement('iframe');
			PRAjax.ifrOverlay.id = 'prajax_iframe_overlay';
			PRAjax.ifrOverlay.style.display = 'none';
			PRAjax.ifrOverlay.style.position = 'absolute';
			document.body.appendChild(PRAjax.ifrOverlay);
		}
	}

	// Place iframe overlay
	this.PlaceIframeOverlay = function () {
		PRAjax.objStatusElement = document.getElementById(PRAjax.strStatusElement);
		
		var zIndex = PRAjax.objStatusElement.style.zIndex;
		if (zIndex == 0) {
			zIndex = 99999;
			PRAjax.objStatusElement.style.zIndex = zIndex;
		}

		PRAjax.ifrOverlay.style.left 	= PRAjax.GetLeft(PRAjax.strStatusElement);
		PRAjax.ifrOverlay.style.top 	= PRAjax.GetTop(PRAjax.strStatusElement);
		PRAjax.ifrOverlay.style.width 	= PRAjax.objStatusElement.offsetWidth;
		PRAjax.ifrOverlay.style.height 	= PRAjax.objStatusElement.offsetHeight;
		PRAjax.ifrOverlay.style.zIndex 	= zIndex - 1;
	}

	// Get left coordinate of a DOM element
	this.GetLeft = function (pElementId) {
		var nodeCurrent = document.getElementById(pElementId);
		var x = 0;

		do {
			x += nodeCurrent.offsetLeft;
			if (nodeCurrent.offsetParent != null) {
				nodeCurrent = nodeCurrent.offsetParent;
			} else {
				break;
			}
		} while (nodeCurrent.tagName.toLowerCase() != 'body');

		return x;
	}

	// Get top coordinate of a DOM element
	this.GetTop = function (pElementId) {
		var nodeCurrent = document.getElementById(pElementId);
		var y = 0;

		do {
			y += nodeCurrent.offsetTop;
			if (nodeCurrent.offsetParent != null) {
				nodeCurrent = nodeCurrent.offsetParent;
			} else {
				break;
			}
		} while (nodeCurrent.tagName.toLowerCase() != 'body');

		return y;
	}

	// Busy DOM element
	this.Busy = function (pStatus) {
		// Keep status busy if calls are still open
		if (PRAjax.iOpenCallCount > 0) {
			pStatus = 1;
		}

		if (PRAjax.blnShowBusyMessage) {
			// Get PRAjax statu element
			PRAjax.objStatusElement = document.getElementById(PRAjax.strStatusElement);
			
			// If not yet present, create a hidden iframe to allow overlaying of the busy message on certain elements
			if (PRAjax.ifrOverlay == null) {
				PRAjax.CreateIframeOverlay();
			}

			// Place the hidden iframe on the right position
			PRAjax.PlaceIframeOverlay();

			// Show or hide busy message
			if (pStatus == 1) {
				PRAjax.ifrOverlay.style.display = 'block';
				PRAjax.objStatusElement.style.display = 'block';
				PRAjax.objStatusElement.innerHTML = PRAjax.strBusyMessage;
			} else {
				PRAjax.ifrOverlay.style.display = 'none';
				PRAjax.objStatusElement.style.display = 'none';
			}
		}

		if (PRAjax.blnShowWaitCursor) {
			// Show or hide wait cursor
			if (pStatus == 1) {
				document.body.style.cursor = 'wait';
			} else {
				document.body.style.cursor = 'default';
			}
		}
	}

	// Convert value
	this.ConvertValue = function (pValue) {
		if (pValue == "") {
			return "";
		}
		
		// Encode using JSON
		return pValue.toJSONString();
	}
	
	// Void function
	this.Nothing = function (data) { }
} ) ();
