﻿/// <reference path="jquery-1.4.2.min.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: "input.inputEmail",

		postal: function(isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._postalBase, isInit); },
		_postalClass: "inputPostal",
		_postalBase: "input.inputPostal",

		url: function(isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._urlBase, isInit); },
		_urlClass: "inputUrl",
		_urlBase: "input.inputUrl",
		password: function(isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._passwordBase, isInit); },
		_passwordClass: "inputPassword",
		_passwordBase: "input.inputPassword",
		matching: function(isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._matchingBase, isInit); },
		_matchingClass: "inputMatching",
		_matchingBase: "input.inputMatching[matchingid]",
		select: function(isInit) { return $.inputValidation.selectors._format($.inputValidation.selectors._selectBase, isInit); },
		_selectClass: "inputSelect",
		_selectBase: "select.inputSelect",
		_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:enabled";
			}

			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: provide enter a valid password.",
		matching: "ERROR: provide enter a matching value.",
		select: "ERROR: Please make a selection."
	},
	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 minLen = $this.attr("minlength");
		if (!minLen)
			minLen = 1;
		var maxLen = $this.attr("maxlength");
		if (!maxLen)
			maxLen = -1;

		var len = $.trim($this.val()).length;

		var isValid = len >= minLen && (maxLen < 1 || len <= maxLen);

		$.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);

		if (EmailRegExp)
		{
			var isValid = EmailRegExp.test($.trim($this.val()));
			$.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);
		if (PostalRegExp)
		{
			var isValid = PostalRegExp.test($.trim($this.val()));
			$.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);

		if (UrlRegExp)
		{
			var isValid = UrlRegExp.test($.trim($this.val()));
			$.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 = $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 messageBuilder = "";
		if (password.length > 0)
			messageBuilder = "<div class=\"" + cssClass + "\"><div class=\"passwordBar\"></div><div>" + message + "</div></div>";

		var statusContainerID = "passwordValidationStatus_" + $this.attr("id");
		var statusContainer = $this.validationIndicator_Password();

		if (statusContainer.size() == 0)
		{
			statusContainer = $("<div id=\"" + statusContainer.selector.substring(1) + "\"></div>");
			$this.after(statusContainer);
		}

		$.inputValidation.showValidateResult($this, isValid, $.inputValidation.validatePasswordHandler, showError);

		statusContainer.html(messageBuilder);

		return isValid;
	},
	validatePasswordHandler: function(event)
	{
		var $this = $(event.currentTarget);

		$.inputValidation.validatePassword($this, false);
	},
	validateMatching: function(element, showError)
	{
		var $this = $(element);

		var matchingInput = $("#" + $this.attr("matchingid"));

		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 isValid = $this.val().length > 0 && $this.val() == matchingInput.val();
			$.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);
		});
	},
	validateSelect: 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.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);
	},
	validateGroups: new Array(),
	validateGroup: function(groupData, showError, isInit)
	{
		var isValid = true;
		if (groupData)
		{
			debugger;
			var elements = $("[name=" + groupData.name + "]:checked", groupData.container);

			if (isInit)
			{
				elements.unbind(".groupValidateEvent");
				elements.bind("click.groupValidateEvent", function()
				{
					validateGroupHandler(groupData);
				});
			}

			var count = elements.size();

			if (count > 0)
			{
				// Valid
				if (groupData.validationContainer)
					groupData.validationContainer.html($.inputValidation.validMessage);
			}
			else
			{
				// Invalid
				isValid = false;

				if (groupData.validationContainer)
					groupData.validationContainer.html($.inputValidation.invalidMessage);

				if (showError && groupData.errorContainer)
					groupData.errorContainer.show();
			}
		}

		return isValid;
	},
	validateGroupHandler: function(groupData)
	{
		$.inputValidation.validateGroup(groupData);
	},
	validateGroupInit: function(container, name, validationContainer, errorContainter)
	{
		var groupData = _createGroupData(container, name, validationContainer, errorContainter);
		$.inputValidation.validateGroups.push(groupData);
		$.inputValidation.validateGroup(groupData, false, true);
	},
	showValidateResult: function(element, isValid, handler, showError)
	{
		var $this = $(element);

		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 = "";
			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;
			}

			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
			msgValidation.html($.inputValidation.validMessage);
		}
		else
		{
			// Show red asterick
			msgValidation.html($.inputValidation.invalidMessage);

			// 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=\"\" /><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=\"\" /><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 (this.size() > 0)
    {
        var $this = $(this[0]);

        var errorContainer = $("#" + $.inputValidation.errorIdPrefix_Custom + $this.attr("id"));
        errorContainer.html(html).show();
        $.inputValidation.addErrorCount(1);
        $.inputValidation.showValidateResult($this, false);
    }
    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.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);

        // 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);

		$.each($.inputValidation.validateGroups, function()
		{
			var groupData = this;
			if ($.contains($this, groupData.container))
			{
				if (!$.inputValidation.validateGroup(groupData, showErrors))
					invalidCount++;
			}
		});
	});

	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);
};