(function($)
{
	$(document).ready(function()
	{
		$('input.error:not(.input_validation)').live('click', function() { $(this).removeClass('error'); });
		$('input.error:not(.input_validation)').live('keyup', function() { $(this).removeClass('error'); });
	
		$('.input_validation:not(input[type="file"])', this).live('keyup', function() { $(this).validate(true); });
		$('.input_validation:not(input[type="file"])', this).live('click', function() { $(this).validate(true); });
		
		$.add_initialize(function() {
			$('input.error:not(.input_validation)').blur(function() { $(this).removeClass('error'); });
			$('.input_validation:not(input[type="file"])').blur(function() { $(this).validate(true); });
		});
	});

	jQuery.validation = {
	
		validate_input: function()
		{
			var validate = true;
			var value = $(this).get_input_value();
			var can_be_empty = !$(this).hasClass('required');
		
			var special_type = false;
			
			if ($(this).attr('type') == 'file')
			{
				validate = $.validation.validate_file(this, value, can_be_empty);
				if (validate !== true)
					return validate;
				special_type = true;
			}
			else
			{
				for (var type in input_classes)
				{
					if ($(this).hasClass(type))
					{
						validate = input_classes[type](value, can_be_empty);
						if (validate !== true)
							return validate;
						
						special_type = true;
						break;
					}
				}
			}
			
			if (!special_type && !can_be_empty && value == "")
				return 'required';
			
			if ($(this).hasClass('required_or'))
			{
				if (!$('.'+$(this).parent().attr('class')+' .input_validation', $(this).closest('form')).input_not_empty(true))
					return 'required';
			}
			
			if ($(this).hasClass('required_match'))
			{
				if (value != $('*[name="'+$(this).parent().attr('class')+'"]', $(this).closest('form')).get_input_value())
					return 'match';
			}
			
			return true;
		},
		
		validate_email: function(email, can_be_empty)
		{
			var emailRegex = /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/;
			if (!emailRegex.test(email))
			{
				if (email != "")
					return 'invalid';
				if (!can_be_empty)
					return 'required';
			}
			return true;
		},
		
		validate_date: function(date, can_be_empty)
		{
			var dateRegex = /^[0-3][0-9]\/(0|1)[0-9]\/[1-2][0-9][0-9][0-9]$/;
			var dateSplit = date.split('/');
			var dateValClass = new Date(dateSplit[2],dateSplit[1]-1,dateSplit[0]);
			if (!dateRegex.test(date) || dateValClass.getFullYear() != dateSplit[2] ||
				dateValClass.getMonth() != dateSplit[1] - 1 || dateValClass.getDate() != dateSplit[0])
			{
				if (date != "__/__/____" && date != "")
					return 'invalid';
				if (!can_be_empty)
					return 'required';
			}
			return true;
		},
		
		validate_time: function(time, can_be_empty)
		{
			var timeSplit = time.split(':');
			var timeRegex = /^[0-2][0-9]:[0-5][0-9]$/;
			if (!timeRegex.test(time) || timeSplit[0] > 23)
			{
				if (time != "__:__" && time != "")
					return 'invalid';
				if (!can_be_empty)
					return 'required';
			}
			return true;
		},
		
		validate_postcode: function(postcode, can_be_empty)
		{
			var postcodeRegex = /^[0-9][0-9][0-9][0-9] [A-Za-z][A-Za-z]$/;
			if (!postcodeRegex.test(postcode))
			{
				if (postcode != "____ __" && postcode != "")
					return 'invalid';
				if (!can_be_empty)
					return 'required';
			}
			return true;
		},
		
		validate_phone: function(phone, can_be_empty)
		{
			var phoneRegex = /^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$/;
			if (!phoneRegex.test(phone))
			{
				if (phone != "__________" && phone != "")
					return 'invalid';
				if (!can_be_empty)
					return 'required';
			}
			return true;
		},
		
		validate_password: function(password, can_be_empty)
		{
			if (password.length < 6)
			{
				if (password != "")
					return 'invalid';
				if (!can_be_empty)
					return 'required';
			}
			return true;
		},
		
		validate_file: function(file, value, can_be_empty)
		{
			if (value == "")
			{
				if (!can_be_empty)
					return 'required';
				return true;
			}
		
			var name = $(file).attr('name');
			var extensions = $('input[name="allowed_extensions_'+name+'"]',	$(file).closest('form'));
			
			if ($(extensions).length == 1)
			{
				var extension = $.utils.getFileExtension(value);
				var possibleExtensions = $(extensions).val().split(',');
				if ($.grep(possibleExtensions, function(ext) { return ($.trim(ext) == extension); }).length == 0)
					return 'invalid';
			}
			return true;
		},
		
		texts: {
			error_dialog_title: 'Incorrect input',
			error_dialog_msg:	'Not all data has been input correctly. Please fix the erroneous input.'
		}
	
	};
	
	var input_classes =
	{
		input_email: 	jQuery.validation.validate_email,
		input_date: 	jQuery.validation.validate_date,
		input_time: 	jQuery.validation.validate_time,
		input_postcode: jQuery.validation.validate_postcode,
		input_phone: 	jQuery.validation.validate_phone,
		input_password: jQuery.validation.validate_password
	};
	
	jQuery.add_custom_validation = function(input_class, func)
	{
		if (!input_classes[input_class])
			input_classes[input_class] = func;
	};
	
	$.fn.get_input_value = function()
	{
		if ($(this).length > 1)
		{
			var arr = $.makeArray(this);
			arr = $.map(arr, function(input, index) {
				return $(input).get_input_value();
			});
			return arr;
		}
		if ($(this).getTagName() == 'textarea')
		{
			if ($.fn.get_wymeditor)
			{
				var wym = $(this).get_wymeditor();
				if (wym) {
					return $.trim(wym.text());
				}
			}
			return $.trim($(this).val());
		}
		if ($(this).getTagName() == 'input')
		{
			switch ($(this).attr('type'))
			{
				default:
					return $.trim($(this).val());
				
				case 'file':
				case 'password':
					return $(this).val();
				
				case 'radio':
					var checked = $('input[name="'+$(this).attr('name')+'"]:checked', $(this).closest('form'));
					if ($(checked).length == 1)
						return $(checked).val();
					return '';
			}
		}
		return this;
	};
	
	$.fn.input_not_empty = function(any)
	{
		var items = $.grep(this.get(), function(input) {
		
			var value = $(input).get_input_value();
			
			if ($(input).hasClass('input_date'))
				return (value != "__/__/____" && value != "");
			if ($(input).hasClass('input_time'))
				return (value != "__:__" && value != "");
			if ($(input).hasClass('input_postcode'))
				return (value != "____ __" && value != "");	
			if ($(input).hasClass('input_phone'))
				return (value != "__________" && value != "");
			
			return value != "";
		
		});
		
		if (any) {
			return $(items).length > 0;
		}
		return ($(items).length == $(this).length);
	};
	
	$.fn.get_validate = function(verbose, required_or)
	{
		if ($(this).length == 0)
			return undefined;
	
		var first = $(this).eq(0);
		var validation = true;
		
		if (!required_or && $(first).hasClass('required_or'))
		{
			if (verbose)
			{
				$('.'+$(first).parent().attr('class')+' .input_validation', 
					$(first).closest('form')).each(function() {
					
					if (this !== first) {
						$(this).get_validate(verbose, true);
					}
				});
			}
			
			validation = $(first).get_validate(verbose, true);
			if (validation !== true) {
				return validation;
			}
		}
	
		validation = $.validation.validate_input.apply(first);
		if (!verbose) {
			return validation;
		}
		
		var parent = $(first).closest('.input_validation_parent');
		if (validation !== true)
		{
			$(first).addClass('error');
		
			if ($(parent).length == 1)
			{
				if ($('.error_message_'+validation+'.error_visible', parent).length == 0)
				{
					if ($('.error_message.error_visible:not(.error_message_'+validation+')', parent).length > 0)
					{
						$('.error_message.error_visible:not(.error_message_'+validation+')', parent).removeClass('error_visible').hide();
						$('.error_message_'+validation, parent).addClass('error_visible').show();
					}
					else
					{
						$('.error_message_'+validation, parent).addClass('error_visible').fadeIn('fast');
					}
				}
				$('.validation_image img', parent).attr('src', '/img/layout/validation_failed.png');
			}
		}
		else
		{
			$(first).removeClass('error');
			
			if ($(parent).length == 1)
			{
				$('.error_message.error_visible', parent).removeClass('error_visible').fadeOut('fast');
				$('.validation_image img', parent).attr('src', '/img/layout/validation_passed.png');
			}
		}
		
		return validation;
	};
	
	$.fn.validate = function(verbose)
	{
		if ($(this).length == 0)
			return true;
	
		switch ($(this).getTagName())
		{
			default:
				return ($.grep(this.get(), function(input) {
					return ($(input).get_validate(verbose) !== true);
				}).length == 0);
			
			case 'form':
				return ($.grep(this.get(), function(form) {
					
					var succeed = $('.input_validation', form).validate(verbose);
					if (!succeed && $.dialogutils && verbose)
					{
						$.dialogutils.message_dialog(
							$.validation.texts.error_dialog_title, $.validation.texts.error_dialog_msg);
					}
					return succeed;
				
				}).length == $(this).length);
		}
		
		return undefined;
	}
	
})(jQuery);
