(function($){
	$.fn.form = function(settings) {

		var defaults = {
			id              : '',
			type            : 'normal',
			data            : {},
			rules           : {},
			success_func    : null,
			error_func      : null,
			errors          : [],
			messages        : [],
			show_processing : true,
			rich_text_ids   : [],
			instructs       : {}
		};
		
		var settings = $.extend(defaults, settings);

		return this.each(function() {
			this.settings = settings;

			// create info div
			this.info_div = $('<div></div>')
			.addClass('form_info')
			.append(
				$('<div></div>')
				.addClass('errors')
				.hide()
			)
			.append(
				$('<div></div>')
				.addClass('messages')
				.hide()
			)
			.append(
				$('<div></div>')
				.addClass('processing')
				.hide()
			)
			.prependTo($(this));

			$(this).append(
				$('<input type="hidden" name="is_form_submit" value="1" />')
			);

			$(this).bind('submit', attempt_submit);
			display_errors.call(this, settings.errors);
			display_messages.call(this, settings.messages);

			// field instructs
			for(var field in this.settings.instructs)
			{
				$('#'+this.settings.id+'_'+field+'_input').input_instruct(this.settings.instructs[field]);
			}
		});

		function display_errors(messages)
		{
			if(typeof messages != 'object' || messages.length == 0) return;

			var icon_url = 'skins/'+moxyfy.skin+'/images/icons/error.png';

			// show error messages
			var html = '';
			for(var i=0;i<messages.length;i++)
			{
				html += '<img src="'+icon_url+'" /> '+messages[i]+'<br />';
			}
			$('.messages', this.info_div).hide();
			$('.errors', this.info_div)
			.html(html)
			.fadeIn('fast')
		}

		function display_messages(messages)
		{
			if(typeof messages != 'object' || messages.length == 0) return;

			var icon_url = 'skins/'+moxyfy.skin+'/images/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
			$('.errors', this.info_div).hide();
			$('.messages', this.info_div)
			.html(html)
			.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)
				{
					// get value of field
					var value = $('#'+this.settings.id+'_'+field+'_input').val();
					// if field is an instruct and the default instruct text is present, consider the value blank
					if(typeof this.settings.instructs[field] != 'undefined' && this.settings.instructs[field] == value)
					{
						value = '';
					}

					if(eval('typeof '+rule_name) == 'function')
					{
						if(!eval(rule_name)(this.settings.id+'_'+field+'_input', value, rules[rule_name].value))
						{
							errors.push(rules[rule_name].message);
						}
					}
				}
			}

			// if all checks are good, send ajax request
			if(errors.length > 0)
			{
				display_errors.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)
				{
					$('.processing', this.info_div).show();
				}
				var this_form = this;

				// make ajax call
				$.ajax_request({data : data, success : function(response) {
					// hide errors
					$('.errors', this_form.info_div).hide();

					if(typeof response.messages == 'object')
					{
						display_messages.call(this_form, response.messages);
					}

					if(this_form.settings.show_processing)
					{
						$('.processing', this_form.info_div).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
					$('.messages', this_form.info_div).hide();

					if(typeof response.errors == 'object')
					{
						display_errors.call(this_form, response.errors);
					}
					if(this_form.settings.show_processing)
					{
						$('.processing', this_form.info_div).hide();
					}
					$(this_form).enable('readonly');
				}});
			}

			return false;
		}
		
		function agree(field, value)
		{
			if($('#'+field).attr('checked'))
			{
				return true;
			}
			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 || value == '')
			{
				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 || value == '')
			{
				return true;
			}

			if(value.length > len)
			{
				return true;
			}
			return false;
		}
		function min_length(field, value, len)
		{
			if(typeof value == 'undefined' || value == null || value == '')
			{
				return true;
			}

			if(value.length >= len)
			{
				return true;
			}
			return false;
		}
		function len_eq(field, value, len)
		{
			if(typeof value == 'undefined' || value == null || value == '')
			{
				return true;
			}

			if(value.length == len)
			{
				return true;
			}
			return false;
		}
		function len_lt(field, value, len)
		{
			if(typeof value == 'undefined' || value == null || value == '')
			{
				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($.is_valid_email(value))
			{
				return true;
			}
			return false;
		}
		function valid_emails(field, value)
		{
			if($.is_valid_emails(value))
			{
				return true;
			}
			return false;
		}
		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);
