if (typeof(includejs) == 'function')
{
	if (typeof(jQuery) == 'undefined') includejs('/javascripts/jquery.js');
	if (typeof(jQuery.fn.center) == 'undefined') includejs('/javascripts/jquery.center.js');
}
else
{
	msg = typeof(jQuery) == 'undefined' ? '\tjquery.js\n' : '';
	msg += typeof(jQuery.fn.center) == 'undefined' ? '\tjquery.center.js\n' : '';
	if (msg != '')
	{
		alert
		(
			'jquery.ajaxctl.js requires:\n\n' +
			msg +
			'\nLoad includejs.js to insure that all necessary jQuery libraries are automatically loaded.'
		);
	}
}

if (typeof(zXml) == 'undefined')
{
	alert('jquery.ajaxctl.js requires zxml.js');
}

/**
 *	AJAX request controller
 *
 *	Arguments (passed as an object):
 *
 * 		url - Required.  URL of the server-side script.
 *		type - Optional.  Default is "POST".  Type of request ("POST" or "GET").
 *		data - Optional.  Payload to send to script.
 *		callback - Optional.  Function to execute when response is received.
 *		error - Optional.  Function to execute when a non-validation error occurs.
 *		val_error - Optional.  Function to execute when a validation error occurs.
 *		block_page - Optional.  If true, a background image is displayed that
 *			prevents user interaction with the page.  See note on jQuery.ajaxSetup(),
 *			below.
 *		xslt_url - Optional.  URL of XSLT document.  Set to false to return raw
 *			data.  If not specified, default XSLT URL (if any) returned by script
 *			is used.
 *		timeout - Optional.  Default is 10000.  Number of milliseconds to wait
 *			for a response before returning an error.
 *		form - Optional.  Reference to either a form element (as a jQuery object)
 *			or a FormEngine object.  This is used to highlight fields that fail
 *			validation if the PHP FormValidator class is used to check input.
 *
 *	Examples:
 *
 *		HTML used by examples:
 *			<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 *			<html>
 *				<head>
 *					<title>MyApp</title>
 *					<script type="text/javascript">
 *						$(document).ready(function(){
 *							$('#myform').submit(function(){
 *								// script examples go here
 *								return false;
 *							});
 *						});
 *					</script>
 *				</head>
 *				<body>
 *					<form id="myform" method="post" action="#">
 *						<p>
 *							<label>SID: <input type="text" id="SID"></label><br>
 *							<label>Favorite Color: <input type="text" id="FAV_COLOR"></label>
 *						</p>
 *					</form>
 *					<div id="info"></div>
 *				</body>
 *			</html>
 *
 *		Simple request, no response expected or processed:
 *			$.ajaxctl({url: 'myscript.php'});
 *
 *		Request with payload (object style) and callback:
 *			$.ajaxctl({
 *				url: 'myscript.php',
 *				data: {
 *					sid_no: $('#SID_NO').val(),
 *					fav_color: $('#FAV_COLOR').val()
 *				},
 *				callback: function(result) {
 *					$('#info').html(result);
 *				}
 *			});
 *
 *		Same as above, but using a string generated with $.serialize():
 *			$.ajaxctl({
 *				url: 'myscript.php',
 *				data: $('#myform').serialize(),
 *				callback: function(result) {
 *					$('#info').html(result);
 *				}
 *			});
 *
 *	If response text returned by script contains an <xslt_url> element, then the
 *	text is transformed (using the zxml.js library), and the transformed results
 *	are passed to the callback function.  If the xslt_url parameter is specified
 *	in the $.ajaxctl() parameter list, then that XSLT is used for the transformation
 *	(the parameter overrides <xslt_url>).  If no XSLT is specified, then the
 *	raw text is passed to the callback function.
 *
 *	If the response text contains one or more <error> elements, then the text in
 *	these nodes is displayed in an alert dialog.
 *
 *	If the response text begins with a left curly-brace ({), then the data is
 *	assumed to be in JSON format.  The code is executed and assigned as an
 *	object to the argument that is passed to the callback function.
 *
 *	Example responses:
 *
 *		XML that specifies XSLT:
 *			<recordset>
 *				<xslt_url>xslt/mytransformation.xsl</xslt_url>
 *				<offenders>
 *					<offender>
 *						<sid_no>01234567</sid_no>
 *						<name>DOE,JOHN</name>
 *					<offender>
 *					<offender>
 *						<sid_no>99999999</sid_no>
 *						<name>SMITH,JANE</name>
 *					</offender>
 *				</offenders>
 *			</recordset>
 *
 *		XML that returns error:
 *			<recordset>
 *				<error>Invalid SID number.</error>
 *			</recordset>
 *
 *		HTML (no transformation needed):
 *			<table id="offender_info">
 *				<thead>
 *					<tr>
 *						<th>SID</th>
 *						<th>Name</th>
 *					</tr>
 *				</thead>
 *				<tbody>
 *					<tr>
 *						<td>01234567</td>
 *						<td>DOE,JOHN</td>
 *					</tr>
 *					<tr>
 *						<td>99999999</td>
 *						<td>SMITH,JANE</td>
 *					</tr>
 *				</tbody>
 *			</table>
 *
 *		JSON:
 *			{"offenders":[
 *				{"sid_no":"01234567","name":"Doe, John"},
 *				{"sid_no":"99999999","name":"Smith, Jane"}
 *			]}
 *
 *	Using JSON data:
 *
 *	ajaxctl evaluations the JSON response text and assigns the result to the
 *	argument that is passed to the callback function.  This data can then be
 *	read as an object within the callback function.  The example below uses
 *	the JSON data, above, to render a table:
 *
 *		$.ajaxctl({
 *			url: 'myscript.php',
 *			callback: function(responseData)
 *			{
 *				var html = '<table border="1">';
 *				for (var i = 0; i < responseData.offenders.length; i++)
 *				{
 *					html += '<tr>' +
 *						'<td>' + responseData.offenders[i].sid_no + '</td>' +
 *						'<td>' + responseData.offenders[i].name + '</td>' +
 *						'</tr>';
 *				}
 *				$('#results').html(html + '</table>');
 *			}
 *		});
 *
 *	Modification history:
 *		2008-12-01, rlg:  Version 
 *		2008-09-19, rlg:  Updated documentation.
 *		2008-04-10, rlg:  AJAX timeout now defaults to the jQuery default setting
 *			instead of 10000.
 *		2008-04-28, rlg:  Now processes JSON data, storing it as an object in
 *			the argument passed to the callback function.
 *		2008-05-05, rlg:  Added "working" message feature.  Automaticaly generates
 *			and manages display of message while AJAX request is in progress.
 */
jQuery.ajaxctl = function(p_args)
{
	if (typeof(p_args) == 'undefined')
	{
		return false;
	}
	var options = {};  // Collection of jQuery AJAX options derived from p_args
	var old_msg = jQuery.ajaxSettings.loading_msg;
	var block_page = jQuery.ajaxSettings.block_page;
	var show_loading = jQuery.ajaxSettings.show_loading;

	// If no URL is specified, display a message and exit
	if ((typeof(p_args) == 'undefined') || (typeof(p_args.url) == 'undefined'))
	{
		alert('Error:  Required arguments are missing.\n' +
			'\nRequired arguments:\n\n' +
			'\turl - URL of server-side script.\n' +
			'\nOptional arguments:\n\n' +
			'\ttype - Type of request (default is POST)\n' +
			'\tdata - Payload.\n' +
			'\tcallback - Callback function\n' +
			'\terror - Error callback (non-validation errors)\n' +
			'\tval_error - Validation error callback\n' +
			'\tblock_page - If true, blocks user interaction\n' +
			'\tshow_loading - If false, loading message does not display\n' +
			'\txslt_url - URL of XSLT document, set to false to return raw data, do not specify to use default\n' +
			'\ttimeout - Milliseconds to wait for a response.  Default is 0 (unlimited).\n' +
			'\tform - jQuery reference to form used for validation\n' +
			'\nArguments are passed in object form:\n\n' +
			'\t$.ajaxctl({url: \'myscript.php\'});');
		return false;
	}

	// Get jQuery AJAX options from p_args
	options.url = p_args.url;
	options.type = typeof(p_args.type) == 'undefined' ? jQuery.ajaxSettings.type : p_args.type;
	options.timeout = typeof(p_args.timeout) == 'undefined' ? jQuery.ajaxSettings.timeout : p_args.timeout;
	options.async = typeof(p_args.async) == 'undefined' ? true : p_args.async;
	
	if (typeof(p_args.loading_msg) != 'undefined')
	{
		jQuery.ajaxSettings.loading_msg = p_args.loading_msg;
	}
	
	if (typeof(p_args.block_page) != 'undefined')
	{
		jQuery.ajaxSettings.block_page = p_args.block_page;
	}
	
	if (typeof(p_args.show_loading) != 'undefined')
	{
		jQuery.ajaxSettings.show_loading = p_args.show_loading;
	}
	
	// Set "Working" message to current setting
	jQuery('#' + jQuery.ajaxSettings.loading_div).hide();
	jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg').hide();
	if (typeof(jQuery.ajaxSettings.loading_msg) != 'undefined')
	{
		jQuery.ajaxctlSetup({
			loading_msg: jQuery.ajaxSettings.loading_msg
		});
		if (jQuery.ajaxSettings.block_page)
		{
			jQuery('#' + jQuery.ajaxSettings.loading_div).show();
		}
		if (jQuery.ajaxSettings.show_loading)
		{
			jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg').show();
		}
	}

	if (typeof(p_args.data) == 'undefined')
	{
		options.data = {};
	}
	else
	{
		options.data = p_args.data;
	}
	
	// Hide any validation error messages
	if (p_args.form)
	{
		if (p_args.form.isFormEngine)
		{
			validated_form_id = p_args.form.getFormID();
		}
		else
		{
			validated_form_id = p_args.form.attr('id');
		}
		jQuery('#' + validated_form_id + ' span._ajaxctl_val').hide();
	}

	// Define AJAX callback function
	options.success = function(response_text)
	{
		var xslt_data = null;
		var error_msgs = null;
		var error_text = '';
		var val_errors = null;
		var xmlDoc = zXmlDom.createDocument();  // Response text returned as XML
		var xslDoc = zXmlDom.createDocument();  // Optional XSL document
		var response_type = 'text';
		
		// Restore default settings
		jQuery.ajaxctlSetup({
			loading_msg: old_msg
		});
		jQuery.ajaxSettings.block_page = block_page;
		jQuery.ajaxSettings.show_loading = show_loading;
		
		xslDoc.async = false;
		
		// Load XML data from response text
		xmlDoc.async = false;
		
		if (((response_text.substr(0, 1) == '<') && (response_text.substr(response_text.length - 1, 1) == '>')) || (typeof(p_args.xslt_url) != 'undefined'))
		{
			if (response_text.substr(0, 5) == '<' + '?xml')
			{
				xmlDoc.loadXML(response_text);
			}
			else
			{
				xmlDoc.loadXML('<' + '?xml version="1.0" encoding="UTF-8"?' + '>' + response_text);
			}
		}
		
		val_errors = xmlDoc.getElementsByTagName('val_error');  // Load validation error messages into DOM object
		if ((val_errors.length > 0) && (typeof(p_args.form) == 'object'))
		{
			for (var i = 0; i < val_errors.length; i++)
			{
				error_text += val_errors[i].text + '\n';
				fldname = val_errors[i].getAttribute('field');
				if (p_args.form.isFormEngine)
				{
					validated_form_id = p_args.form.getFormID();
				}
				else
				{
					validated_form_id = p_args.form.attr('id');
				}
				sname = '_ajaxctl_val_' + validated_form_id + '_' + fldname;
				errhtml = '<a href="#" onclick="alert(\'' + val_errors[i].text + '\'); return false" style="text-decoration: none; border-width: 0px;">' +
						'<img src="' + jQuery.ajaxSettings.valid_err_img + '" alt="' + val_errors[i].text + '" style="cursor: help; border-width: 0px">' +
						'</a>';
				if (jQuery('#' + sname).length == 0)
				{
					jQuery('#' + validated_form_id + ' input[name="' + fldname + '"],' +
							'#' + validated_form_id + ' textarea[name="' + fldname + '"],' +
							'#' + validated_form_id + ' select[name="' + fldname + '"]')
						.after('<span class="_ajaxctl_val" id="' + sname + '">' + errhtml + '</span>');
				}
				else
				{
					jQuery('#' + sname).html(errhtml).show();
				}
			}
			jQuery('#' + jQuery.ajaxSettings.loading_div).hide();
			jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg').hide();
			alert('The following validation error' + (val_errors.length == 1 ? '' : 's') + ' occurred:\n\n' + error_text);
			
			// If a validation error callback function is defined, call it
			if (typeof(p_args.val_error) == 'function')
			{
				p_args.val_error(response_text);
			}
		}
		else
		{
			error_msgs = xmlDoc.getElementsByTagName('error');  // Load error messages into DOM object
			// Display error messages, if any
			if (error_msgs.length > 0)
			{
				for (var i = 0; i < error_msgs.length; i++)
				{
					error_text += error_msgs[i].text + '\n';
				}
				jQuery('#' + jQuery.ajaxSettings.loading_div).hide();
				jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg').hide();
				alert('The following error' + (error_msgs.length == 1 ? '' : 's') + ' occurred:\n\n' + error_text);
				
				// If an error callback function is defined, call it
				if (typeof(p_args.error) == 'function')
				{
					p_args.error(response_text);
				}
			}
			else
			{
				// Execute user-defined callback function, if specified
				if (typeof(p_args.callback) == 'function')
				{
					/*
					 * An XSLT document can be specified one of two ways:  1) as a
					 * URL in p_args, or 2) within the optional <xslt_url> tag in the
					 * response text XML.  The former overrides the latter.  If
					 * either is specified, then the result of the transformation is
					 * passed to the user-defined callback function.  If neither,
					 * then the response text is passed to the callback function.
					 */
					if (typeof(p_args.xslt_url) == 'undefined')
					{
						xslt_data = xmlDoc.getElementsByTagName('xslt_url');
						if (xslt_data.length > 0)
						{
							// Response text is XML, use XSLT specified in data
							xslDoc.load(xslt_data[0].text);
							response_text = zXslt.transformToText(xmlDoc, xslDoc);
							response_type = 'XML';
						}
						else if ((response_text.substr(0, 1) == '{') || (response_text.substr(0, 1) == '['))
						{
							// Response text is JSON data
							eval('response_text = ' + response_text);
							response_type = 'JSON';
						}
					}
					else
					{
						// Response text is JSON, so ignore p_args.xslt_url
						if (response_text.substr(0, 1) == '{')
						{
							eval('response_text = ' + response_text);
							response_type = 'JSON';
						}
						else
						{
							// Response text is XML, use XSLT specified in p_args.xslt_url
							xslDoc.load(p_args.xslt_url);
							response_text = zXslt.transformToText(xmlDoc, xslDoc);
							response_type = 'XML';
						}
					}
					
					// Pass transformed/evaluated data to callback function
					p_args.callback(response_text, response_type);
				}
				
				if (p_args.form)
				{
					if (p_args.form.isFormEngine)
					{
						//p_args.form.setFormStatus(FRMENG_VIEW_MODE);  // Removed 2008-12-02 to fix menu update bug after delete
						p_args.form.lockForm();
						p_args.form.updateMenu();
					}
				}
			}
		}
	};

	// Used for XMLHttpRequest-related (client-side) errors
	options.error = function(XMLHttpRequest, textStatus, errorThrown)
	{
		alert('AJAX error:\n\ntextStatus: ' + textStatus + '\n\nerrorThrown: ' + errorThrown);
	}
	
	options.dataType = 'text';
	
	jQuery.ajax(options);
};

jQuery.ajaxctlSetup = function(p_args)
{
	var msg_changed = jQuery.ajaxSettings.loading_msg != p_args.loading_msg;
	
	jQuery.ajaxSetup(p_args);
	
	/*
	 *	Set up the "Working..." message that appears while an AJAX request is
	 *	being processed.
	 */
	if ((typeof(jQuery.ajaxSettings.loading_div) != 'null') || msg_changed)
	{
		if (jQuery('#' + jQuery.ajaxSettings.loading_div).length == 0)
		{
			/*
			 *	This division spans the entire page.  It can include a background
			 *	image (if loading_img is set) that will block the user from
			 *	interacting with the page while the request is processing.
			 */
			jQuery('body').prepend('<div id="' + jQuery.ajaxSettings.loading_div + '"></div>');
			jQuery('#' + jQuery.ajaxSettings.loading_div)
				.css('position', 'fixed')
				.css('top', '0px')
				.css('left', '0px')
				.css('right', '0px')
				.css('bottom', '0px')
				.css('z-index', '10000')
				.css('background-image', (jQuery.ajaxSettings.loading_bg ? 'url(' + jQuery.ajaxSettings.loading_bg + ')' : 'none'));
		}
		
		
		/*
		 *	This table has a higher z-index than the division defined above.  It
		 *	contains the optional loading message (loading_msg) and the
		 *	optional loading image (loading_img).
		 */
		if (jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg').length > 0)
		{
			jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg').remove();
		}
		jQuery('body').prepend
		(
			'<table id="' + jQuery.ajaxSettings.loading_div + '_msg"><tr><td>' +
				'<span id="' + jQuery.ajaxSettings.loading_div + '_msg_text">' +
				((typeof(jQuery.ajaxSettings.loading_msg) != 'null') && (jQuery.ajaxSettings.loading_msg != '')
					? jQuery.ajaxSettings.loading_msg + '</span><br>'
					: '') +
				((typeof(jQuery.ajaxSettings.loading_img) != 'null')
					? '<img src="' + jQuery.ajaxSettings.loading_img + '">'
					: '') +
			'</td></td></table>'
		);
		
		jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg td')
			.css('text-align', 'center')
			.css('font-family', 'Arial, sans-serif')
			.css('font-weight', 'bold')
			.css('font-size', '14px')
			.css('padding', '2px')
			.css('border-style', 'none')
			.css('border-width', '1px')
			.css('color', '#000000')
			.css('vertical-align', 'top')
			.css('line-height', '99%');
		jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg')
			.css('display', 'block')
			.css('position', 'absolute')
			.css('width', 'auto')
			.css('margin-left', 'auto')
			.css('margin-right', 'auto')
			.css('border-width', '2px')
			.css('border-style', 'outset')
			.css('z-index', '10001')
			.css('background-color', '#E7E7D7')
			.css('border-color', '#808080')
			.css('color', '#000000')
			.center();
		
		/*
		 *	Set up the elements to display when an AJAX request is in
		 *	progress.
		 */
		jQuery('#' + jQuery.ajaxSettings.loading_div)
			.ajaxStart(function(){
				/*
				 *	If block_page is true, then the optional background image
				 *	(loading_bg) is displayed.  This blocks the user from
				 *	interacting with the rest of the page while the request is
				 *	in progress.
				 */
				if (jQuery.ajaxSettings.block_page)
				{
					jQuery(this).show();
				}
			})
			.ajaxStop(function(){
				jQuery(this).hide();
			})
			.hide();
		jQuery('#' + jQuery.ajaxSettings.loading_div + '_msg')
			.ajaxStart(function(){
				if (jQuery.ajaxSettings.show_loading)
				{
					jQuery(this).show();
				}
			})
			.ajaxStop(function(){
				jQuery(this).hide();
			})
			.hide();
	}
};

/*
 *	The following command sets up default settings and adds the new settings
 *	used by ajaxctl.  The new settings are:
 *
 *		loading_img		Optional.  URL to an image, such as an animated "loader"
 *						image, that is displayed while the AJAX request is in
 *						progress.
 *		loading_bg		Optional.  URL to an image that spans the entire page
 *						to prevent user interaction with the page while the
 *						request is in progress.  This image does not need to be
 *						very large--it is repeated across the division that
 *						uses it.  Typically, this would be a transparent or
 *						semi-transparent image.
 *		loading_msg		Optional.  Message that is displayed above the optional
 *						loading_img.
 *		show_loading	Optional.  If true, then the "loading" division
 *						is displayed while the request is in progress.  If false,
 *						then the division is not displayed.
 *		loading_div		Name of the division that is displayed while an AJAX
 *						request is in progress.
 *		block_page		If true, then the loading_bg is displayed within
 *						loading_div to prevent interaction with the underlying
 *						web page.  This setting can also be specified in
 *						ajaxctl's argument object.
 */
jQuery.ajaxctlSetup({
	type:			'POST',
	loading_img:	'/images/loading.gif',
	loading_bg:		'/images/bo.png',
	loading_msg:	'Working...',
	show_loading:	false,
	loading_div:	'_ajaxctl_working',
	valid_err_img:	'/images/critical.gif',
	block_page:		false,
	expire_maxtime:	60000
});

jQuery(document).ready(function(){
	jQuery.ajaxctlSetup({});
});
