(function () {
	
	function ajaxSubmit(form) {
		if ($(form).hasClass('loading')) {
			return;
		}

		var opts, data, $response, $form;

		$form = $(form);

		opts = $form.data('ajax-form-opts');

		if (opts === undefined) {
			alert('no options passed to onSubmit');
		}
		
		if (opts.beforevalidate) {
			if (!opts.beforevalidate.apply($form)) {
				return false;
			}
		}

		// Disable the form to prevent duplicate submissions
		$form.attr('disabled', 'disabled');
		
		opts = $.extend({
			'url'      : $form.attr('action') + '.json',
			'method'   : $form.attr('method') ? $form.attr('method') : 'post',
			'dataType' : 'json'
		}, opts);
	
		data = {};
		
		if (!$form.isValid()) {
			$(form).removeAttr('disabled');
			return false;
		}

		if (opts.validate) {
			if (!opts.validate.apply($form)) {
				$(form).removeAttr('disabled');
				return false;
			}
		}

		if (opts.beforesubmit) {
			if (!opts.beforesubmit.apply($form)) {
				$(form).removeAttr('disabled');
				return false;
			}
		}

		// Build our data array
		$form	
			.addClass('loading')
			.find('input:text,input:checkbox:checked,input:radio:checked,input[type=email],input[type=hidden],textarea,select').each(
				function () {
					var value = $(this).val();
					if ($(this).hasClass('empty')) {
						value = '';
					}
					data[$(this).attr('name')] = value;
				}
			).end();
	
		if (opts.response) {
			$response = $(opts.response);

			if ($response.size() !== 1) {
				alert("No response target found, but selector was given");
			}
		}

		// Perform our AJAX query
		jQuery.ajax({
			url      : opts.url,
			type     : opts.method,
			dataType : 'json',
			data     : data,
			success  : function (data, textStatus, XMLHttpRequest) {
				$form.removeClass('loading').removeAttr('disabled');
				var div;
				if ($response) {
					// remove old response
					$response
						.removeClass('good bad')
						.find('div').remove();
					if (data.text) {
						$response.append($('<div></div>').text(data.text));
					} else if (data.html) {
						$response.html(data.html);
					}
				}

				if (data.NONCE) {
					$form.find('input[name=NONCE]').val(data['NONCE']);
				}

				// Successful communication with server
				if (data.status) {
					if ($response) {
						$response.addClass('bad');
					}

					// Server indicated failure with our action
					if (jQuery.isFunction(opts.failure)) {
						opts.failure.apply($form, [data]);
					}
				} else {
					if ($response) {
						$response.addClass('good');
					}

					// Server indicated success in our action
					if (jQuery.isFunction(opts.success)) {
						opts.success.apply($form, [data]);
					}
				}
				
				if ($response) {
					$response.slideDown();
				}
			},
			error : function (XMLHttpRequest, textStatus, errorThrown) {
				$form.removeClass('loading').removeAttr('disabled');
				// Error communicating with server
				if (jQuery.isFunction(opts.error)) {
					opts.error(XMLHttpRequest, textStatus, errorThrown);
				}
			},
			complete : function () {
				$form.removeClass('loading').removeAttr('disabled');
			}
		});

	} // ajaxSubmit

	/**
	 * Options
	 * before   - called before the form is submitted
	 * success  - called on successful response from server
	 * failure  - called on failure response from serer
	 * error    - called when there is a communication error with the server
	 * callback - called when the transaction is complete
	 * method   - the method to use for communication (post by default)
	 * event    - the event on which to submit our ajax data (change, submit, blur)
	 */
	$.fn.ajaxForm = function (options) {

		var settings = { 'event' : 'submit' };

		if ($.isFunction(options)) {
			// Single function - bind to success
			settings['success'] = options;
		} else if (arguments.length === 2) {
			if ($.isString(arguments[0])) {
				settings[arguments[0]] = arguments[1];
			} else if ($.isFunction(arguments[0]) && $.isFunction(arguments[1])) {
				$.extend(settings, { 'success' : arguments[0], 'failure' : arguments[1] });
			}
		} else if ($.isPlainObject(options)) {
			$.extend(settings, options);
		}

		// Make sure we have an array of events
		if (!$.isArray(settings['event'])) {
			settings['event'] = [settings['event']];
		}

		$(this)
			.addClass('ajax-form')
			.data('ajax-form-opts', settings)
			.append($('<div class="load"><div></div></div>'));
	
		$(this).bind(settings['event'].join(' '), function(event) {
			event.preventDefault();
			ajaxSubmit(this);
			return false;
		});

		return this;
	};

})(jQuery);

