jQuery.fn.think_validation = function (vOptions) {
	//validation
	function isValid(fieldToValidate) {
		//***********************************************
		var self = jQuery("input[name=" + fieldToValidate + "]");
		var errMsg = "";

		if (self.attr("id") == jQuery("input[id$=txtNumWaterDevicesRequired]").attr("id")) {
			if (jQuery('select[id$="ddlNature"]').attr('selectedIndex') == 4) {
				if (self.val() != "" && jQuery("input[id$=rdoCustUseBusiness]:checked").length > 0) {
					errMsg = "<span class=\"inline errorMessage errHouseOnly\" live=\"polite\"><label for=\"" + self.attr("id") + "\">Unfortunately this product is only available to household customers</label></span>";
					if (!jQuery(".errHouseOnly").length > 0) {
						//self.after("<span class=\"inline errorMessage errHouseOnly\" live=\"polite\"><label for=\"" + self.attr("id") + "\">Unfortunately this product is only available to household customers</label></span>");
						self.after(errMsg);
					};

					return;
				}
			};
		}
		//***********************************************
		fieldToValidate == escape(fieldToValidate);

		var postData = jQuery(vOptions.formId).serialize() + "&validate_json_request=true&validate_json_field=" + fieldToValidate; //live data

		jQuery.ajax({
			type: "POST",
			contentType: "application/json; charset=utf-8",
			url: vOptions.urlString,
			data: postData,
			dataType: "json",
			contentType: "application/x-www-form-urlencoded",
			error: function (errorData, errorData1) {

			},
			success: function (returnedData) {
				//loop JSON
				var i = returnedData.validation.field.length;
				while (i--) {
					var mainMessage = returnedData.validation.error_message_info;
					var fieldId = returnedData.validation.field[i].field_id;
					var inlineMess = returnedData.validation.field[i].message;
					var success = returnedData.validation.field[i].sucess;

					if (!success && jQuery("#" + fieldId).val()) {
						clearErrors(jQuery("#" + fieldId), fieldId)
						addInlineMessage(fieldId, inlineMess);
						addMainError(fieldId, mainMessage);
					}
					else if (success) {
						clearErrors(jQuery("#" + fieldId), fieldId)
						addInlineSuccessMessage(fieldId, inlineMess);
					}
				}
			}
		});
	};

	//display inline message next to field
	function addInlineMessage(fieldId, inlineMess) {

		var rowParent = jQuery("#" + fieldId).parents(".frmRow:first");
		var messageExists = rowParent.find(".errorMessage:has(label[for='" + fieldId + "'])").filter(function () { return jQuery(this).html() == jQuery(inlineMess).html(); });

		if (rowParent.hasClass("error")) {
			if (messageExists.length == 0) {
				if (!rowParent.find(".errorIcon").length > 0) {
					rowParent.append(" " + inlineMess);
				}
			}
		}
		else if (rowParent.hasClass("servererror")) {
			if (messageExists.length > 0) {
				rowParent.removeClass("success");
				rowParent.find(".successIcon").addClass("js-hide");
				messageExists.removeClass("js-hide");
			}
			else {
				if (!rowParent.find(".errorIcon").length > 0) {
					rowParent.append(" " + inlineMess);
				}
				else {
					rowParent.find(".errorIcon").removeClass("js-hide");
					rowParent.find(".successIcon").addClass("js-hide");
				}
			}

			if (rowParent.find(".errorMessage:not(.js-hide)").length > 0) {
				rowParent.addClass("error");
			}
		}
		else if (rowParent.hasClass("serversuccess")) {
			if (rowParent.find(".errorMessage").length > 0) {
				rowParent.removeClass("success");
				rowParent.find(".successIcon").addClass("js-hide");
				messageExists.removeClass("js-hide");
				if (!rowParent.find(".errorIcon").length > 0) {
					rowParent.append(" " + inlineMess);
				}
			}
			else {
				rowParent.append(" " + inlineMess);
			}

			if (rowParent.find(".errorMessage:not(.js-hide)").length > 0) {
				rowParent.addClass("error");
			}

		}
		else {
			//no message exists, so add it

			rowParent.addClass("error");
			rowParent.append(" " + inlineMess);
		}

	};

	function addInlineSuccessMessage(fieldId, inlineMess) {

		var rowParent = jQuery("#" + fieldId).parents(".frmRow:first");

		if (rowParent.hasClass("error")) {
			rowParent.removeClass("error")
		}

		if (!rowParent.find('.successIcon').length > 0) {
			rowParent.addClass("success");
			rowParent.append(" " + inlineMess);
		}
		else {
			rowParent.find('.successIcon').removeClass("js-hide");
			rowParent.find('.errorIcon').addClass("js-hide");
			rowParent.addClass("success")
		}
	};

	function clearErrors(field, fieldId) {

		var rowParent = jQuery(field).parents(".frmRow:first");

		if (rowParent.hasClass("servererror")) {
			rowParent.find(".errorMessage:has(label[for='" + fieldId + "'])").addClass("js-hide");
		}
		else if (rowParent.hasClass("serversuccess")) {
			rowParent.find(".errorMessage:has(label[for='" + fieldId + "'])").addClass("js-hide");
		}
		else if (rowParent.hasClass("error")) {
			rowParent.find(".errorMessage:has(label[for='" + fieldId + "'])").remove();
		}
		else if (rowParent.hasClass("success")) {
			rowParent.removeClass("success").find(".errorMessage").remove();
		}

		if (rowParent.find(".errorMessage:not(.js-hide)").length == 0 && jQuery('.error').length > 0) {
			//current
			rowParent.removeClass("error");
		}

		//check if other errors exist on page, true: update main error message at top of page
		if (jQuery("#iError").length && jQuery(".frmRow").hasClass(".error") == false) {
			jQuery("#iError").remove(); //remove if main message exists and no inline errors exist
		}
		else if (jQuery("#iError").length && jQuery(".frmRow").hasClass(".error") == true) {
			//validate all fields
			isValid();
		}
	};

	function addMainError(fieldId, mainMessage) {
		//check if main message exists
		if (jQuery("#iError").length) {
			//check if main message has changed
			if (jQuery("#iError").html() !== jQuery(mainMessage).html()) {
				jQuery("#iError").replaceWith(mainMessage); //if changed replace
			}
		}
		else //append message
		{
			jQuery("#" + fieldId).parents("div.form").prepend(mainMessage);
		}
		jQuery("#iError").roundedCorners(true);
	};

	//set event on fields
	jQuery(this).blur(function () {
		//check if field is null or empty
		if (!(jQuery(this).val())) {
			// Get the control ID
			var fieldId = jQuery(this).attr("id");
			var rowParent = jQuery(this).parents(".frmRow:first");

			if (jQuery(this).parent().hasClass("frmElement")) {
				if (!rowParent.hasClass("servererror")) {
					//unless current field is the forename field
					if (!jQuery(this).parent(".frmElement").prev().hasClass("title")) {
						//remove associated inline error message and parent class
						clearErrors(jQuery(this), jQuery(this).attr("id"));
					}
				}
			}
			else {
				if (!rowParent.hasClass("servererror")) {
					//remove associated inline error message and parent class
					clearErrors(jQuery(this), jQuery(this).attr("id"));
				}
			}

			if (rowParent.hasClass("servererror")) {
				// Check if this field was the one that caused the error on postback (servererror)
				var exists = rowParent.find(".errorIcon:has(label[for='" + fieldId + "'])");

				if (exists.length > 0) {
					// Set the status back to how it was before any js interaction
					rowParent.removeClass("success");
					rowParent.addClass("error")
					exists.removeClass("js-hide");
					rowParent.find(".successIcon").addClass("js-hide");
				}

			}
			else if (rowParent.hasClass("serversuccess")) {
				var exists = rowParent.find(".successIcon");

				if (exists.length > 0) {
					// Set the status back to how it was before any js interaction
					rowParent.removeClass("error");
					rowParent.addClass("success")
					exists.removeClass("js-hide");
					rowParent.find(".errorIcon").addClass("js-hide");
				}
			}
		}
		else //if field contains data validate it
		{
			var fieldId = jQuery(this).attr("id");
			clearErrors("#" + fieldId, fieldId);
			// check that there are no invalid characters first, we don't want the asp.net "potentially dangerous characters" exception
			if (this.value.match("[%\^*+=}{#~/<>|;]")) {
				addInlineMessage(fieldId, '<span class="inline errorMessage errorIcon"><label for="' + fieldId + '">The field contains invalid characters</label></span>');
			}
			else {
				isValid(this.name); //validate passing in id of field
			}
		}
	});

	/*
	end validation
	*/
};

