/*
	ajaxform.js
	This class will take a standard self-posting form and ajaxify it.
	Author: Barry Jones
*/
var cAjaxForm = function(o_form, o_onsuccess){

	//////////////////////////////////////////////////
	// Member variables
	//////////////////////////////////////////////////
	this.form 					= $j(o_form);
	this.form_id				= null;
	this.formmessage			= null;
	this.ajaxindicator			= null;
	this.onsuccess				= o_onsuccess;

	//////////////////////////////////////////////////
	// Private methods
	//////////////////////////////////////////////////


	//////////////////////////////////////////////////
	// Public methods
	//////////////////////////////////////////////////

	// Handle the form submission
	this.submit = function(e)
	{
		try
		{
			e.preventDefault();

			// Show working indicator
			this.showFormMask(true);

			// Post form to the server
			$j.ajax({
				'url'		: document.location.href,
				'type'		: 'POST',
				'data'		: this.form.serialize(),
				'dataType'	: 'json',
				'cache'		: false,
				'error'		: function(o_xhr, v_status, o_error)
				{
					this.showFormMask(false);
					alert('The server did not respond to your request, please try again.');
				}.bind(this),
				'success'	: function(o_data)
				{
					if (o_data.success)
					{

						// Show the message
						this.showMessage(o_data.message);

						// Hide the contact form
						this.showFormMask(false);

						// Any custom onsuccess handler specified?
						if (this.onsuccess)
						{
							this.onsuccess(this);
						}

					}
					else
					{

						// Show the message
						this.showMessage(o_data.message);

						// Remove all previous validation highlights
						this.form.find(':input').removeClass('validation-failed')
							.parent().find('span.validation-advice').remove();

						// Highlight the error fields
						for (var v_fldname in o_data.errors)
						{

							var v_errormsg = o_data.errors[v_fldname];
							var o_fld = this.form.find('[name="' + v_fldname + '"]');
							if (o_fld && (o_fld.length > 0))
							{

								// Add an error classname and show the error message above the element
								o_fld.addClass('validation-failed').parent().prepend(
									$j('<span/>').addClass('validation-advice').html(v_errormsg)
								);

							}
						}

						// Hide ajax indicator
						this.showFormMask(false);

						// Set the focus to the first error field
						this.form.find(':input').each(function(){
							var $this = $j(this);
							if (o_data.errors[$this.attr('name')])
							{
								$this.focus();
								return false;
							}
						});

					}
				}.bind(this)
			})

			return false;
		}
		catch(e)
		{
			// TODO: Error handling class?
			this.showFormMask(false);
			alert("An error occurred while submitting this form: " + e);
		}

		return this; // Call-chaining

	} // this.submit()

	// Show the general form message
	this.showMessage = function(v_msg)
	{

		// Show the message
		this.formmessage.html(v_msg).show();

		return this;

	} // this.showMessage()

	// Show the form ajax indicator
	this.showFormMask = function(v_show)
	{
		if (v_show)
		{
			// Size and show
			this.ajaxindicator.width(this.form.outerWidth(true) + 10).height(this.form.outerHeight(true) + 10);
			this.ajaxindicator.show();
			this.form.hide();
		}
		else
		{
			this.form.fadeIn('fast', function(){this.ajaxindicator.hide()}.bind(this));
		}
		return this;

	} // this.showMessage()

	//////////////////////////////////////////////////
	// Constructor code
	//////////////////////////////////////////////////
	try
	{

		// Verify that we have a form element
		if ((this.form.length == 0) || (this.form.get(0).tagName.toLowerCase() != 'form')){
			throw ("Invalid form element.");
		}
		this.form_id = this.form.attr('id');

		// If the message tag does not exist, create it
		this.formmessage = $j('#statusmessage');
		if (this.formmessage.length == 0)
		{
			this.formmessage = this.form.parent().prepend(
				$j('<p/>').attr({'id': 'statusmessage'}).addClass('formmessage')
			);
		}

		// Create the form ajax indicator
		this.ajaxindicator = $j('<div/>')
			.addClass('formajaxmask')
			.width(this.form.outerWidth(true) + 10)
			.height(this.form.outerHeight(true) + 10)
			.css('opacity', 0.9)
			.html('working...');
		this.form.parent().prepend(this.ajaxindicator.hide());

		// Add a hidden field to let the serverside know we are using ajax
		var o_isajax = $j('<input/>').attr({
			'type'		: 'hidden',
			'id'		: this.form_id + '_isajax',
			'name'		: 'isajax'
		}).val(1);
		if (this.form.find('fieldset').length == 0)
		{
			// Add the field to the form element
			this.form.prepend(o_isajax);
		}
		else
		{
			// Add the field to the fieldset element (standards compliance - fieldset is required element)
			this.form.find('fieldset').eq(0).append(o_isajax);
		}

		// Override the form submit
		this.form.submit(this.submit.bind(this));

	}
	catch(e)
	{
		// TODO: Error handling class?
		alert("An error occurred while converting the form to ajax: " + e);
	}

} // cAjaxForm
