(function() {
	var s = {
		defaultError: "This is a required field",
		radioError: "You must choose one of these options",
		checkError: "This box must be ticked",
		emailError: "This must be a valid email address",
		phoneError: "This must be a valid phone number",
		postError: "This must be a valid postcode"
	},
	regs = {
		required: /required/i,
		classEmail: /email/i,
		classPhone: /phone/i,
		classPcode: /postcode/i,
		email: /([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})/,
		phone: /[0-9\+]/,
		postcode: /(^[A-Z]{1,2}[0-9]{1,2})(\s|)([0-9][A-Z]{2}$)/i,
		inputs: /(hidden|submit|image|button|reset)/i
	},
	createError = function(elm,msg){
		removeError(elm);
		var errorAlert = $(document.createElement("span")).addClass("formError"),
		position = $(elm).position(),
		leftVal = position.left + $(elm).outerWidth() + 10,
		topVal = position.top,
		errorHtml = msg;
		errorAlert.html(errorHtml).css({"top":topVal,"left":leftVal}).insertAfter(elm);
	},
	removeError = function(elm) {
		$(elm).next(".formError").remove();
	},
	radioObj = {},
	check = function(formArray){
		var $return = true,
		len = formArray.length;
		while (len--) {
			var isValid = true,
			errorMsg = "",
			elm = formArray[len],
			className = elm.getAttribute("class"),
			tagName = elm.nodeName.toLowerCase(),
			inpType = elm.getAttribute("type"),
			inpValue = elm.value;
			if(inpValue) {inpValue = inpValue.trim() };
			if(className) { className = className.toLowerCase(); };
			if(inpType) { inpType = inpType.toLowerCase(); };
			
			if(!regs.inputs.test(inpType) && tagName != "fieldset" && regs.required.test(className)) {
			
				if(inpType == "text" || tagName == "textarea") {
					// perform live checking
					elm.onkeyup = function(){
						check([this]);
					};
					if(inpValue == '' || inpValue == null) {
						$return = isValid = false;
						errorMsg = s.defaultError
					} else if(regs.classEmail.test(className)) {
						$return = isValid = regs.email.test(inpValue);
						errorMsg = s.emailError
					} else if(regs.classPhone.test(className)) {
						$return = isValid = regs.phone.test(inpValue);
						errorMsg = s.phoneError
					} else if(regs.classPcode.test(className)) {
						$return = isValid = regs.postcode.test(inpValue);
						errorMsg = s.postError
					};
					
				} else if (inpType == "radio") {
					elm.onclick = function(){
						check([this]);
					};
					var group = elm.getAttribute("name");
					if(group) {
						group = group.toLowerCase();
						if(typeof radioObj[group] === "undefined") {
							radioObj[group] = {
								firstElement: elm,
								valArray: []
							};
						};
						radioObj[group].valArray.push(elm.checked);
					};
				} else if (inpType == "checkbox") {
					elm.onclick = function(){
						check([this]);
					};
					if(!elm.checked) {
						$return = isValid = false;
						errorMsg = s.checkError
					};
				};
				if(isValid) { removeError(elm); }
				else { createError(elm,errorMsg); };
			};
		};
		for(var x in radioObj) {
			var radioValid = false,
			valArray = radioObj[x].valArray;
			for(var y in valArray) {
				if(valArray[y] === true) { radioValid = true; };
			};
			if(radioValid) { removeError(radioObj[x].firstElement); }
			else {
				createError(radioObj[x].firstElement,s.radioError);
				$return = false;
			};
		}; 
		return $return;
	};
	(function($){  
		jQuery.fn.fatValidate = function(o) {  
			s = $.extend(s, o);  
			return this.each(function() {  
				$(this).submit(function(){
					return check(this.elements);
				});
			});  
		};  
	})(jQuery);
})();
