(function($) {
	var validate = function(userOptions) {
		var defaultOptions = {
			inputWrapper: $(this),
			requiredClassName: "required",
			selectDefaultClassName: "default_option",
			labelErrorClassName: "error",
			dataLabelErrorKey: "hasError",
			dataInputLabelKey: "userLabel",
			dataCustomValidateKey: "customValidator",
			onLabelError: function(labelErrorClassName) {
				$(this).addClass(labelErrorClassName);
			},
			onLabelRemoveError: function(labelErrorClassName) {
				$(this).removeClass(labelErrorClassName);
			},
			onError: function(errorsArray,successArray) {
				return false;
			},
			onSuccess: function(errorsArray,successArray) {
				return true;
			}
		}
		var options = {};
		if (userOptions == undefined) {
			options = defaultOptions;
		} else {
			for (var prop in defaultOptions) {
				if (userOptions[prop] != undefined) {
					options[prop] = userOptions[prop];
				} else {
					options[prop] = defaultOptions[prop];
				}
			}
		}
		
		var errors = new Array();
		var allSet = new Array();
		$("."+ options.requiredClassName, options.inputWrapper).each(function(indx) {
			if ($(this).data(options.dataCustomValidateKey) != undefined && $(this).data(options.dataCustomValidateKey) instanceof Function) {
				var valid = $(this).data(options.dataCustomValidateKey).call(this,indx);
				if (!valid)
					errors.push(this);
				else 
					allSet.push(this);
			} else {
				switch (this.tagName.toLowerCase()) {
					case 'input':
						switch (this.type) {
							case "text":
								if (this.value == "")
									errors.push(this);
								else 
									allSet.push(this);
								break;
							case 'radio':
								var emptyRadios = true;
								$('input[name='+this.name+']',options.inputWrapper).each(function() {
									if (this.checked)
										emptyRadios = false;
								});
								if (!emptyRadios)
									errors.push(this);
								else 
									allSet.push(this);
								break;
							case 'checkbox':
								var checkedCheckboxes = false;
								$('input[name='+this.name+']',options.inputWrapper).each(function() {
									if (this.checked)
										checkedCheckboxes = true;
								});
								if (!checkedCheckboxes)
									errors.push(this);
								else 
									allSet.push(this);
								break;
						}
						break;
					case "textarea":
						if (this.value == '') 
							errors.push(this);
						else 
							allSet.push(this);
						break;
					case 'select':
						var defaultSelect = false;
						for (var i=0; i < this.options.length; i++) {
							if (this.options[i].selected && !$(this.options[i]).hasClass(options.selectDefaultClassName)) {
								defaultSelect = true;
							}
						};
						if (!defaultSelect)
							errors.push(this);
						else 
							allSet.push(this);
						break;
				}
			}
		});
		
		$(allSet).each(function() {
			var customLabel = $(this).data(options.dataInputLabelKey);
			var defaultLabel = $('label[for='+this.id+']',options.inputWrapper);
			
			if (customLabel != undefined) {
				if ($(customLabel).data(options.dataLabelErrorKey) != undefined) {
					options.onLabelRemoveError.call($(customLabel)[0],options.labelErrorClassName);
				}
				$(customLabel).removeData(options.dataLabelErrorKey);
			} else if (defaultLabel.length > 0) {
				if (defaultLabel.data(options.dataLabelErrorKey) != undefined) {
					options.onLabelRemoveError.call(defaultLabel[0],options.labelErrorClassName);
				}
				defaultLabel.removeData(options.dataLabelErrorKey);
			}
		});
		$(errors).each(function() {
			var customLabel = $(this).data(options.dataInputLabelKey);
			var defaultLabel = $('label[for='+this.id+']',options.inputWrapper);
			
			if (customLabel != undefined) {
				if ($(customLabel).data(options.dataLabelErrorKey) == undefined) {
					options.onLabelError.call($(customLabel)[0],options.labelErrorClassName);
					$(customLabel).data(options.dataLabelErrorKey,true);
				}
			} else if (defaultLabel.length > 0) {
				if (defaultLabel.data(options.dataLabelErrorKey) == undefined) {
					options.onLabelError.call(defaultLabel[0],options.labelErrorClassName);
					defaultLabel.data(options.dataLabelErrorKey,true);
				}
			}
		});
		if (errors.length == 0) {
			var retVal = options.onSuccess.call(this,errors,allSet);
			return (retVal == undefined) ? true : retVal;
		} else {
			var retVal = options.onError.call(this,errors,allSet);
			return (retVal == undefined) ? false : retVal;
		}
	}
	
	$.fn.formValidate = function(userOptions) {
		var valid = undefined;
		this.each(function() {
			valid = validate.call(this,userOptions);
		});
		return valid;
	}
})(jQuery);

