//2010-04-30
//Written by Ran Zafrir
//
//
//
//This file, unlike "general.js" consists of functions that are application specific,
//but within the context of the application, they can be considered "generic".
//
//For example - a function that is dependent only on JQuery should go in this file ( and not in "general.js" ! )



/**
 *
 * <p>Written by Ran Zafrir.</p>
 * <p>
 *	Simplifies the use of AJAX<br />
 * </p>
 *
 *
 *
 * @requires JQuery
 *
 * @author Ran Zafrir
 *
 */
var AjaxHelpers =
{
	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	This function sends data to the server via AJAX.<br />
	 *	What's unique about this function is that it takes care of any possible scenario including when network problems prevent the client from connecting to the server.<br />
	 * </p>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>data</li>
	 *		<li>url</li>
	 *		<li>type</li>
	 *		<li>serverFunction</li>
	 *		<li>onValid</li>
	 *		<li>onExplicitlyInvalid</li>
	 *		<li>onImplicitlyInvalid</li>
	 *		<li>onError</li>
	 *		<li>onEmpty</li>
	 *		<li>onNonEmpty</li>
	 *		<li>onComplete</li>
	 *		<li>onNonErrorNonEmpty</li>
	 *		<li>retry</li>
	 *		<li>retryDelay</li>
	 *		<li>decodeFunction</li>
	 *		<li>validateResponse</li>
	 *		<li>validResponseIndicator</li>
	 *		<li>invalidResponseIndicator</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>data</strong> -<br />
	 *			Required.<br />
	 *			Data to be sent to the server.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>url</strong> -<br />
	 *			Required.<br />
	 *			The URL of the request.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>type</strong> -<br />
	 *			Optional.<br />
	 *			Request type ( "get" or "post" ).<br />
	 *			"post" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>serverFunction</strong> -<br />
	 *			Optional.<br />
	 *			This is useful if you concentrate all of your AJAX handling in 1 file.<br />
	 *			That way you can use this parameter to specify the server-function ( within that file ) to handle the request.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onValid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run upon a valid response from the server.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onExplicitlyInvalid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if the server returns an explicitly invalid response.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onImplicitlyInvalid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if the server returns an implicitly invalid response.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onError</strong> -<br />
	 *			function(XMLHttpRequest, textStatus, errorThrown)<br />
	 *			Optional.<br />
	 *			A function to be called if the request fails. The function is passed three arguments: The XMLHttpRequest object, a string describing the type of error that occurred and an optional exception object, if one occurred. Possible values for the second argument (besides null) are "timeout", "error", "notmodified" and "parsererror".<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onEmpty</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if an empty response is received ( could be the result of failing to reach the server ).<br />
	 *			By default, this will be a function that waits 2 seconds and tries sending the request again.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onNonEmpty</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if a non-empty response is received<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onComplete</strong> -<br />
	 *			function(XMLHttpRequest, textStatus)<br />
	 *			Optional.<br />
	 *			A function to be called when the request finishes (after success and error callbacks are executed). The function gets passed two arguments: The XMLHttpRequest object and a string describing the status of the request.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onNonErrorNonEmpty</strong> -<br />
	 *			function<br />
	 *			Optional.<br />
	 *			A function to be called when the response is not empty and not a server-error<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>retry</strong> -<br />
	 *			Boolean<br />
	 *			Optional.<br />
	 *			A boolean specifying whether to keep retrying when an empty response is received.<br />
	 *			TRUE by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>retryDelay</strong> -<br />
	 *			Integer<br />
	 *			Optional.<br />
	 *			Specifies the number of milliseconds to wait between retry attempts.<br />
	 *			2000 by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>decodeFunction</strong> -<br />
	 *			function<br />
	 *			Optional.<br />
	 *			A function to pass the returned data through.<br />
	 *			For example - Base64.decode can go here.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validateResponse</strong> -<br />
	 *			boolean<br />
	 *			Optional.<br />
	 *			A boolean indicating whether the server's response should be passed through AjaxHelpers.validateResponse().<br />
	 *			<i>onExplicitlyInvalid</i> and <i>onImplicitlyInvalid</i> will be ignored if this is set to FALSE.<br />
	 *			TRUE by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validResponseIndicator</strong> -<br />
	 *			string<br />
	 *			Optional.<br />
	 *			A string the server should add to the beginning of the response in order to indicate "success".<br />
	 *			"1" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>invalidResponseIndicator</strong> -<br />
	 *			string<br />
	 *			Optional.<br />
	 *			A string the server should add to the beginning of the response in order to indicate "failure".<br />
	 *			"0" by default.<br />
	 *			<br />
	 *		</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * @return Void
	 * @requires JQuery
	 *
	 * @author Ran Zafrir
	 *
	 */
	sendRequest: function(origSettings)
	{
		//NOTICE: This function is dependant on JQuery

		if (
			typeof origSettings != 'object'
			||
			origSettings == null
			)
		{
			throw 'Input must be a JavaScript object !';
		}
		var settings = jQuery.extend(true, {}, origSettings);

		if (
			typeof settings.data != 'string'
			&&
			typeof settings.data != 'object'
			)
		{
			throw 'Data must be a string or a JSON object !';
		}
		if (typeof settings.url != 'string')
		{
			throw 'URL must be a string !';
		}
		var self = this;

		if (typeof settings.retry == 'undefined' || settings.retry == null)
		{
			settings.retry = true;
		}
		if (typeof settings.retryDelay == 'undefined' || settings.retryDelay == null)
		{
			settings.retryDelay = 2000;
		}
		if (typeof settings.onEmpty == 'function')
		{
			if (settings.retry)
			{
				var originalOnEmpty = settings.onEmpty;

				//If response empty - Try again...
				settings.onEmpty = function(data, textStatus)
				{
					originalOnEmpty(data, textStatus);
					setTimeout(
						function()
						{
							self.sendRequest(origSettings);
						},
						settings.retryDelay
						);
				};
			}
		}
		else
		{
			if (settings.retry)
			{
				//If response empty - Try again...
				settings.onEmpty = function(data, textStatus)
				{
					setTimeout(
						function()
						{
							self.sendRequest(origSettings);
						},
						settings.retryDelay
						);
				};
			}
			else
			{
				settings.onEmpty = function(data, textStatus)
				{
				};
			}
		}

		if (typeof settings.onNonErrorNonEmpty == 'function')
		{
			if (typeof settings.onNonEmpty == 'function')
			{
				var originalOnNonEmpty = settings.onNonEmpty;
				settings.onNonEmpty =
					function(data, textStatus)
					{
						originalOnNonEmpty(data, textStatus);
						settings.onNonErrorNonEmpty(data, textStatus);
					};
			}
			else
			{
				settings.onNonEmpty = settings.onNonErrorNonEmpty;
			}

			if (typeof settings.onError == 'function')
			{
				var originalOnError = settings.onError;
				settings.onError =
					function(xhr, textStatus, errorThrown)
					{
						originalOnError(xhr, textStatus, errorThrown);
						settings.onNonErrorNonEmpty(null, textStatus);
					};
			}
			else
			{
				settings.onError =
					function(xhr, textStatus, errorThrown)
					{
						settings.onNonErrorNonEmpty(null, textStatus);
					};
			}
		}
		var ajaxSettings =
			{
				url: settings.url,
				processData: true,
				dataType: 'text',
				success: function(data, textStatus, xhr)
				{
					if (
						typeof settings.validateResponse == 'undefined'
						||
						settings.validateResponse != FALSE//To help enforce "True by default" - I specifically check that it's not equal to FALSE instead of checking that it is TRUE.
						)
					{
						var validateResponseSettings =
							{
								data: data,
								textStatus: textStatus
							};
						if (typeof settings.onValid != 'undefined')
						{
							validateResponseSettings.onValid = settings.onValid;
						}
						if (typeof settings.onExplicitlyInvalid != 'undefined')
						{
							validateResponseSettings.onExplicitlyInvalid = settings.onExplicitlyInvalid;
						}
						if (typeof settings.onImplicitlyInvalid != 'undefined')
						{
							validateResponseSettings.onImplicitlyInvalid = settings.onImplicitlyInvalid;
						}
						if (typeof settings.onEmpty != 'undefined')
						{
							validateResponseSettings.onEmpty = settings.onEmpty;
						}
						if (typeof settings.onNonEmpty != 'undefined')
						{
							validateResponseSettings.onNonEmpty = settings.onNonEmpty;
						}
						if (typeof settings.decodeFunction != 'undefined')
						{
							validateResponseSettings.decodeFunction = settings.decodeFunction;
						}
						if (typeof settings.validResponseIndicator != 'undefined')
						{
							validateResponseSettings.validResponseIndicator = settings.validResponseIndicator;
						}
						if (typeof settings.invalidResponseIndicator != 'undefined')
						{
							validateResponseSettings.invalidResponseIndicator = settings.invalidResponseIndicator;
						}

						self.validateResponse(validateResponseSettings);
					}
					else
					{
						if (typeof data == 'undefined')
						{
							settings.onEmpty(data, textStatus);
						}
						else if (typeof data == 'string')
						{
							if (data == '')
							{
								settings.onEmpty(data, textStatus);
							}
							else
							{
								if (typeof settings.decodeFunction == 'function')
								{
									data = settings.decodeFunction(data);
								}
								settings.onNonEmpty(data, textStatus);
							}

							if (typeof settings.onValid == 'function')
							{
								settings.onValid(data, textStatus);
							}
						}
					}
				},
				dataFilter: function(data, type)
				{
					return data;
				}
			};

		if (typeof settings.type == 'undefined' || settings.type == null)
		{
			ajaxSettings.type = 'post';
		}
		else
		{
			ajaxSettings.type = settings.type;
		}

		ajaxSettings.data = {};
		if (typeof settings.data != 'undefined')
		{
			ajaxSettings.data = settings.data;
		}
		if (settings.serverFunction != null)
		{
			if (typeof settings.data == 'string')
			{
				ajaxSettings.data += '&serverFunction=' + settings.serverFunction;
			}
			else
			{
				ajaxSettings.data.serverFunction = settings.serverFunction;
			}
		}

		if (typeof settings.onError == 'function')
		{
			ajaxSettings.error = settings.onError;
		}
		if (typeof settings.onComplete == 'function')
		{
			ajaxSettings.complete = settings.onComplete;
		}

		$.ajax(ajaxSettings);
	},

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	This function is very useful to distinguish between different scenarios such as:<br />
	 * </p>
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>Valid server response</li>
	 *		<li>Explicitly invalid server response</li>
	 *		<li>Implicitly invalid server response</li>
	 *		<li>No response ( Possible network problem )</li>
	 *	</ul>
	 * </div>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>data</li>
	 *		<li>textStatus</li>
	 *		<li>onValid</li>
	 *		<li>onExplicitlyInvalid</li>
	 *		<li>onImplicitlyInvalid</li>
	 *		<li>onEmpty</li>
	 *		<li>onNonEmpty</li>
	 *		<li>decodeFunction</li>
	 *		<li>validResponseIndicator</li>
	 *		<li>invalidResponseIndicator</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>data</strong> -<br />
	 *			Required.<br />
	 *			Data received from the server.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>textStatus</strong> -<br />
	 *			Required.<br />
	 *			String.<br />
	 *			textStatus as received by JQuery's functions.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onValid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run upon a valid response from the server.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onExplicitlyInvalid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if the server returns an explicitly invalid response.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onImplicitlyInvalid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if the server returns an implicitly invalid response.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onEmpty</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if an empty response is received ( could be the result of failing to reach the server ).<br />
	 *			By default, this will be a function that waits 2 seconds and tries sending the request again.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onNonEmpty</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if a non-empty response is received<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>decodeFunction</strong> -<br />
	 *			function<br />
	 *			Optional.<br />
	 *			A function to pass the returned data through.<br />
	 *			For example - <i>Base64.decode()</i> can go here.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validResponseIndicator</strong> -<br />
	 *			string<br />
	 *			Optional.<br />
	 *			A string the server should add to the beginning of the response in order to indicate "success".<br />
	 *			"1" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>invalidResponseIndicator</strong> -<br />
	 *			string<br />
	 *			Optional.<br />
	 *			A string the server should add to the beginning of the response in order to indicate "failure".<br />
	 *			"0" by default.<br />
	 *			<br />
	 *		</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * @return Void
	 *
	 * @author Ran Zafrir
	 *
	 */
	validateResponse: function(origSettings)
	{
		//This function has no dependencies

		if (
			typeof origSettings != 'object'
			||
			origSettings == null
			)
		{
			throw 'Input must be a JavaScript object !';
		}
		var settings = {};
		settings.data = origSettings.data;
		settings.textStatus = origSettings.textStatus;

		if (typeof origSettings.onValid == 'function')
		{
			settings.onValid = origSettings.onValid;
		}
		else
		{
			settings.onValid = function(data, textStatus) {};
		}
		if (typeof origSettings.onExplicitlyInvalid == 'function')
		{
			settings.onExplicitlyInvalid = origSettings.onExplicitlyInvalid;
		}
		else
		{
			settings.onExplicitlyInvalid = function(data, textStatus) {};
		}
		if (typeof origSettings.onImplicitlyInvalid == 'function')
		{
			settings.onImplicitlyInvalid = origSettings.onImplicitlyInvalid;
		}
		else
		{
			settings.onImplicitlyInvalid = function(data, textStatus) {};
		}
		if (typeof origSettings.onEmpty == 'function')
		{
			settings.onEmpty = origSettings.onEmpty;
		}
		else
		{
			settings.onEmpty = function(data, textStatus) {};
		}
		if (typeof origSettings.onNonEmpty == 'function')
		{
			settings.onNonEmpty = origSettings.onNonEmpty;
		}
		else
		{
			settings.onNonEmpty = function(data, textStatus) {};
		}
		if (typeof origSettings.validResponseIndicator == 'string')
		{
			settings.validResponseIndicator = origSettings.validResponseIndicator;
		}
		else
		{
			settings.validResponseIndicator = '1';
		}
		if (typeof origSettings.invalidResponseIndicator == 'string')
		{
			settings.invalidResponseIndicator = origSettings.invalidResponseIndicator;
		}
		else
		{
			settings.invalidResponseIndicator = '0';
		}

		if (typeof settings.data == 'undefined')
		{
			settings.onEmpty(settings.data, settings.textStatus);
		}
		else if (typeof settings.data == 'string')
		{
			if (
				settings.data.length >= settings.validResponseIndicator.length
				&&
				settings.data.substring(0, settings.validResponseIndicator.length) == settings.validResponseIndicator
				)
			{
				settings.data = settings.data.substring(settings.validResponseIndicator.length);
				if (typeof origSettings.decodeFunction == 'function')
				{
					settings.data = origSettings.decodeFunction(settings.data);
				}
				settings.onNonEmpty(settings.data, settings.textStatus);
				settings.onValid(settings.data, settings.textStatus);
			}
			else if (
				settings.data.length >= settings.invalidResponseIndicator.length
				&&
				settings.data.substring(0, settings.invalidResponseIndicator.length) == settings.invalidResponseIndicator
				)
			{
				settings.data = settings.data.substring(settings.invalidResponseIndicator.length);
				if (typeof origSettings.decodeFunction == 'function')
				{
					settings.data = origSettings.decodeFunction(settings.data);//Not sure anyone will use this, but let's return the data anyway just in case.
				}
				settings.onNonEmpty(settings.data, settings.textStatus);
				settings.onExplicitlyInvalid(settings.data, settings.textStatus);
			}
			else if (settings.data == '')
			{
				settings.onEmpty(settings.data, settings.textStatus);
			}
			else
			{
				if (typeof origSettings.decodeFunction == 'function')
				{
					settings.data = origSettings.decodeFunction(settings.data);//Not sure anyone will use this, but let's return the data anyway just in case.
				}
				settings.onNonEmpty(settings.data, settings.textStatus);
				settings.onImplicitlyInvalid(settings.data, settings.textStatus);
			}
		}
	},

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	Like sendRequest, only that this function sends the contents of a "select" object.<br />
	 *	This function will first disable the "select" object so it can't be modified until the request is processed.<br />
	 *	Once a response is received from the server, the "select" will be returned to it's inital state ( enabled / disabled )<br />
	 * </p>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>data</li>
	 *		<li>url</li>
	 *		<li>type</li>
	 *		<li>serverFunction</li>
	 *		<li>onValid</li>
	 *		<li>onExplicitlyInvalid</li>
	 *		<li>onImplicitlyInvalid</li>
	 *		<li>onError</li>
	 *		<li>onEmpty</li>
	 *		<li>onNonEmpty</li>
	 *		<li>onComplete</li>
	 *		<li>onNonErrorNonEmpty</li>
	 *		<li>retry</li>
	 *		<li>retryDelay</li>
	 *		<li>decodeFunction</li>
	 *		<li>validateResponse</li>
	 *		<li>validResponseIndicator</li>
	 *		<li>invalidResponseIndicator</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>data</strong> -<br />
	 *			Required.<br />
	 *			Data to be sent to the server.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>url</strong> -<br />
	 *			Required.<br />
	 *			The URL of the request.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>type</strong> -<br />
	 *			Optional.<br />
	 *			Request type ( "get" or "post" ).<br />
	 *			"post" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>serverFunction</strong> -<br />
	 *			Optional.<br />
	 *			This is useful if you concentrate all of your AJAX handling in 1 file.<br />
	 *			That way you can use this parameter to specify the server-function ( within that file ) to handle the request.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onValid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run upon a valid response from the server.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onExplicitlyInvalid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if the server returns an explicitly invalid response.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onImplicitlyInvalid</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if the server returns an implicitly invalid response.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onError</strong> -<br />
	 *			function(XMLHttpRequest, textStatus, errorThrown)<br />
	 *			Optional.<br />
	 *			A function to be called if the request fails. The function is passed three arguments: The XMLHttpRequest object, a string describing the type of error that occurred and an optional exception object, if one occurred. Possible values for the second argument (besides null) are "timeout", "error", "notmodified" and "parsererror".<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onEmpty</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if an empty response is received ( could be the result of failing to reach the server ).<br />
	 *			By default, this will be a function that waits 2 seconds and tries sending the request again.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onNonEmpty</strong> -<br />
	 *			function(data, textStatus)<br />
	 *			Optional.<br />
	 *			A function to run if a non-empty response is received<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onComplete</strong> -<br />
	 *			function(XMLHttpRequest, textStatus)<br />
	 *			Optional.<br />
	 *			A function to be called when the request finishes (after success and error callbacks are executed). The function gets passed two arguments: The XMLHttpRequest object and a string describing the status of the request.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onNonErrorNonEmpty</strong> -<br />
	 *			function<br />
	 *			Optional.<br />
	 *			A function to be called when the response is not empty and not a server-error<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>retry</strong> -<br />
	 *			Boolean<br />
	 *			Optional.<br />
	 *			A boolean specifying whether to keep retrying when an empty response is received.<br />
	 *			TRUE by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>retryDelay</strong> -<br />
	 *			Integer<br />
	 *			Optional.<br />
	 *			Specifies the number of milliseconds to wait between retry attempts.<br />
	 *			2000 by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>decodeFunction</strong> -<br />
	 *			function<br />
	 *			Optional.<br />
	 *			A function to pass the returned data through.<br />
	 *			For example - Base64.decode can go here.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validateResponse</strong> -<br />
	 *			boolean<br />
	 *			Optional.<br />
	 *			A boolean indicating whether the server's response should be passed through AjaxHelpers.validateResponse().<br />
	 *			<i>onExplicitlyInvalid</i> and <i>onImplicitlyInvalid</i> will be ignored if this is set to FALSE.<br />
	 *			TRUE by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validResponseIndicator</strong> -<br />
	 *			string<br />
	 *			Optional.<br />
	 *			A string the server should add to the beginning of the response in order to indicate "success".<br />
	 *			"1" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>invalidResponseIndicator</strong> -<br />
	 *			string<br />
	 *			Optional.<br />
	 *			A string the server should add to the beginning of the response in order to indicate "failure".<br />
	 *			"0" by default.<br />
	 *			<br />
	 *		</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * @return Void
	 * @requires JQuery
	 *
	 * @author Ran Zafrir
	 *
	 */
	sendList: function(origSettings)
	{
		//NOTICE: This function is dependant on JQuery

		if (
			typeof origSettings != 'object'
			||
			origSettings == null
			)
		{
			throw 'Input must be a JavaScript object !';
		}
		var settings = jQuery.extend(true, {}, origSettings);

		if (typeof settings.list == 'string') settings.list = document.getElementById(list);

		settings.data = '';
		for (var i = 0; i < settings.list.length; i++)
		{
			settings.data +=
				settings.list.options[i].value.length + ',' + settings.list.options[i].value;
		}

		if (!settings.list.disabled)
		{
			settings.list.disabled = true;

			if (typeof onNonEmpty == 'function')
			{
				var originalOnNonEmpty = settings.onNonEmpty;
				settings.onNonEmpty =
					function(data, textStatus)
					{
						settings.list.disabled = false;
						originalOnNonEmpty(data, textStatus);
					};
			}
			else
			{
				settings.onNonEmpty =
					function(data, textStatus)
					{
						settings.list.disabled = false;
					};
			}
		}

		AjaxHelpers.sendRequest(settings);
	}
};

var Validation = function()
{
	var self;
	var init = function()
	{
		self = this;
	}

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	This function is being used internally.<br />
	 *	Validates a specified input-field and adds/removes a specified CSS-class ( typically "error" ) to/from that field.<br />
	 * </p>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>input</li>
	 *		<li>validationFunction</li>
	 *		<li>errorClass</li>
	 *		<li>passToCallbacks</li>
	 *		<li>beforeSetError</li>
	 *		<li>beforeRemoveError</li>
	 *		<li>onError</li>
	 *		<li>onValid</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>input</strong> -<br />
	 *			Required.<br />
	 *			The input-field ( or a JQuery Selector pointing to an input-field ) to validate.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validationFunction</strong> -<br />
	 *			Required.<br />
	 *			A JavaScript function that accepts 1 string paramter and returns a boolean.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>errorClass</strong> -<br />
	 *			Required.<br />
	 *			A CSS-class to use for showing that the specified input-field has errors.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>passToCallbacks</strong> -<br />
	 *			Optional.<br />
	 *			A parameter to be passed to callbacks.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeSetError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called before setting the error-class<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeRemoveError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called before removing the error-class.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is invalid.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onValid</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is valid.<br />
	 *			<br />
	 *		</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * @return Void
	 * @requires JQuery
	 *
	 * @author Ran Zafrir
	 *
	 */
	var _validateInput = function(settings)
	{
		if (typeof settings.input == 'undefined')
		{
			throw 'Must specify input element';
		}
		if (typeof settings.validationFunction != 'function')
		{
			throw 'Must specify validation-function';
		}
		if (typeof settings.errorClass != 'string')
		{
			throw '"errorClass" must be a string. ' + (typeof settings.errorClass) + ' specified.';
		}

		if (settings.validationFunction($(settings.input).val()) == true)
		{
			if (typeof settings.beforeRemoveError == 'function')
			{
				if ($(settings.input).hasClass(settings.errorClass))
				{
					settings.beforeRemoveError(settings.input, settings.passToCallbacks);
					$(settings.input).removeClass(settings.errorClass);
				}
			}
			else
			{
				$(settings.input).removeClass(settings.errorClass);
			}

			if (typeof settings.onValid == 'function')
			{
				settings.onValid(settings.input, settings.passToCallbacks);
			}
		}
		else
		{
			if (!$(settings.input).hasClass(settings.errorClass))
			{
				if (typeof settings.beforeSetError == 'function')
				{
					settings.beforeSetError(settings.input, settings.passToCallbacks);
				}
				$(settings.input).addClass(settings.errorClass);
			}

			if (typeof settings.onError == 'function')
			{
				settings.onError(settings.input, settings.passToCallbacks);
			}
		}
	};

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	Validates a specified input-field and adds/removes a specified CSS-class ( typically "error" ) to/from that field.<br />
	 * </p>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>input</li>
	 *		<li>validationFunction</li>
	 *		<li>errorClass</li>
	 *		<li>passToCallbacks</li>
	 *		<li>beforeSetError</li>
	 *		<li>beforeRemoveError</li>
	 *		<li>onError</li>
	 *		<li>onValid</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>input</strong> -<br />
	 *			Required.<br />
	 *			The input-field ( or a JQuery Selector pointing to an input-field ) to validate.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validationFunction</strong> -<br />
	 *			Required.<br />
	 *			A JavaScript function that accepts 1 string paramter and returns a boolean.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>errorClass</strong> -<br />
	 *			Optional.<br />
	 *			A CSS-class to use for showing that the specified input-field has errors.<br />
	 *			"error" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>passToCallbacks</strong> -<br />
	 *			Optional.<br />
	 *			A parameter to be passed to callbacks.<br />
	 *			<i>validationFunction</i> by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeSetError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called before setting the error-class<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeRemoveError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called before removing the error-class.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is invalid.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onValid</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is valid.<br />
	 *			<br />
	 *		</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * @return Void
	 * @requires JQuery
	 *
	 * @author Ran Zafrir
	 *
	 */
	var validateInput = function(settings)
	{
		//NOTICE: This function is dependant on JQuery
		//TODO: Make this function NON-JQuery dependent and then move it to general.js

		if (
			typeof settings != 'object'
			||
			settings == null
			)
		{
			throw 'Input must be a JavaScript object !';
		}

		var settingsCopy = {};
		if (typeof settings.input == 'undefined')
		{
			throw 'Must specify input element';
		}
		else
		{
			settingsCopy.input = settings.input;
		}
		if (typeof settings.validationFunction == 'function')
		{
			settingsCopy.validationFunction = settings.validationFunction;
		}
		else
		{
			throw 'Must specify validation-function';
		}
		if (typeof settings.errorClass == 'string')
		{
			settingsCopy.errorClass = settings.errorClass;
		}
		else
		{
			settingsCopy.errorClass = 'error';
		}
		if (typeof settings.passToCallbacks == 'undefined')
		{
			settingsCopy.passToCallbacks = settings.validationFunction;
		}
		else
		{
			settingsCopy.passToCallbacks = settings.passToCallbacks;
		}
		if (typeof settings.beforeSetError != 'undefined')
		{
			settingsCopy.beforeSetError = settings.beforeSetError;
		}
		if (typeof settings.beforeRemoveError != 'undefined')
		{
			settingsCopy.beforeRemoveError = settings.beforeRemoveError;
		}
		if (typeof settings.onError != 'undefined')
		{
			settingsCopy.onError = settings.onError;
		}
		if (typeof settings.onValid != 'undefined')
		{
			settingsCopy.onValid = settings.onValid;
		}

		_validateInput(settingsCopy);
	};

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	Starts validating the specified input-field in real-time.<br />
	 * </p>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>input</li>
	 *		<li>validationFunction</li>
	 *		<li>errorClass</li>
	 *		<li>passToCallbacks</li>
	 *		<li>beforeSetError</li>
	 *		<li>beforeRemoveError</li>
	 *		<li>onError</li>
	 *		<li>onValid</li>
	 *		<li>validateOnBlur</li>
	 *		<li>validateOnChange</li>
	 *		<li>validateOnKeyup</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>input</strong> -<br />
	 *			Required.<br />
	 *			The input-field ( or a JQuery Selector pointing to an input-field ) to validate.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validationFunction</strong> -<br />
	 *			Required.<br />
	 *			A JavaScript function that accepts 1 string paramter and returns a boolean.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>errorClass</strong> -<br />
	 *			Optional.<br />
	 *			A CSS-class to use for showing that the specified input-field has errors.<br />
	 *			"error" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>passToCallbacks</strong> -<br />
	 *			Optional.<br />
	 *			A parameter to be passed to callbacks.<br />
	 *			<i>validationFunction</i> by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeSetError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called before setting the error-class<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeRemoveError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called before removing the error-class.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onError</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is invalid.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onValid</strong> -<br />
	 *			function(input, validationFunction)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is valid.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validateOnBlur</strong> -<br />
	 *			Optional.<br />
	 *			True by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validateOnChange</strong> -<br />
	 *			Optional.<br />
	 *			True by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>validateOnKeyup</strong> -<br />
	 *			Optional.<br />
	 *			True by default.<br />
	 *			<br />
	 *		</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * @return Void
	 * @requires JQuery
	 *
	 * @author Ran Zafrir
	 *
	 */
	var startInputValidation = function(origSettings)
	{
		//NOTICE: This function is dependant on JQuery

		if (
			typeof origSettings != 'object'
			||
			origSettings == null
			)
		{
			throw 'Input must be a JavaScript object !';
		}

		var settings = {};
		if (typeof origSettings.validationFunction == 'function')
		{
			settings.validationFunction = origSettings.validationFunction;
		}
		else
		{
			throw 'Must specify validation-function';
		}
		if (typeof origSettings.errorClass == 'string')
		{
			settings.errorClass = origSettings.errorClass;
		}
		if (typeof origSettings.beforeSetError != 'undefined')
		{
			settings.beforeSetError = origSettings.beforeSetError;
		}
		if (typeof origSettings.beforeRemoveError != 'undefined')
		{
			settings.beforeRemoveError = origSettings.beforeRemoveError;
		}
		if (typeof origSettings.onError != 'undefined')
		{
			settings.onError = origSettings.onError;
		}
		if (typeof origSettings.onValid != 'undefined')
		{
			settings.onValid = origSettings.onValid;
		}

		//var self = this;

		if (
			typeof origSettings.validateOnKeyup == 'undefined'
			||
			origSettings.validateOnBlur != false//To help enforce "True by default" - I specifically check that it's not equal to FALSE instead of checking that it is TRUE.
			)
		{
			$(origSettings.input).blur(
				function()
				{
					settings.input = this;
					self.validateInput(settings);
				}
			);
		}
		if (
			typeof origSettings.validateOnKeyup == 'undefined'
			||
			origSettings.validateOnChange != false//To help enforce "True by default" - I specifically check that it's not equal to FALSE instead of checking that it is TRUE.
			)
		{
			$(origSettings.input).change(
				function()
				{
					settings.input = this;
					self.validateInput(settings);
				}
			);
		}
		if (
			typeof origSettings.validateOnKeyup == 'undefined'
			||
			origSettings.validateOnKeyup != false//To help enforce "True by default" - I specifically check that it's not equal to FALSE instead of checking that it is TRUE.
			)
		{
			$(origSettings.input).keyup(
				function()
				{
					settings.input = this;
					self.validateInput(settings);
				}
			);
		}
	};

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	This can be used to validate an entire form via AJAX.<br />
	 * </p>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li>elements</li>
	 *		<li>errors</li>
	 *		<li>errorClass</li>
	 *		<li>beforeSetError</li>
	 *		<li>beforeRemoveError</li>
	 *		<li>onError</li>
	 *		<li>onValid</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>elements</strong> -<br />
	 *			Required.<br />
	 *			A JSON-array with this format:<br />
	 *			<div style="margin-left: 20px;">
	 *				{<br />
	 *					serverIdentifier1: input1,<br />
	 *					serverIdentifier2: input2,<br />
	 *					serverIdentifier3: input3,<br />
	 *					.<br />
	 *					.<br />
	 *					.<br />
	 *					serverIdentifierN: inputN<br />
	 *				}
	 *			</div>
	 *			<br />
	 *			"serverIdentifier" is a name ( string ) used by the server to identify the specified input-field.<br />
	 *			"input" is an input-field or a JQuery Selector pointing to an input-field.<br />
	 *		</li>
	 *
	 *		<li><strong>errors</strong> -<br />
	 *			Required.<br />
	 *			A JSON-object with this format:<br />
	 *			<div style="margin-left: 20px;">
	 *				{<br />
	 *					serverIdentifier1: error1,<br />
	 *					serverIdentifier2: error2,<br />
	 *					serverIdentifier3: error3<br />
	 *					.<br />
	 *					.<br />
	 *					.<br />
	 *					serverIdentifierN: errorN<br />
	 *				}
	 *			</div>
	 *			<br />
	 *			"serverIdentifier" is a name ( string ) used by the server to identify the specified input-field.<br />
	 *			"error" is the text to display for the specified input-field.<br />
	 *		</li>
	 *
	 *		<li><strong>errorClass</strong> -<br />
	 *			Optional.<br />
	 *			A CSS-class to use for showing that the specified input-field has errors.<br />
	 *			"error" by default.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeSetError</strong> -<br />
	 *			function(input, error)<br />
	 *			Optional.<br />
	 *			A function to be called before setting the error-class<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>beforeRemoveError</strong> -<br />
	 *			function(input, error)<br />
	 *			Optional.<br />
	 *			A function to be called before removing the error-class.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onError</strong> -<br />
	 *			function(input, error)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is invalid.<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>onValid</strong> -<br />
	 *			function(input, error)<br />
	 *			Optional.<br />
	 *			A function to be called if the specified input is valid.<br />
	 *			<br />
	 *		</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 *
	 * @return Void
	 * @requires JQuery
	 *
	 * @author Ran Zafrir
	 *
	 */
	var applyErrorsToElements = function(settings)
	{
		//NOTICE: This function is dependant on JQuery
		//TODO

		if (
			typeof settings != 'object'
			||
			settings == null
			)
		{
			throw 'Input must be a JavaScript object !';
		}
		if (typeof settings.elements != 'object')
		{
			throw 'Must specify elements';
		}
		if (typeof settings.errors != 'object')
		{
			throw 'Must specify errors';
		}

		var settingsCopy = {};
		if (typeof settings.errorClass == 'string')
		{
			settingsCopy.errorClass = settings.errorClass;
		}
		if (typeof settings.beforeSetError != 'undefined')
		{
			settingsCopy.beforeSetError = settings.beforeSetError;
		}
		if (typeof settings.beforeRemoveError != 'undefined')
		{
			settingsCopy.beforeRemoveError = settings.beforeRemoveError;
		}
		if (typeof settings.onError != 'undefined')
		{
			settingsCopy.onError = settings.onError;
		}
		if (typeof settings.onValid != 'undefined')
		{
			settingsCopy.onValid = settings.onValid;
		}

		//var self = this;

		for (elementKey in settings.elements)
		{
			if (settings.errors.hasOwnProperty(elementKey))
			{
				//Set error
				$(settings.elements[elementKey]).each(
					function()
					{
						settingsCopy.input = this;
						settingsCopy.validationFunction = function(param)
						{
							return false;
						};
						settingsCopy.passToCallbacks = settings.errors[elementKey];
						self.validateInput(settingsCopy);
					}
				);
			}
			else
			{
				//Clear error
				$(settings.elements[elementKey]).each(
					function()
					{
						settingsCopy.input = this;
						settingsCopy.validationFunction = function(param)
						{
							return true;
						};
						self.validateInput(settingsCopy);
					}
				);
			}
		}
	};

	return {
		// Declare which properties and methods are supposed to be public
		init: init,
		validateInput: validateInput,
		startInputValidation: startInputValidation,
		applyErrorsToElements: applyErrorsToElements
	};
}();
Validation.init();

/**
 *
 * <p>Written by Ran Zafrir.</p>
 * <p>
 *	This is used for opening JQuery-dialogs ( possibly with several buttons like: "OK", "Cancel", etc'. ) on the fly with very little coding and ** WITHOUT ** creating any HTML !<br />
 * </p>
 *
 *
 *
 * @requires JQuery
 * @requires JQuery-UI
 *
 * @author Ran Zafrir
 *
 */
var DialogFactory =
{
	//Private Properties:
	_dialogs: [],
	_reservedDialogs: [],

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	Initializes a new dialog.<br />
	 *	This function was meant for internal use, but you can also use it externally.<br />
	 *	( though I can't figure why you'll want to do that )<br />
	 * </p>
	 *
	 *
	 *
	 * @return A JSON object containing information about the created dialog.
	 * @type JSON Object
	 * @requires JQuery
	 * @requires JQuery-UI
	 *
	 * @author Ran Zafrir
	 *
	 */
	initNewDialog : function(reserve)
	{
		//NOTICE: This function is dependant on JQuery

		if (typeof reserve == 'undefined') reserve = false;

		//Create a div and then have JQuery make it into a dialog
		var dialogDiv = document.createElement('div');
		dialogDiv.style.display = 'none';
		var messageObj = document.createElement('div');
		dialogDiv.appendChild(messageObj);
		document.body.appendChild(dialogDiv);

		$(dialogDiv).dialog({
			autoOpen: false,
			closeOnEscape: true,
			dialogClass: 'jqueryui',
			modal: false,
			stack: true,
			resizable: false,//JQuery's default is TRUE
			title: ''
			//buttons:
			//{
			//	'OK': function()
			//	{
			//		$(this).dialog('close');
			//	}
			//},
			//beforeClose: function(event, ui)
			//{
			//},
			//close: function(event, ui)
			//{
			//}
		});

		var dialog =
		{
			dialogDiv: dialogDiv,
			messageObj: messageObj,
			dialogDivClass: null
		};
		if (reserve)
		{
			this._reservedDialogs.push(dialog);
		}
		else
		{
			this._dialogs.push(dialog);
		}

		return dialog;
	},

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 *
	 * <p>
	 *	Creates a new DIV and initializes it into a JQuery-dialog ( or re-uses a JQuery-dialog already initialized by <i>DialogFactory</i> ).
	 * </p>
	 *
	 * <p>This function receives a JSON-object that can contain any of these options:</p>
	 *
	 * <p><u><strong>List of Options:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<u>Non-JQuery Options:</u>
	 *	<ul>
	 *		<li>message</li>
	 *		<li>dialog</li>
	 *		<li>reserve</li>
	 *		<li>forceNew</li>
	 *		<li>dialogInnerClass</li>
	 *	</ul>
	 *
	 *	<u>JQuery Options:</u>
	 *	<ul>
	 *		<li>title</li>
	 *		<li>modal</li>
	 *		<li>buttons</li>
	 *		<li>beforeclose</li>
	 *		<li>close</li>
	 *		<li>width</li>
	 *		<li>height</li>
	 *		<li>dialogClass</li>
	 *		<li>disabled</li>
	 *		<li>closeOnEscape</li>
	 *		<li>stack</li>
	 *		<li>resizable</li>
	 *	</ul>
	 * </div>
	 *
	 *
	 * <p><u><strong>Options Description:</strong></u></p>
	 * <br />
	 *
	 * <div style="margin-left: 20px;">
	 *	<ul>
	 *		<li><strong>message</strong> -<br />
	 *			Required unless <i>dialog</i> is used.<br />
	 *			Message HTML<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>dialog</strong> -<br />
	 *			Required unless <i>message</i> is used.<br />
	 *			Specifies an existing dialog to use<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>reserve</strong> -<br />
	 *			Optional.<br />
	 *			Boolean specifying whether to "reserve" the dialog for future use.<br />
	 *			If this is set to TRUE - The dialog will not be used again unless specifically referenced by "dialog".<br />
	 *			False by default<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>forceNew</strong> -<br />
	 *			Optional.<br />
	 *			Boolean specifying whether to always open a new dialog.<br />
	 *			By default an existing dialog will be used if one is available.<br />
	 *			This will be ignored if "dialog" is set<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>dialogInnerClass</strong> -<br />
	 *			Optional.<br />
	 *			CSS-Class of the dialog's div ( The original div used to create the dialog ).<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>title</strong> -<br />
	 *			Optional.<br />
	 *			Dialog Title<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>modal</strong> -<br />
	 *			Optional.<br />
	 *			Boolean specifying whether dialog is modal or not.<br />
	 *			False by default<br />
	 *			<br />
	 *		</li>
	 *
	 *		<li><strong>buttons</strong> -<br />
	 *			Optional.<br />
	 *			<br />
	 *
	 *			<pre>
	 *			Something in this format:
	 *			{
	 *			&#9;'OK': function()
	 *			&#9;{
	 *			&#9;&#9;DO_SOMETHING_HERE...
	 *
	 *			&#9;&#9;$(this).dialog('close');
	 *			&#9;},
	 *			&#9;'Cancel': function()
	 *			&#9;{
	 *			&#9;&#9;$(this).dialog('close');
	 *			&#9;}
	 *			};
	 *			</pre>
	 *			<br />
	 *
	 *			Default is an "OK" button that closes the dialog<br />
	 *			<br />
	 *		</li>
	 *
	 *
	 *	<li><strong>beforeclose</strong> -<br />
	 *			Optional.<br />
	 *			function ( function(event, ui) ) to run before dialog closes<br />
	 *			<br />
	 *	</li>
	 *
	 *	<li><strong>close</strong> -<br />
	 *			Optional.<br />
	 *			function ( function(event, ui) ) to run right after dialog closes<br />
	 *			<br />
	 *	</li>
	 *
	 *	<li><strong>width</strong> -<br />
	 *			Optional.<br />
	 *			Width of the form.<br />
	 *			300 pixels by default.<br />
	 *			<br />
	 *	</li>
	 *
	 *	<li><strong>height</strong> -<br />
	 *			Optional.<br />
	 *			Height of the form.<br />
	 *			'auto' by default.<br />
	 *			<br />
	 *	</li>
	 *
	 *	<li><strong>dialogClass</strong> -<br />
	 *			Optional.<br />
	 *			CSS-Class of the dialog's div ( The one auto-generated by JQuery that contains the original div ).<br />
	 *			<br />
	 *	</li>
	 *
	 *	<li><strong>disabled</strong> -<br />
	 *		Optional.<br />
	 *		Disables (true) or enables (false) the dialog.<br />
	 *		<br />
	 * 	</li>
	 *
	 *	<li><strong>closeOnEscape</strong> -<br />
	 *		Optional.<br />
	 *		Specifies whether the dialog should close when it has focus and the user presses the esacpe (ESC) key.<br />
	 *		<br />
	 * 	</li>
	 *
	 *	<li><strong>stack</strong> -<br />
	 *		Optional.<br />
	 *		Specifies whether the dialog will stack on top of other dialogs.<br />
	 *		This will cause the dialog to move to the front of other dialogs when it gains focus.<br />
	 *		True by default<br />
	 *		<br />
	 * 	</li>
	 *
	 *	<li><strong>resizable</strong> -<br />
	 *		Optional.<br />
	 *		If set to true, the dialog will be resizeable.<br />
	 *		False by default<br />
	 *		<br />
	 * 	</li>
	 * </ul>
	 * </div>
	 *
	 *
	 *
	 * @return A JSON object containing information about the dialog used.
	 * @type JSON Object
	 * @requires JQuery
	 * @requires JQuery-UI
	 *
	 * @author Ran Zafrir
	 *
	 */
	openDialog : function(settings)
	{
		//NOTICE: This function is dependant on JQuery

		if (
			typeof settings != 'object'
			||
			settings == null
			)
		{
			throw 'Input must be a JavaScript object !';
		}

		if (
			typeof settings.message == 'undefined'
			&&
			typeof settings.dialog == 'undefined'
			)
		{
			throw 'Must set new-dialog\'s content or specify an existing dialog !';
		}

		var dialog = null;
		if (
			typeof settings.dialog == 'undefined'
			||
			settings.dialog == null
			)
		{
			if (
				typeof settings.forceNew == 'undefined'
				||
				!settings.forceNew
				)
			{
				//Check if you can re-use an existing ( non-reserved ) dialog
				for (var i = this._dialogs.length - 1; i >= 0; i--)
				{
					if ( !$(this._dialogs[i].dialogDiv).dialog('isOpen') )
					//If found an existing dialog that's not currently open
					{
						//Use the existing dialog !
						dialog = this._dialogs[i];
						break;
					}
				}

				if (dialog == null)
				//If no available dialogs found --> Make a new one
				{
					dialog =
						this.initNewDialog(
							typeof settings.reserve != 'undefined'
							&&
							settings.reserve
						);//Initialize a new dialog
				}
			}
			else
			{
				dialog =
					this.initNewDialog(
						typeof settings.reserve != 'undefined'
						&&
						settings.reserve
					);//Initialize a new dialog
			}
		}
		else
		{
			dialog = settings.dialog;
		}

		if (typeof settings.message != 'undefined')
		{
			dialog.messageObj.innerHTML = settings.message;
		}

		var dialogOptions = {};

		if (typeof settings.title != 'undefined')
		{
			dialogOptions.title = settings.title;
		}
		if (typeof settings.modal != 'undefined')
		{
			dialogOptions.modal = settings.modal;
		}
		if (
			typeof settings.buttons == 'undefined'
			||
			settings.buttons == null
			)
		{
			if (
				typeof settings.dialog == 'undefined'
				||
				settings.dialog == null
				)
			{
				//This is the default when not forced to use a specific dialog
				dialogOptions.buttons =
					{
						'OK': function()
						{
							$(this).dialog('close');
						}
					};
			}
		}
		else
		{
			dialogOptions.buttons = settings.buttons;
		}

		if (typeof settings.beforeclose == 'function')
		{
			dialogOptions.beforeclose = settings.beforeclose;
		}
		if (typeof settings.close == 'function')
		{
			dialogOptions.close = settings.close;
		}
		if (typeof settings.width != 'undefined')
		{
			dialogOptions.width = settings.width;
		}
		if (typeof settings.height != 'undefined')
		{
			dialogOptions.height = settings.height;
		}
		if (typeof settings.dialogClass == 'string')
		{
			dialogOptions.dialogClass = settings.dialogClass;
		}
		if (typeof settings.disabled != 'undefined')
		{
			dialogOptions.disabled = settings.disabled;
		}
		if (typeof settings.closeOnEscape != 'undefined')
		{
			dialogOptions.closeOnEscape = settings.closeOnEscape;
		}
		if (typeof settings.stack != 'undefined')
		{
			dialogOptions.stack = settings.stack;
		}
		if (typeof settings.resizable != 'undefined')
		{
			dialogOptions.resizable = settings.resizable;
		}

		$(dialog.dialogDiv).dialog(
			'option',
			dialogOptions
			);

		if (typeof settings.dialogInnerClass == 'string')
		{
			if (dialog.dialogDivClass != null)
			{
				$(dialog.dialogDiv).removeClass(dialog.dialogDivClass);
			}
			dialog.dialogDivClass = settings.dialogInnerClass;
			$(dialog.dialogDiv).addClass(settings.dialogInnerClass);
		}
		else
		{
			if (dialog.dialogDivClass != null)
			{
				$(dialog.dialogDiv).removeClass(dialog.dialogDivClass);
				dialog.dialogDivClass = null;
			}
		}

		$(dialog.dialogDiv).dialog('open');

		return dialog;
	},

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	"Marks" the specified dialog as "Reserved" so that it won't be re-used when <i>openDialog()</i> is called.<br />
	 * </p>
	 *
	 *
	 *
	 * @return A JSON object containing information about the dialog used, or FALSE if the specified dialog was already reserved or wasn't found.
	 * @type JSON Object
	 *
	 * @author Ran Zafrir
	 *
	 */
	reserveDialog: function(dialog)
	{
		for (var i = this._dialogs.length - 1; i >= 0; i--)
		{
			if ( this._dialogs[i] == dialog )
			{
				this._dialogs.splice(i, 1)
				this._reservedDialogs.push(dialog);

				return dialog;
			}
		}

		return false;
	},

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	"Marks" the specified dialog as "Unreserved" making it available for re-use when calling <i>openDialog()</i>.<br />
	 * </p>
	 *
	 *
	 *
	 * @return A JSON object containing information about the dialog used, or FALSE if the specified dialog was not reserved or not found
	 * @type JSON Object
	 *
	 * @author Ran Zafrir
	 *
	 */
	unreserveDialog: function(dialog)
	{
		for (var i = this._reservedDialogs.length - 1; i >= 0; i--)
		{
			if ( this._reservedDialogs[i] == dialog )
			{
				this._reservedDialogs.splice(i, 1)
				this._dialogs.push(dialog);

				return dialog;
			}
		}

		return false;
	},

	/**
	 *
	 * <p>Written by Ran Zafrir.</p>
	 * <p>
	 *	Destroys all unreserved-dialogs and clears their DIVs.<br />
	 * </p>
	 *
	 *
	 *
	 * @return Void
	 * @requires JQuery
	 * @requires JQuery-UI
	 *
	 * @author Ran Zafrir
	 *
	 */
	clearUnreservedDialogs: function()
	{
		for (var i = this._dialogs.length - 1; i >= 0; i--)
		{
			$(this._dialogs[i].dialogDiv).dialog('destroy');
			document.body.removeChild(this._dialogs[i].dialogDiv);
		}
		this._dialogs = [];
	}
};

