	$("document").ready(function() {
		$(":input[validate]").bind("change.validate keyup.validate click.validate blur.validate focus.validate",function() {
			var id = $(this).attr("id");
			var state = "valid";
			var val = $(this).val();
			
			if (val == "")
			{
				if ($(this).attr("required") == "true")
				{
					state = "required";
				}
				else
				{
					$(".validation_status[field='" + id + "']").html('');
					$(this).attr("state","valid");
					return;
				}
			}
			
			if ($(this).attr("match"))
			{
				if (val != $("#" + $(this).attr("match")).val())
				{
					state = "unmatched";
				}
			}
			
			if ($(this).attr("min"))
			{
				if (val.length < $(this).attr("min"))
				{
					state = "too_short";
				}
			}
			
			if ($(this).attr("max"))
			{
				if($(this).attr("show_length") == "true")
				{
					$(".desc_length").html("Length: "+val.length);
				}
				if (val.length > $(this).attr("max"))
				{
					state = "too_long";
				}
			}
			
			if ($(this).attr("numeric"))
			{
				if (isCharacter(val))
				{
					state = "non_numeric";
				}
			}
			
			if ($(this).attr("validate_function") && val)
			{
				if (!call_function($(this).attr("validate_function"),val))
				{
					if($(this).attr("validate_function") == 'check_alpha')
					{
						state = "not_alpha";
					}
					else if($(this).attr("validate_function") == 'check_alphanum')
					{
						state = "not_alphanumeric";
					}
					else if($(this).attr("validate_function") == 'check_address')
					{
						state = "not_address";
					}
					else
					{	
						state = "invalid";
					}
				}
			}
			
			$(this).attr("state",state);

			if ($(this).attr("match"))
			{
				if ($("#" + $(this).attr("match")).attr("state") != state)
				{
					$("#" + $(this).attr("match")).change();
				}
			}

			switch(state)
			{
				case "required":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Required" title="Required" align="top" />');
					break;
				case "invalid":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Not Valid" title="Not Valid" align="top" />');
					break;
				case "unmatched":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="No Match" title="No Match" align="top" />');
					break;
				case "valid":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/valid.png" alt="Thankyou" title="Thankyou" align="top" />');
					break;
				case "non_numeric":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Non Numeric" title="Non Numeric" align="top" />');
					break;
				case "too_short":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Too Short" title="Too Short" align="top" />');
					break;
				case "too_long":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Too Long" title="Too Long" align="top" />');
					break;
				case "not_alpha":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Not Letters Only" title="Not Letters Only" align="top" />');
					break;
				case "not_alphanumeric":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Not Alphanumeric" title="Not Alphanumeric" align="top" />');
					break;
				case "not_address":
					$(".validation_status[field='" + id + "']").html('<img src="/images/site/error.png" alt="Alphanumeric or commas only" title="Alphanumeric or commas only" align="top" />');
					break;
			}
		});
		
		// Validate all items now
		$(":input[validate]",this).each(function() { $(this).change(); });
		
		$("form").submit(function() {
			var validated = true;
			$(":input[validate]",this).each(function() {
				$(this).change();
				if ($(this).attr("state") != "valid")
				{
					$(this).validated = false;
				}
			});
			if (validated)
			{
				return true;
			}
			else
			{
				$.msgBox("Errors with form","There are errors with your form, please review and re-submit",{ OK: null });
				return false;
			}
		});
	});
	
	function call_function(function_name)
	{
		var args = [];
		var gthis = (function(){return this;})();
		for (var i = 1; i < arguments.length; i++)
		{
			args[i - 1] = arguments[i];
		}
		return gthis[function_name].apply(gthis,args);
	}
	
    function check_alpha(e)
    {
    	if(e.optional == true && e.value=="")
        {
    		return "";
        }

    	var mypattern = /^[a-zA-Z\s]+$/;
    	var result = e.match(mypattern);
    	if(result == null)
    	{
    		return false;
    	}
    	else
    	{
    		return true;
    	}
    }
	
	function check_alphanum(e)
    {
    	if(e.optional == true && e.value=="")
        {
    		return "";
        }

    	var mypattern = /^[a-zA-Z0-9\s]+$/;
    	var result = e.match(mypattern);
    	if(result == null)
    	{
    		return false;
    	}
    	else
    	{
    		return true;
    	}
    }
	
	function check_address(e)
    {
    	if(e.optional == true && e.value=="")
        {
    		return "";
        }

    	var mypattern = /^[a-zA-Z0-9-,'\s]+$/;
    	var result = e.match(mypattern);
    	if(result == null)
    	{
    		return false;
    	}
    	else
    	{
    		return true;
    	}
    }
	
	function check_string(e)
    {
    	if(e.optional == true && e.value=="")
        {
    		return "";
        }

    	var mypattern = /^[a-zA-Z0-9\-\.,&\(\)'\/\s]+$/;
    	var result = e.match(mypattern);
    	if(result == null)
    	{
    		return false;
    	}
    	else
    	{
    		return true;
    	}
    }
	
	function check_email(email)
	{
		var isvalid = true;
		var atIndex = email.indexOf('@');
		
		if(atIndex == '')
		{
			isvalid = false;
		}
		else
		{
			var local = email.substr(0,atIndex);
			var domain = email.substr((atIndex + 1));
			var locallen = local.length;
			var domainlen = domain.length;
			
			if(locallen < 1 || locallen > 64)
			{
				isvalid = false; // checks length before @
			}
			else if(domainlen < 1 || domainlen > 255)
			{
				isvalid = false; // checks length after @
			}
			else if(local.substr(0,1) == '.' || local.substr((atIndex - 1)) == '.')
			{
				isvalid = false; // makes sure local doesn't start or end in a dot
			}
			else if(domain.substr(0,1) == '.' || domain.substr((domainlen - 1)) == '.')
			{
				isvalid = false; // makes sure domain doesn't start or end in a dot
			}
			else if(local.match(/\.\./) || domain.match(/\.\./))
			{
				isvalid = false; // makes sure there aren't 2 dots in a row in local or the domain
			}
			else if(!domain.match(/^[A-Za-z0-9\-\.]+$/))
			{
				isvalid = false; // checks for invalid characters in the domain
			}
			var amended_local = local.replace('\\\\','');
			if(!amended_local.match(/^(\\.|[A-Za-z0-9!#%&`_=\/$\'*+?^{}|~.-])+$/))
			{
				// character not valid in local part unless local part is quoted
				if(!amended_local.match(/^"(\\\\"|[^"])+"$/))
				{
					isvalid = false; 
				}
			}
		}
		
		return isvalid;
		
		//var mypattern = /^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z0-9_\-\.]+$/; 
		//var result = email.match(mypattern);
		//if(result == null)
		//{
			//return false;
		//}
		//else
		//{
			//return true;
		//}
	}

	function check_phone(number)
	{
		// attempts to match phone number.
		var mypattern = /^[0|\+][0-9 ]{7,}$/;

		var result = number.match(mypattern);

		if(result == null)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	function check_postcode(postcode)
	{
		// attempts to match postcode.
		var mypattern = /^[A-PR-UWYZa-pr-uwyz]{1,2}[0-9][ABEHMNPRV-Yabehmnprv-y0-9]? ?[0-9]{1}[ABD-HJLNP-UW-Zabc-hjlnp-uw-z]{2}$/;

		var result = postcode.match(mypattern);

		if(result == null)
		{
			return false;
		}
		else
		{
			return true;
		}
	}
