(function($){
	$.fn.form = function(settings) {

		var defaults = {
			id:                '',
			type:              'normal',
			data:              {},
			rules:             {},
			success_func:      null,
			error_func:        null,
			error_messages:    [],
			success_messages:  [],
			show_processing:   true,
			rich_text_ids:     []
		};
		
		var settings = $.extend(defaults, settings);
	
		return this.each(function() {
			this.settings = settings;
			$(this).prepend('<div id="'+this.settings.id+'_messages_success" class="form_messages_success"></div>');
			$(this).prepend('<div id="'+this.settings.id+'_messages_error" class="form_messages_error"></div>');
			$(this).prepend('<div id="'+this.settings.id+'_processing" class="form_processing" style="display: none; text-align: center;"><img src="images/skins/'+mx_skin+'/loading_bar.gif" /></div>');
			this.error_messages_div   = $('#'+this.settings.id+'_messages_error');
			this.success_messages_div = $('#'+this.settings.id+'_messages_success');
			$(this).bind('submit', attempt_submit);
			display_error_messages.call(this, settings.error_messages);
			display_success_messages.call(this, settings.success_messages);
		});

		function display_error_messages(messages)
		{
			if(typeof messages != 'object' || messages.length == 0) return;

			var icon_url = 'images/skins/'+mx_skin+'/icons/error.png';

			// show error messages
			var html = '';
			for(var i=0;i<messages.length;i++)
			{
				html += '<img src="'+icon_url+'" /> '+messages[i]+'<br />';
			}
			this.success_messages_div.hide();
			this.error_messages_div.html(html);
			this.error_messages_div.fadeIn('fast');
		}

		function display_success_messages(messages)
		{
			if(typeof messages != 'object' || messages.length == 0) return;

			var icon_url = 'images/skins/'+mx_skin+'/icons/tick.png';

			// show success messages
			var html = '';
			for(var i=0;i<messages.length;i++)
			{
				html += '<img src="'+icon_url+'" /> '+messages[i]+'<br />';
			}

			// show success
			this.error_messages_div.hide();
			this.success_messages_div.html(html);
			this.success_messages_div.fadeIn('fast');
		}

		function attempt_submit()
		{
			// must trigger a save on each rich text editor
			if(this.settings.rich_text_ids.length > 0)
			{
				for(var i=0;i<this.settings.rich_text_ids.length;i++)
				{
					tinyMCE.execCommand('mceFocus', false, this.settings.rich_text_ids[i]);
					tinyMCE.triggerSave();
				}
			}
			
			var errors = [];
			for(var field in this.settings.rules)
			{
				var rules = this.settings.rules[field];
				for(var rule_name in rules)
				{
					if(eval('typeof '+rule_name) == 'function')
					{
						if(!eval(rule_name)(this.settings.id+'_'+field+'_input', $('#'+this.settings.id+'_'+field+'_input').val(), rules[rule_name].value))
						{
							errors.push(rules[rule_name].message);
						}
					}
				}
			}

			// if all checks are good, send ajax request
			if(errors.length > 0)
			{
				display_error_messages.call(this, errors);
			}
			else
			{
				if(this.settings.type == 'normal')
				{
					return true;
				}
				
				var this_form = this;
				
				// add form fields to database
				var data = $(this).serialize();

				for(key in this.settings.data)
				{
					data += '&'+key+'='+this.settings.data[key];
				}
				data += '&is_form_submit=1';

				$(this).disable('readonly');
				if(this.settings.show_processing)
				{
					$('#'+this.settings.id+'_processing').show();
				}
				var this_form = this;

				// make ajax call
				ajax_request(data, {
					'success': function(response) {
						// hide errors
						this_form.error_messages_div.hide();

						if(typeof response.success_messages == 'object')
						{
							display_success_messages.call(this_form, response.success_messages);
						}

						if(this_form.settings.show_processing)
						{
							$('#'+this_form.settings.id+'_processing').hide();
						}
						$(this_form).enable('readonly');
						
						if(eval('typeof '+this_form.settings.success_func) == 'function')
						{
							eval(this_form.settings.success_func)(response);
						}
					},
					'error': function(response) {
						// hide success
						this_form.success_messages_div.hide();

						if(typeof response.error_messages == 'object')
						{
							display_error_messages.call(this_form, response.error_messages);
						}
						if(this_form.settings.show_processing)
						{
							$('#'+this_form.settings.id+'_processing').hide();
						}
						$(this_form).enable('readonly');
					}
				});
			}

			return false;
		}
		
		function confirm(field, value)
		{
			var confirm_field = field.replace('_input', '_confirm_input');
			if($('#'+confirm_field).val() != value)
			{
				return false;
			}
			return true;
		}
		
		function required(field, value)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			var tmp_val = value;
			tmp_val = tmp_val.replace(/ /ig,"");
			if(tmp_val == '' || tmp_val == null)
			{
				return false;
			}
			return true;
		}
		function len_gt(field, value, len)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			if(value.length > len)
			{
				return true;
			}
			return false;
		}
		function min_length(field, value, len)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			if(value.length >= len)
			{
				return true;
			}
			return false;
		}
		function len_eq(field, value, len)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			if(value.length == len)
			{
				return true;
			}
			return false;
		}
		function len_lt(field, value, len)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return true;
			}

			if(value.length < len)
			{
				return true;
			}
			return false;
		}
		function max_length(field, value, len)
		{
			if(typeof value == 'undefined' || value == null || value == '')
			{
				return true;
			}
			
			if(value.length <= len)
			{
				return true;
			}
			return false;
		}
		function valid_email(field, value)
		{
			if(typeof value == 'undefined' || value == null || value == '')
			{
				return true;
			}

			var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
			if(filter.test(value))
			{
				return true;
			}
			return false;
		}
		function valid_emails(field, value)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return true;
			}

			var emails = value.split(',');
			var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
			for(i in emails)
			{
				var email = emails[i].trim();
				if(!filter.test(email))
				{
					return false;
				}
			}
			return true;
		}
		function valid_domain(field, value)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			var filter = /^(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
			if(filter.test(value))
			{
				return true;
			}
			return false;
		}
		function valid_username(field, value)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			var filter = /[^a-zA-Z0-9\-]/;
			if(filter.test(value))
			{
				return false;
			}
			return true;
		}
		function valid_date(field, value)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			// Are there any invalid characters?
			var filter = /[^0-9\-]/;
			if(filter.test(value))
			{
				return false;
			}
		
			var date = value.split('-');
			if(date.length != 3)
			{
				return false;
			}

			// if year is 2 digits (ex: '08, '97), make it 4 digits
			if(date[0] > 10 && date[0] < 100)
			{
				var new_year = parseInt(date[0]) + 1900;
				$('#'+field).val($('#'+field).val().replace(value,new_year+'-'+date[1]+'-'+date[2]));
			}
		
			var filter  = /^[0-9]{1,2}$/;
			var filter2 = /^[0-9]{4}$/;
			
			if(filter2.test(date[0]) && filter.test(date[1]) && filter.test(date[2]))
			{
				return true;
			}
			return false;
		}
		function valid_time(field, value)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			var time = value.split(':');
			if(time.length != 3)
			{
				return false;
			}

			var filter  = /^[0-9]{1,2}$/;

			if(filter.test(time[0]) && filter.test(time[1]) && filter.test(time[2]))
			{
				return true;
			}
			return false;
		}
		function valid_date_time(field, value)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			// Are there any invalid characters?
			var filter = /[^0-9\-: ]/;
			if(filter.test(value))
			{
				return false;
			}

			var parts = value.split(' ');
			var date  = parts[0];
			var time  = parts[1];

			// is date part valid
			if(!valid_date(field, date))
			{
				return false;
			}

			// is time part valid
			if(!valid_time(field, time))
			{
				return false;
			}
			
			return true;
		}
		function contains_only(field, value, regex)
		{
			if(typeof value == 'undefined' || value == null)
			{
				return false;
			}

			var filter = new RegExp("[^" + regex + "]");
			
			if(filter.test(value))
			{
				return false;
			}
			return true;
		}
		function make_lowercase(field, value)
		{
			$('#'+field).val(value.toLowerCase());
			return true;
		}
	};
})(jQuery);