(function( $ ){
	$.fn.clearValidate = function( options ) {

			var changedClass  = "changed";
			var invalidClass  = "invalid";
			var validClass    = "valid";
			var ignoreClass   = "ignore";
			var requiredClass = "required";
			var emailClass    = "email";
			var domainClass   = "domain";
	
			// loop through each matched element
			this.each( function() {

				//@@TODO - check if $(this) is actually a form
				var $form    = $(this);
				var $fields  = $form.find(":text");				
				var $field;
					
				// bind validateForm to form' "submit" event
				$form.bind( "submit", validateForm );
					
				$fields.each(function(){
					$field = $(this);
							
					// bind clearField to fields' "blur", "focus" events
					$field.bind( "blur focus", clearField );
						
					// bind validateField to field's "blur" event
					$field.bind( "blur formSubmit", validateField );	

				});
				
				function validateForm( event ){
				
					var isFormValid = true;
					var isFieldValid;
					
					$fields.each(function(){
						$field = $(this);

						// trigger blur on each field to validate
						isFieldValid = $field.triggerHandler( "formSubmit" );
						// if function call failed or returned false, invalidate form
						//isFormValid = !( isFieldValid == undefined || isFieldValid == false );
						isFormValid == undefined ? isFormValid = false : isFormValid &= isFieldValid;

					});


					//@@TODO - stop default action if form invlaid
					
					// Prevent form submission if form is invalid
					if ( !isFormValid ) {
						event.stopImmediatePropagation();
					}
					
					event.preventDefault();
					return isFormValid;
				}
				
				function validateField( event ){

					var isValid     = true;
					var $field      = $(this);
					var domainRegEx = /((https?):\/\/)?(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
					var emailRegEx  = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
					var changed     = $field.hasClass( changedClass );
					var required    = $field.hasClass( requiredClass );
					var formSubmit  = ( event.type == "formSubmit" );
					
					
					// Validate when field value changes or form is submitted and field is required
					if ( changed || (formSubmit && required) ){ 
								
						// Check domains against regex, required fields have been changed
						isValid &= $field.hasClass( domainClass ) ? domainRegEx.test($field.val()) : true;
						isValid &= $field.hasClass( emailClass ) ? emailRegEx.test($field.val()) : true;
						isValid &= $field.hasClass( requiredClass )? changed : true;
						$field.removeClass( ignoreClass );
									
						//	valid
						if ( isValid ){
							$field.removeClass( invalidClass );
							$field.addClass( validClass );
						//	invalid
						} else {
							$field.removeClass( validClass );
							$field.addClass( invalidClass );
						}
					}
					// Doesn't need to be validated, ignore.
					else {
						$field.removeClass( validClass );
						$field.removeClass( invalidClass );
						$field.addClass( ignoreClass );
					}
					
					return isValid;
				}

				function clearField( event ){
					
					var $field  = $(this);
					var initVal = $field.attr("defaultValue");
					var changed = ( $field.val() != "" && $field.val() != initVal );
						
					// On tab out of an empty field insert default value
					if ( event.type == "blur" && $field.val() == "" ) {
						$field.val( initVal );
					}
					// On tab into field with initial value clear out field
					else if ( event.type == "focus" && $field.val() == initVal ) {
						$field.val("");
					}
					
					changed ? $field.addClass( changedClass ) : $field.removeClass( changedClass );

				}
				
				return this;
			});
		};
})( jQuery );
