﻿function Validator(validationControls, nonInputControls, inputControls, nonInputControlErrorClass, inputControlErrorClass, addResetEvents) 
{
	///<summary>Validator accepts validation controls and validates them.  If any fail the supplied NonInputControls (e.g. labels) and controls are then styled with the error classes passed in.  Also adds the onFocus event to the controls to clear and error styling once the control is clicked on.</summary>
	///<param name="validationControls">This could be the ID or instance of a single validation control or it could be an Array of ID's or instances of multiple validation controls that you wish validate</param>
	///<param name="nonInputControls">This could be the ID or instance of a single non input control (such as a div or lablel control) or it could be an Array of ID's or instances of multiple non input controls that you wish to style.</param>
	///<param name="inputControls">This could be the ID or instance of a single input control or it could be an Array of ID's or instances of multiple input controls that you wish to style.</param>
	///<param name="nonInputControlErrorClass">The error class for non input styling</param>
	///<param name="inputControlErrorClass">The error class for input styling</param>
	///<param name="addResetEvents">If "True" allows the error styling to be cleared once the control is clicked on or gains focus.  True by default.</param>
	
	
	var me = this;

	this.ValidationControls = validationControls;
	this.NonInputControls = nonInputControls;
	this.InputControls = inputControls;
	this.nonInputControlErrorClass = nonInputControlErrorClass;
	this.InputControlErrorClass = inputControlErrorClass;
	
	this.AddResetEvents = true;
	if (addResetEvents != undefined)
	    this.AddResetEvents = addResetEvents;
	    
	this.IsValid = true;
	
	
	//Constants
	this.STYLE_TYPE_DEFAULT = "default";
	this.STYLE_TYPE_ERROR = "error";
	
	this.InputControl_OnFocus = function(e) 
	{
		if (!me.IsValid)
			me.Reset();
	}

	this.checkInstance = function(variableToCheck) 
	{
		///<summary> Finds the variable on the page.  If we have been passed the variable's ID as a string this is used to get the variable.</smmary>
		if (typeof (variableToCheck) == "string")
			variableToCheck = $get(variableToCheck);

		return variableToCheck;
	}
	
	this.setElementStyle = function(element, styleType, isLabel)
	{
		///<summary> Styles the element based on styleType</summary>
		switch (styleType)
		{
			case this.STYLE_TYPE_DEFAULT:
			{
				//Set the default style.
				if (element.getAttribute("origColor") != null) 
				{
					Validator.ResetElement(element);				
				}
				break;
			}
			case this.STYLE_TYPE_ERROR:
			{
				//Set the error style.
				if (element.getAttribute("origColor") == null) 
				{
					// Store original styles
					element.setAttribute("origColor", element.style.color);
					element.setAttribute("origBackgroundColor", element.style.backgroundColor);
					element.setAttribute("origClass", element.className);
					
					// Set Error class 
					if (isLabel)
					{
					    if (this.nonInputControlErrorClass != '')
					    {
						    element.className = element.className + " " + this.nonInputControlErrorClass
						    // Remove original styles
					        element.style.color = '';
					        element.style.backgroundColor = '';
						}
					}
					else
					{
					    if (this.InputControlErrorClass != '')
					    {
						    element.className = element.className + " " + this.InputControlErrorClass;
						    // Remove original styles
					        element.style.color = '';
					        element.style.backgroundColor = '';
						}
					}
				}
				break;
			}
		}
	}

	this.setDefaultStyles = function() 
	{
		///<summary> Sets the default styles of the supplied controls </summary>	
		if (this.NonInputControls instanceof Array)
		{
			for (var i = 0; i < this.NonInputControls.length; i++)
			{
				this.NonInputControls[i] = this.checkInstance(this.NonInputControls[i]);
				this.setElementStyle(this.NonInputControls[i], this.STYLE_TYPE_DEFAULT, true);
			}
		}
		else
		{
			this.NonInputControls = this.checkInstance(this.NonInputControls);
			this.setElementStyle(this.NonInputControls, this.STYLE_TYPE_DEFAULT, true);
		}
		
		
		if (this.InputControls instanceof Array) 
		{
			for (var i = 0; i < this.InputControls.length; i++) 
			{
				this.InputControls[i] = this.checkInstance(this.InputControls[i]);
				this.setElementStyle(this.InputControls[i], this.STYLE_TYPE_DEFAULT);		
			}
		}
		else 
		{
			this.InputControls = this.checkInstance(this.InputControls);
			this.setElementStyle(this.InputControls, this.STYLE_TYPE_DEFAULT);
		}
	}

	this.setErrorStyles = function() 
	{
		///<summary> Sets the error styles of the supplied controls </summary>
		if (this.NonInputControls instanceof Array)
		{
			for(var i = 0; i < this.NonInputControls.length; i++)
			{
				this.NonInputControls[i] = this.checkInstance(this.NonInputControls[i]);
				this.setElementStyle(this.NonInputControls[i], this.STYLE_TYPE_ERROR, true);
			}
		}
		else
		{
			this.NonInputControls = this.checkInstance(this.NonInputControls);
			this.setElementStyle(this.NonInputControls, this.STYLE_TYPE_ERROR, true);
		}
		
		
		if (this.InputControls instanceof Array) 
		{
			for (var i = 0; i < this.InputControls.length; i++) 
			{
				this.InputControls[i] = this.checkInstance(this.InputControls[i]);
				this.setElementStyle(this.InputControls[i], this.STYLE_TYPE_ERROR);
			}
		}
		else
		{
			this.InputControls = this.checkInstance(this.InputControls);
			this.setElementStyle(this.InputControls, this.STYLE_TYPE_ERROR);
		}
	}
	
	this.Initialise = function() 
	{
		// Check to see if we have been passed an array of NonInputControls
		if (this.NonInputControls instanceof Array)
		{
			for (var i = 0; i < this.NonInputControls.length; i++)
			{
				this.NonInputControls[i] = this.checkInstance(this.NonInputControls[i]);
			}	
		}
		else
		{
			this.NonInputControls = this.checkInstance(this.NonInputControls);
		}
		
        if (this.AddResetEvents)
        {
		    // Check to see if we have been passed an array of inputs
		    if (this.InputControls instanceof Array) 
		    {
			    for (var i = 0; i < this.InputControls.length; i++) 
			    {
				    this.InputControls[i] = this.checkInstance(this.InputControls[i]);

				    //Text box events.
				    //If the browser supports onactivate (such as IE) then use it as onfocus may not bubble correctly.
				    if (!this.InputControls[i].getAttribute("type") && !this.InputControls[i].type)
				    {
				        removeEvent(this.InputControls[i], "click", this.InputControl_OnFocus);
					    addEvent(this.InputControls[i], "click", this.InputControl_OnFocus);
				    }
				    else
				    {
				        if (typeof(document.onactivate) == 'object' && this.InputControls[i].getAttribute("type") != 'radio' && this.InputControls[i].getAttribute("type") != 'checkbox')
				        {
					        removeEvent(this.InputControls[i], "activate", this.InputControl_OnFocus);
					        addEvent(this.InputControls[i], "activate", this.InputControl_OnFocus);
				        }
				        else
				        {
					        removeEvent(this.InputControls[i], "focus", this.InputControl_OnFocus);
					        addEvent(this.InputControls[i], "focus", this.InputControl_OnFocus);
				        }
                    }
			    }
		    }
		    else 
		    {
			    this.InputControls = this.checkInstance(this.InputControls);

			    //Text box events.
			    //If the browser supports onactivate (such as IE) then use it as onfocus may not bubble correctly.
			    if (!this.InputControls.getAttribute("type") && !this.InputControls.type)
			    {
			        removeEvent(this.InputControls, "click", this.InputControl_OnFocus);
				    addEvent(this.InputControls, "click", this.InputControl_OnFocus);
			    }
			    else
			    {
			        if (typeof(document.onactivate) == 'object')
			        {
				        removeEvent(this.InputControls, "activate", this.InputControl_OnFocus);
				        addEvent(this.InputControls, "activate", this.InputControl_OnFocus);
			        }
			        else
			        {
				        removeEvent(this.InputControls, "focus", this.InputControl_OnFocus);
				        addEvent(this.InputControls, "focus", this.InputControl_OnFocus);
			        }
	            }
		    }
        
        }
	}

	this.Initialised = this.Initialise();
}

Validator.prototype.Reset = function() 
{
	this.setDefaultStyles();
	
	/* Uncomment and test if you need the validator's reseting when Reset is called.*/
	if (this.ValidationControls instanceof Array) 
	{
		for (var i = 0; i < this.ValidationControls.length; i++) 
		{
			this.ValidationControls[i] = this.checkInstance(this.ValidationControls[i]);
			Validator.ResetValidator(this.ValidationControls[i]);
		}
	}
	else 
	{
		this.ValidationControls = this.checkInstance(this.ValidationControls);
		Validator.ResetValidator(this.ValidationControls);
	}	
}

Validator.prototype.Validate = function(applyStyling) 
{
	///<summary>Asks each validation control that you've supplied if it's valid.  If any fail then sets the error styling that's been specifed to the input controls that have been supplied.  If all pass, the default styles are set.</summary>
	var isValid = true;

	if (applyStyling == undefined)
		applyStyling = true;
	
	if (this.ValidationControls instanceof Array) 
	{
		for (var i = 0; i < this.ValidationControls.length; i++) 
		{
			this.ValidationControls[i] = this.checkInstance(this.ValidationControls[i]);
			Validator.ForceValidation(this.ValidationControls[i]);
			isValid = isValid && this.ValidationControls[i].isvalid;
		}
	}
	else 
	{
		this.ValidationControls = this.checkInstance(this.ValidationControls);
		Validator.ForceValidation(this.ValidationControls);
		isValid = this.ValidationControls.isvalid;
	}

	this.IsValid = isValid;
	
	if (!isValid && applyStyling)
		this.setErrorStyles();
	else
		if (!this.AddResetEvents) // Basically, if we're not adding the events to automatically reset the validator when the control gets focus, then reset it here otherwise you'll need to reset it yourself somewhere.
			this.Reset();
}

Validator.ForceValidation = function(validationControl)
{
    ///<summary>Forces a validation control to validate.  This hooks into the validation evaluation function and then causes any message to display.  It's needed if we want to validate the controls onblur as by default, the event only fires on the onchange event.</summary>
    
    validationControl.isvalid = validationControl.evaluationfunction(validationControl);
    
    if (typeof(validationControl.display) == "string")
    {
        if (validationControl.display == "None") {
            return;
        }
        if (validationControl.display == "Dynamic") {
            validationControl.style.display = validationControl.isvalid ? "none" : "inline";
            return;
        }
    }
    
    validationControl.style.visibility = validationControl.isvalid ? "hidden" : "visible";
}

Validator.ValidatePage = function(validationGroup)
{
	///<summary> Validates the page using a validation group </summary>
	Page_ClientValidate(validationGroup);
}

Validator.IsPageValid = function()
{
	///<summary> Returns true if page is valid, false if not.</summary>
	return Page_IsValid;
}

Validator.ResetAll = function(arrErrorStyles) 
{
	///<summary> Resets all validation styling for elements with an error class specified in the supplied array.</summary>
	for (var i = 0; i < arrErrorStyles.length; i++) 
	{
		// Search for all inputs and NonInputControls with error styling, reseting the styles on each.
		$("." + arrErrorStyles[i]).each(function(i) 
		{
			Validator.ResetElement(this);
		});
	}
}

Validator.ResetElement = function(element) 
{
	///<summary> Resets element validation styling.</summary>
	
	// Reset original styles
	element.style.color = element.getAttribute("origColor");
	element.style.backgroundColor = element.getAttribute("origBackgroundColor");
	element.className = element.getAttribute("origClass");

	// Remove original styles
	element.removeAttribute("origColor");
	element.removeAttribute("origBackgroundColor");
	element.removeAttribute("origClass");
}

Validator.ResetValidator = function(validator)
{
	validator.isvalid = true;
    validator.style.display = 'none';
}

Validator.ResetValidationSummary = function(validationSummary)
{
    validationSummary.style.display = 'none';
}
