﻿/// <reference path="jquery-1.6.1-vsdoc.js" />
/// <reference path="jquery-plugins.js" />

/*
reference for commenting js code
/// <summary>
///		
///	</summary>
/// <param name="" optional="false"></param>
///	<returns type="jQuery"></returns>
*/

var debugMode = false;

function _createGroupData(container, name, validationContainer, errorContainer)
{
	return { container: container, name: name, validationContainer: validationContainer, errorContainer: errorContainer };
}

$.inputValidation =
{

	selectors:
	{
		required: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._requiredBase, isInit); },
		_requiredClass: "inputRequired",
		_requiredBase: ".inputRequired",
		email: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._emailBase, isInit); },
		_emailClass: "inputEmail",
		_emailBase: ".inputEmail",

		postal: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._postalBase, isInit); },
		_postalClass: "inputPostal",
		_postalBase: ".inputPostal",

		url: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._urlBase, isInit); },
		_urlClass: "inputUrl",
		_urlBase: ".inputUrl",

		password: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._passwordBase, isInit); },
		_passwordClass: "inputPassword",
		_passwordBase: ".inputPassword",

		matching: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._matchingBase, isInit); },
		_matchingClass: "inputMatching",
		_matchingBase: ".inputMatching",

		select: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._selectBase, isInit); },
		_selectClass: "inputSelect",
		_selectBase: ".inputSelect",

		radioGroup: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._radioGroupBase, isInit); },
		_radioGroupClass: "radioButtonRequired",
		_radioGroupBase: ".radioButtonRequired",

		checkBoxGroup: function (isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._checkBoxGroupBase, isInit); },
		_checkBoxGroupClass: "checkBoxRequired",
		_checkBoxGroupBase: ".checkBoxRequired",

		_format: function (validationSelector, isInit)
		{
			var selector = validationSelector + "[" + $.inputValidation.resultAttribute;

			if (isInit)
			{
				// Grab elements without the validation result attribue since that attribute is
				// added after the input has been initialized
				selector += "!=]";
			}
			else
			{
				// Grab all elements with the validation result attribute that are visible and enabled
				selector += "]:visible";
			}

			return selector;
		}
	},
	errorMessage:
	{
		required: "ERROR: Please provide a valid entry.",
		email: "ERROR: Please provide a valid email address.",
		postal: "ERROR: Please provide a valid postal code.",
		url: "ERROR: Please provide a valid URL.",
		password: "ERROR: Please provide a valid password.",
		matching: "ERROR: Values do not match.",
		select: "ERROR: Please make a selection.",
		radio: "ERROR: Please select one."
	},
	errorClass: "inputError",
	errorIdPrefix_Default: "msgError_Default_",
	errorIdPrefix_Custom: "msgError_Custom_",
	validationMessagePrefix_Default: "msgValidation_Default_",
	validationMessagePrefix_Password: "msgValidation_Password_",
	resultAttribute: "validationResult",
	validMessage: "<span class=\"validationMessage\" style=\"color: green;\"><img src='/ImagesV3/green_check.gif' alt='&#x2713;' /></span>",
	invalidMessage: "<span class=\"validationMessage\" style=\"color: red;\">*</span>",
	keyPressMinInterval: 500,
	lastKeyPress: null,
	keyPressTimes: new Array(),
	keyPressPause: function (element, handler)
	{
		var $this = $(element);

		if ($this.size() > 0)
		{
			// No swirly for now
			//$this.validationIndicator_Default().html("<img src=\"../ImagesV3/spinner.gif\" alt=\"Checking...\" class=\"validationMessage\" style=\"margin: 0 0 0 2px;\" />");

			$.inputValidation.keyPressTimes[$this.attr("id")] = new Date().getTime();

			setTimeout(function ()
			{
				var now = new Date().getTime();

				if (now - $.inputValidation.keyPressTimes[$this.attr("id")] > $.inputValidation.keyPressMinInterval)
					handler($this);
			}, $.inputValidation.keyPressMinInterval + 100);
		}
	},
	validateRequired: function (element, showError)
	{
		var $this = $(element);

		var value, len, minLen, maxLen, isValid;

		value = $.trim($this.val());
		len = value.length;

		minLen = $this.attr("minlength");
		if (!minLen)
			minLen = 1;

		maxLen = $this.attr("maxlength");
		if (!maxLen)
			maxLen = -1;

		isValid = len >= minLen && (maxLen < 1 || len <= maxLen);

		var regexStr = $this.attr("validationregex");
		if (regexStr)
		{
			var re = new RegExp(regexStr);

			isValid = re.test(value);
		}

		$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validateRequiredHandler, showError);

		return isValid;
	},
	validateRequiredHandler: function (event)
	{
		var $this = $(event.currentTarget);

		$.inputValidation.keyPressPause($this, function ()
		{
			$.inputValidation.validateRequired($this, false);
		});
	},
	validateEmail: function (element, showError)
	{
		// NOTE: EmailRegExp is assigned in the MainBasePage by writing the expression to the page inside a script tag
		var $this = $(element);

		var value = $.trim($this.val());
		var allowEmpty = $this.attr("allowEmpty") == "true";

		if (EmailRegExp)
		{
			var isValid = (allowEmpty && value.length == 0) || EmailRegExp.test(value);
			$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validateEmailHandler, showError);
			return isValid;
		}
		else
		{
			return true;
		}
	},
	validateEmailHandler: function (event)
	{
		var $this = $(event.currentTarget);
		$.inputValidation.keyPressPause($this, function ()
		{
			$.inputValidation.validateEmail($this, false);
		});
	},
	validatePostal: function (element, showError)
	{
		var $this = $(element);

		var value = $.trim($this.val());
		var allowEmpty = $this.attr("allowEmpty") == "true";

		if (PostalRegExp)
		{
			var isValid = (allowEmpty && value.length == 0) || PostalRegExp.test(value);
			$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validatePostalHandler, showError);
			return isValid;
		}
		else
		{
			return true;
		}
	},
	validatePostalHandler: function (event)
	{
		var $this = $(event.currentTarget);
		$.inputValidation.keyPressPause($this, function ()
		{
			$.inputValidation.validatePostal($this, false);
		});
	},
	validateUrl: function (element, showError)
	{
		// NOTE: UrlRegExp is assigned in the MainBasePage by writing the expression to the page inside a script tag
		var $this = $(element);

		var value = $.trim($this.val());
		var allowEmpty = $this.attr("allowEmpty") == "true";

		if (UrlRegExp)
		{
			var isValid = (allowEmpty && value.length == 0) || UrlRegExp.test(value);
			$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validateUrlHandler, showError);
			return isValid;
		}
		else
		{
			return true;
		}
	},
	validateUrlHandler: function (event)
	{
		var $this = $(event.currentTarget);
		$.inputValidation.keyPressPause($this, function ()
		{
			$.inputValidation.validateUrl($this, false);
		});
	},
	validatePassword: function (element, showError)
	{
		var $this = $(element);

		var isValid = false;

		var password;

		password = $.trim($this.val());

		var strength = 0;
		if (password.length <= 20)
		{
			if (password.length >= 6)
			{
				// Any upper or lowercase letter
				if (password.match(/[a-zA-Z]/))
					strength++;

				// Any number
				if (password.match(/\d/))
					strength++;

				if (strength == 2)
				{
					// Password is strong enough, determine if it is better by checking
					// for upper case, lower case, and special characters
					// Reduce the strength so we can check for upper/lower case letters
					strength--;

					// Lowercase letter
					if (password.match(/[a-z]/))
						strength++;

					// Uppercase letter
					if (password.match(/[A-Z]/))
						strength++;

					// Special Character
					if (password.match(/[^a-zA-Z0-9]/))
						strength++;
				}
			}
			else
			{
				// Too Short;
				strength = -1;
			}
		}
		else
		{
			// Too Long
			strength = -2;
		}

		var message = "";
		var cssClass = "";

		switch (strength)
		{
			case -2:
				message = "Too Long";
				cssClass = "weakPass";
				break;
			case -1:
				message = "Too Short";
				cssClass = "weakPass";
				break;
			case 2:
				message = "Strong";
				cssClass = "strongPass";
				break;
			case 3:
			case 4:
				message = "Very Strong";
				cssClass = "veryStrongPass";
				break;
			default:
				message = "Too Weak";
				cssClass = "weakPass";
				break;
		}

		isValid = strength >= 2;

		var statusContainer = $this.validationIndicator_Password();

		$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validatePasswordHandler, showError);

		if (statusContainer.size() == 0)
		{
			statusContainer = $("<div id=\"" + statusContainer.selector.substring(1) + "\" class=\"passwordStrengthStatus\"></div>");
			$this.parent().after(statusContainer);
		}

		if (password.length > 0)
		{
			statusContainer.show().html("<div class=\"" + cssClass + "\"><div class=\"passwordBar\">&nbsp;</div><div>" + message + "</div></div>");
		}
		else
		{
			statusContainer.hide();
		}

		return isValid;
	},
	validatePasswordHandler: function (event)
	{
		var $this = $(event.currentTarget);

		$.inputValidation.validatePassword($this, false);
	},
	validateMatching: function (element, showError)
	{
		var $this = $(element);

		var thisValue = $.trim($this.val());

		var machingInputID;
		if ($this.hasClass("riTextBox"))
			machingInputID = $this.attr("matchingid") + "_text";
		else
			machingInputID = $this.attr("matchingid");

		var matchingInput = $("#" + machingInputID);

		if (matchingInput.size() == 1)
		{
			if (!$this.attr($.inputValidation.resultAttribute))
			{
				// First time init--add a handler to the matching input so if it changes
				// this input will be revalidated
				matchingInput.keyup(function (event) { event.currentTarget = $this; $.inputValidation.validateMatchingHandler(event); });
			}

			var matchingIsValid = matchingInput.attr("validationresult") != "false";
			var matchingValue = $.trim(matchingInput.val());

			var isValid = matchingIsValid && thisValue == matchingValue;
			$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validateMatchingHandler, showError);

			return isValid;
		}
		else
			return true;
	},
	validateMatchingHandler: function (event)
	{
		var $this = $(event.currentTarget);
		$.inputValidation.keyPressPause($this, function ()
		{
			$.inputValidation.validateMatching($this, false);
		});
	},
	validateSelectRetrys: 0,
	validateSelect: function (element, showError)
	{
		var $this = $(element);

		var selectedValue = null;
		if ($this.hasClass("RadComboBox"))
		{
			var comboBox = $find($this.attr("id"));

			if (comboBox == null)
			{
				if ($.inputValidation.validateSelectRetrys < 10)
				{
					$.inputValidation.validateSelectRetrys++;
					setTimeout(function ()
					{
						$.inputValidation.validateSelect(element, showError);
					}, 100);
				}
			}
			else
			{
				var selectedItem = comboBox.get_selectedItem();

				if (selectedItem != null)
					selectedValue = selectedItem.get_value();
				else
					selectedValue = null;
			}
		}
		else
		{
			if (!$this.attr($.inputValidation.resultAttribute))
			{
				// First time init--add a handler to the matching input so if it changes
				// this input will be revalidated
				$this.change(function (event) { event.currentTarget = $this; $.inputValidation.validateSelectHandler(event); });
			}

			selectedValue = $("option:selected", element).val();
		}

		if (!selectedValue)
			selectedValue = "";
		var isValid = selectedValue.length > 0;
		$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validateSelectHandler, showError);

		return isValid;
	},
	validateSelectHandler: function (event)
	{
		$.inputValidation.validateSelect(event.currentTarget, false);
	},
	validateTelerikCombo: function (sender, eventArgs)
	{
		return $.inputValidation.validateSelect($("#" + sender._uniqueId.replace(/\$/g, "_")), false);
	},
	validateRadioGroup: function (element, showError)
	{
		var $this = $(element);

		if (!$this.attr($.inputValidation.resultAttribute))
		{
			// First time init--add a handler to the matching input so if it changes
			// this input will be revalidated
			$this.change(function (event) { event.currentTarget = $this; $.inputValidation.validateSelectHandler(event); });
		}

		var selectedValue = $this.find(".rbToggleRadioChecked").parent(".radioButton").attr("Value");
		if (!selectedValue)
			selectedValue = "";
		var isValid = selectedValue.length > 0;
		$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validateRadioGroupHandler, showError);

		return isValid;
	},
	validateRadioGroupHandler: function (event)
	{
		$.inputValidation.validateRadioGroup(event.currentTarget, false);
	},
	validateCheckBoxGroup: function (element, showError)
	{
		var $this = $(element);

		if (!$this.attr($.inputValidation.resultAttribute))
		{
			// First time init--add a handler to the matching input so if it changes
			// this input will be revalidated
			$this.change(function (event) { event.currentTarget = $this; $.inputValidation.validateSelectHandler(event); });
		}

		var checkedCount = $this.find(".rbToggleCheckboxChecked").parent(".checkBox").children().size();
		var isValid = checkedCount > 0;
		$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validateRadioGroupHandler, showError);

		return isValid;
	},
	validateCheckBoxGroupHandler: function (event)
	{
		$.inputValidation.validateCheckBoxGroup(event.currentTarget, false);
	},
	showValidateResult: function (element, isValid, handler, showError)
	{
		var $this = $(element);

		var parent = $this.parent();

		if (!parent.is("span") || parent.css("display") != "inline-block")
		{
			parent = $("<span style=\"display: inline-block;\"></span>");
			$this.wrap(parent);
		}

		var msgValidation = $this.validationIndicator_Default();

		// Add the result element after the input if it does not exist
		if (msgValidation.size() == 0)
		{
			msgValidation = $("<span id=\"" + msgValidation.selector.substring(1) + "\"></span>");
			$this.after(msgValidation);
		}

		var msgError_Default = $this.validationErrorContainer_Default();

		if (msgError_Default.size() == 0)
		{
			// If there is no default error message, generate it
			msgError_Default = $("<div id=\"" + msgError_Default.selector.substring(1) + "\" class=\"" + $.inputValidation.errorClass + "\"></div>");

			var parentRow = $this.parent(".rightCell").parent(".inputRow");
			if (parentRow.size() > 0)
			{
				parentRow.before(msgError_Default);
			}
			else
			{
				$this.before(msgError_Default);
			}

			var errorMessage = "";
			var specifiedErrorMessage = $.trim($this.attr("defaulterrormessage"));
			if (specifiedErrorMessage != null && specifiedErrorMessage.length > 0)
			{
				errorMessage = specifiedErrorMessage;
			}
			else if (handler === $.inputValidation.validateRequiredHandler)
			{
				/*var minLen = $this.attr("minlength");
				if (!minLen)
				minLen = 1;
				var maxLen = $this.attr("maxlength");
				if (debugMode && (!maxLen || maxLen < 1 || maxLen > 8000))
				$this.css("border", "solid 5px #9B30FF");


				var plural;
				if (minLen > 1)
				plural = "s";
				else
				plural = "";

				errorMessage = "ERROR: This field requires at least " + minLen + " character" + plural;

				if (maxLen && maxLen > 0)
				{
				if (maxLen > 1)
				plural = "s";
				else
				plural = "";

				errorMessage += " and no more than " + maxLen + " character" + plural + ".";
				}

				else
				errorMessage += ".";*/
				errorMessage = $.inputValidation.errorMessage.required;
			}
			else if (handler === $.inputValidation.validateEmailHandler)
			{
				errorMessage = $.inputValidation.errorMessage.email;
			}
			else if (handler === $.inputValidation.validatePostalHandler)
			{
				errorMessage = $.inputValidation.errorMessage.postal;
			}
			else if (handler === $.inputValidation.validateUrlHandler)
			{
				errorMessage = $.inputValidation.errorMessage.url;
			}
			else if (handler === $.inputValidation.validatePasswordHandler)
			{
				errorMessage = $.inputValidation.errorMessage.password;
			}
			else if (handler === $.inputValidation.validateMatchingHandler)
			{
				errorMessage = $.inputValidation.errorMessage.matching;
			}
			else if (handler === $.inputValidation.validateSelectHandler)
			{
				errorMessage = $.inputValidation.errorMessage.select;
			}
			else if (handler === $.inputValidation.validateRadioGroupHandler)
			{
				errorMessage = $.inputValidation.errorMessage.radio;
			}

			msgError_Default.html(errorMessage);
		}

		var msgError_Custom = $this.validationErrorContainer_Custom();

		if (msgError_Custom.size() == 0)
		{
			msgError_Custom = $("<div id=\"" + msgError_Custom.selector.substring(1) + "\" class=\"" + $.inputValidation.errorClass + "\"></div>");
			$this.before(msgError_Custom);
		}

		/*
		// Fade out the custom error after 2 seconds from the last keyup
		if(msgError_Custom.is(":visible"))
		setTimeout("$(\"#" + msgError_Custom_ID + "\").slideUp();", 2000);
		*/

		if (isValid)
		{
			// Hide the error only if the error summary is hidden or missing
			if (showError && (!$.inputValidation.errorSummaryContainer || $.inputValidation.errorSummaryContainer.is(":hidden")))
			{
				if ($this.parent().hasClass("invalidOutline"))
					$this.unwrap();
				//$this.removeClass("invalidOutline");
				msgError_Default.hide();
			}

			// Show green checkmark
			if (handler !== $.inputValidation.validateRadioGroupHandler)
				msgValidation.html($.inputValidation.validMessage);
			else
				msgValidation.html("");
		}
		else
		{
			// Show red asterick
			if (handler !== $.inputValidation.validateRadioGroupHandler)
				msgValidation.html($.inputValidation.invalidMessage);
			else
				msgValidation.html("");

			// Show the error message if we're showing errors 
			// and have a container specified to show
			if (showError)
			{
				if (!$this.parent().hasClass("invalidOutline"))
					$this.wrap("<span class='invalidOutline' />");

				msgError_Default.show();
			}
		}

		// If this element has not been initialized for validation, do so
		if (!$this.attr($.inputValidation.resultAttribute) && handler)
		{
			$this.bind("keyup.inputValidation", handler);
		}

		// Add/Set the result attribute on this element so we can quickly
		// see what needs to be validated and tell that this element has been initialized
		// This must be done before the formatValidationResult since it counts the invalid inputs
		$this.attr($.inputValidation.resultAttribute, isValid.toString());
	},
	getInvalidCount: function ()
	{
		var errorCountContainter = $(".errorCount", $.inputValidation.errorSummaryContainer);
		var errorAmmount;
		if (errorCountContainter.size() > 0)
		{
			errorAmmount = parseInt(errorCountContainter.text());
		}
		var inputAmmount = $("input[" + $.inputValidation.resultAttribute + "='false']:visible, select[" + $.inputValidation.resultAttribute + "='false']:visible").size();

		return errorAmmount > inputAmmount ? errorAmmount : inputAmmount;
	},
	errorSummaryContainer: null,
	formatValidationResult: function (numInvalid)
	{
		/// <summary>
		///		Adjusts the error message based on the numInvald.  Will show the container only if the numInvalid > 0
		///	</summary>
		/// <param name="numInvalid" optional="false">Number of errors to be reported</param>

		var $errorContainer = $($.inputValidation.errorSummaryContainer);
		if ($errorContainer)
		{
			if (numInvalid > 0)
			{
				if (numInvalid == 1)
				{
					$errorContainer.html("<div class=\"errorTextSummary\"><img src=\"/ImagesV3/error.gif\" alt=\"\" />&nbsp;<b>ERROR:</b> There is an error on the page.<br />Please scroll down and fix the error in red.<span class=\"errorCount\" style=\"display: none;\">" + numInvalid + "</span></div>");
				}
				else
				{
					$errorContainer.html("<div class=\"errorTextSummary\"><img src=\"/ImagesV3/error.gif\" alt=\"\" />&nbsp;<b>ERROR:</b> There appears to be a few errors.<br />Please scroll down and fix the <span class=\"errorCount\">" + numInvalid + "</span> errors in red.</div>");
				}
				$errorContainer.show();
				$.scrollTo($errorContainer, { offset: { top: -100} });
			}
		}
	},
	addErrorCount: function (additionalAmmount, setThisAmmount)
	{
		/// <summary>
		///		Adds (or optionally sets) the error count by the specified ammount
		///	</summary>
		/// <param name="additionalAmmount" optional="false">Number to adjust the errors by</param>
		/// <param name="setThisAmmount" optional="true">If true, set the error count to this number instead of adding</param>
		if ($.inputValidation.errorSummaryContainer)
		{
			var errorCountContainter = $(".errorCount", $.inputValidation.errorSummaryContainer);

			if (errorCountContainter.size() > 0)
			{
				if (setThisAmmount)
					$.inputValidation.formatValidationResult(additionalAmmount);
				else
				{
					var currentAmmount = parseInt(errorCountContainter.text());
					currentAmmount += additionalAmmount;
					$.inputValidation.formatValidationResult(currentAmmount);
				}
			}
			else
			{
				$.inputValidation.formatValidationResult(additionalAmmount);
			}

			$.inputValidation.errorSummaryContainer.show();
		}
	}
};

$.fn.validationIndicator_Default = function ()
{
	/// <summary>
	///		Gets the validation indication container for this element (if it exists)
	/// </summary>
	///	<returns type="jQuery">The validation message container for this element</returns>
	return $("#" + $.inputValidation.validationMessagePrefix_Default + this.attr("id"));
};

$.fn.validationIndicator_Password = function ()
{
	/// <summary>
	///		Gets the password validation indication container for this element (if it exists)
	/// </summary>
	///	<returns type="jQuery">The password message container for this element</returns>
	return $("#" + $.inputValidation.validationMessagePrefix_Password + this.attr("id"));
};

$.fn.validationErrorContainer_Default = function ()
{
	/// <summary>
	///		Gets the default validation error container for this element (if it exists)
	/// </summary>
	///	<returns type="jQuery">The default error container for this element</returns>
	return $("#" + $.inputValidation.errorIdPrefix_Default + this.attr("id"));
};

$.fn.validationErrorContainer_Custom = function ()
{
	/// <summary>
	///		Gets the custom validation error container for this element (if it exists)
	/// </summary>
	///	<returns type="jQuery">The custom error container for this element</returns>
	return $("#" + $.inputValidation.errorIdPrefix_Custom + this.attr("id"));
};

$.fn.setCustomError = function (html)
{
	if (html && this.size() > 0)
	{
		var $this = $(this[0]);

		var customErrorContainer = $this.validationErrorContainer_Custom();
		customErrorContainer.html(html).show();
		$.inputValidation.addErrorCount(1);
		$.inputValidation.showValidateResult($this, false, null, true);
		$this.validationErrorContainer_Default().hide();
	}
	return this;
};

$.fn.validateRequired = function (showErrors, isInit)
{
	/// <summary>
	///		Initializes and runs the validation on child elements for a trimmed value of > 0 
	///		as well as any matching parent elements in the case that we call it on the element we want to validate
	/// </summary>
	/// <param name="showErrors" optional="true">Show the red error notes on error</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.required(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validateRequired(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.validateEmail = function (showErrors, isInit)
{
	/// <summary>
	///		Initializes and runs the validation on child elements for emails 
	///		as well as any matching parent elements in the case that we call it on the element we want to validate
	/// </summary>
	/// <param name="showErrors" optional="true">Show the red error notes on error</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.email(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validateEmail(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.validatePostal = function (showErrors, isInit)
{
	/// <summary>
	///		Initializes and runs the validation on child elements for postal codes 
	///		as well as any matching parent elements in the case that we call it on the element we want to validate
	/// </summary>
	/// <param name="showErrors" optional="true">Show the red error notes on error</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.postal(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validatePostal(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.validateUrl = function (showErrors, isInit)
{
	/// <summary>
	///		Initializes and runs the validation on child elements for emails 
	///		as well as any matching parent elements in the case that we call it on the element we want to validate
	/// </summary>
	/// <param name="showErrors" optional="true">Show the red error notes on error</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.url(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validateUrl(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.validatePassword = function (showErrors, isInit)
{
	/// <summary>
	///		Initializes and runs the validation on child elements for passwords 
	///		as well as any matching parent elements in the case that we call it on the element we want to validate
	///		Adds a password strength indication to the inputs container.  
	///		Valid (strong) passwords: 6<=length<=20 containing at least 1 letter and at least 1 number.  
	///		Very strong passwords: criteria above with the addition of an upercase/lowercase/special character.
	/// </summary>
	/// <param name="showErrors" optional="true">Show the red error notes on error</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.password(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validatePassword(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.validateMatching = function (showErrors, isInit)
{
	/// <summary>
	///		Initializes and runs the validation on child elements for matching 
	///		as well as any matching parent elements in the case that we call it on the element we want to validate  
	///		Should revalidate whenever the input changes or the element that it is matching to changes.
	/// </summary>
	/// <param name="showErrors" optional="true">Show the red error notes on error</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.matching(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validateMatching(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.validateSelect = function (showErrors, isInit)
{
	/// <summary>
	///		Initializes and runs the validation on child elements for selects 
	///		as well as any matching parent elements in the case that we call it on the element we want to validate  
	///		Should revalidate whenever the selected option changes.
	/// </summary>
	/// <param name="showErrors" optional="true">Show the red error notes on error</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.select(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validateSelect(this, showErrors))
			invalidCount++;
	});


	return invalidCount;
};

$.fn.validateRadioGroup = function (showErrors, isInit)
{

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.radioGroup(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validateRadioGroup(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.validateCheckBoxGroup = function (showErrors, isInit)
{

	var invalidCount = 0;
	var selector = $.inputValidation.selectors.checkBoxGroup(isInit);

	$(selector, this).add(this.filter(selector)).each(function ()
	{
		if (!$.inputValidation.validateCheckBoxGroup(this, showErrors))
			invalidCount++;
	});

	return invalidCount;
};

$.fn.removeValidation = function ()
{
	/// <summary>
	///		Remove validation attribute from element and hide any error/validation messages associated with it
	/// </summary>
	///	<returns type="jQuery"></returns>

	this.each(function ()
	{
		var $this = $(this);

		// Remove any classes that are used for validation
		// as well as the validation attribute telling us that
		// this element has been initialized for validation
		$this.removeAttr($.inputValidation.resultAttribute)
				.removeClass($.inputValidation.selectors._requiredClass)
				.removeClass($.inputValidation.selectors._emailClass)
				.removeClass($.inputValidation.selectors._postalClass)
				.removeClass($.inputValidation.selectors._urlClass)
				.removeClass($.inputValidation.selectors._passwordClass)
				.removeClass($.inputValidation.selectors._matchingClass)
				.removeClass($.inputValidation.selectors._selectClass)
				.removeClass($.inputValidation.selectors._radioGroupClass)
				.removeClass($.inputValidation.selectors._checkBoxGroupClass);

		// Hide any message containers associated with validation
		$("#" + $.inputValidation.validationMessagePrefix_Default + $this.attr("id")).html("");
		$("#" + $.inputValidation.validationMessagePrefix_Password + $this.attr("id")).hide();
		$("#" + $.inputValidation.errorIdPrefix_Default + $this.attr("id")).hide();
		$("#" + $.inputValidation.errorIdPrefix_Custom + $this.attr("id")).hide();
	});
	return this;
};

$.fn.clearErrors = function ()
{
	/// <summary>
	///		Hides the main error container and all text errors in the current context 
	///		as well as unwrapping any outlines
	/// </summary>
	///	<returns type="jQuery"></returns>

	if ($.inputValidation.errorSummaryContainer)
	{
		$.inputValidation.errorSummaryContainer.hide();
	}

	this.each(function ()
	{
		var $this = $(this);
		$("." + $.inputValidation.errorClass, $this).hide();
		$(".invalidOutline", $this).each(function ()
		{
			$(">:first", $(this)).unwrap();
		});
	});

	return this;
};

$.fn.validateAll = function (errorElement, isInit)
{
	/// <summary>
	///		Validates the child validation elements
	/// </summary>
	/// <param name="errorElement" optional="true">Show the red error notes on error and show the error report in the specified element</param>
	///	<param name="isInit" optional="true">Only run on child elements that are not initialized</param>
	///	<returns type="int">Number of invalid inputs</returns>

	var invalidCount = 0;
	var showErrors = false;
	if (errorElement)
	{
		showErrors = true;

		// Clean up the old error container
		if ($.inputValidation.errorSummaryContainer)
		{
			$.inputValidation.errorSummaryContainer.html("");
			$.inputValidation.errorSummaryContainer.hide();
		}

		// Assign and setup the new errorContainer
		$.inputValidation.errorSummaryContainer = $(errorElement);

		// Hide existing error messages
		this.clearErrors();
	}

	$(this).each(function ()
	{
		var $this = $(this);

		invalidCount += $this.validateRequired(showErrors, isInit);
		invalidCount += $this.validateEmail(showErrors, isInit);
		invalidCount += $this.validatePostal(showErrors, isInit);
		invalidCount += $this.validateUrl(showErrors, isInit);
		invalidCount += $this.validatePassword(showErrors, isInit);
		invalidCount += $this.validateMatching(showErrors, isInit);
		invalidCount += $this.validateSelect(showErrors, isInit);
		invalidCount += $this.validateRadioGroup(showErrors, isInit);
		invalidCount += $this.validateCheckBoxGroup(showErrors, isInit);
	});

	if (showErrors && $.inputValidation.errorSummaryContainer)
	{
		$.inputValidation.formatValidationResult(invalidCount);
	}

	return invalidCount;
};

$.fn.validateInit = function (errorElement)
{
	/// <summary>
	///		Intializes all child validation elements
	/// </summary>
	/// <param name="errorElement" optional="true">Main error container to use</param>
	///	<returns type="jQuery"></returns>

	// Hide any previously show errors
	$(".inputError", this).hide();

	if (errorElement)
	{
		if ($.inputValidation.errorSummaryContainer)
			$.inputValidation.errorSummaryContainer.html("");

		$.inputValidation.errorSummaryContainer = $(errorElement);
	}

	return this.validateAll(false, true);
};
