// ~~ Form Validation Classes ~~

function formValidator(id, handle_ValidationFail, handle_ValidationPass)
{
	// Get handle for the form
	this.Form = $id(id);
	var me = this;
	
	if (typeof(handle_ValidationFail) == 'function')
	{
		this.onFail = handle_ValidationFail;
	}
	else
	{
		this.onFail = null;	
	}
	
	if (typeof(handle_ValidationPass) == 'function')
	{
		this.onPass = handle_ValidationPass;
	}
	else
	{
		this.onPass = null;	
	}	
	
	//  Declare an array to store the Valadation Rule objects
	this.ValidationRules = new Array();
	
	//  Declare a variable to store whether the form has been tested
	this.Tested = false;
	
	//  Declare a variable to store whether the form has been validated
	this.Validated = false;
	
	//  Method: Add a validation rule to the Form Validator Object
	this.AddRule = function(name, validationType, handle_ValidationFail, handle_ValidationPass)
	{
		this.ValidationRules[this.ValidationRules.length] = new ValidationRule(name, me.Form, validationType, handle_ValidationFail, handle_ValidationPass);
	}
	
	this.RemoveRules = function(ref, rule)
	{
		if (typeof(name) == "string")
		{
			elName = ref;
		}
		else
		{
			elName = ref.name;
		}
		
		for (var i = 0; i < me.ValidationRules.length; i++)
		{
			if (rule)
			{
				if ((me.ValidationRules[i].Element.name == elName) && (me.ValidationRules[i].ValidationType == rule))
				{
					me.DeleteRule(i);
					i--;
				}
			}
			else
			{
				if (me.ValidationRules[i].Element.name == elName)
				{
					me.DeleteRule(i);
					i--;
				}
			}
		}
	}
	
	this.DeleteRule = function(idx)
	{
		if (idx < me.ValidationRules.length)
		{
			for (var i = idx; i < (me.ValidationRules.length - 1); i++)
			{
				me.ValidationRules[i] = me.ValidationRules[(i + 1)];
			}
			me.ValidationRules.pop();
		}
	}
	
	//  Method: Validate Form (onsubmit handler)
	this.Validate = function(e)
	{
		me.Validated = true;
		for (var iVR = 0; iVR < me.ValidationRules.length; iVR++)
		{
			me.Validated = me.ValidationRules[iVR].Validate() && me.Validated;
		}

		//  If all elements successfully validate
		
		if (!me.Validated)
		{
			$preventDefault(e);
			if (typeof(me.onFail) == 'function')
			{
				me.onFail(me.Form);	
			}
		}
		else
		{
			if (typeof(me.onPass) == 'function')
			{
				me.onPass(me.Form);	
			}
		}
		//  If validation fails return error message and stop the form submitting
	}
}

//  Object: Valadation Rule - Assigns a valadation rule to form element
function ValidationRule(name, form, validationType, handle_ValidationFail, handle_ValidationPass)
{
	if (typeof(name) == 'string')
	{
		this.Element = $name(form, name);
	}
	else
	{
		this.Element = name;	
	}
	
	var me = this;
	
	this.ValidationArg = false;
	this.ValidationType = getValidationType(me, validationType);
	
	this.onFail = handle_ValidationFail;
	this.onPass = handle_ValidationPass;
	
	
	this.Tested = false;
	this.Validated = false;
	
		//  Method: Validate Element
	this.Validate = function()
	{
		// alert(me.Element.name + " : " + me.ValidationType + " : " + me.ValidationArg);
		if (me.ValidationType == "required")
		{
			me.Validated = /^(\s)*(\S)+(.)*$/.test(me.Element.value);
		}
		else if (me.ValidationType == "numeric")
		{
			me.Validated = /^$|^[0-9]$|^[1-9][0-9]*$/.test(me.Element.value);
		}
		else if (me.ValidationType == "decimal")
		{
			if (me.ValidationArg < 0)
			{
				me.Validated = /^$|^[0-9](\.[0-9]+)?$|^[1-9][0-9]*(\.[0-9]+)?$/.test(me.Element.value);
			}
			else if (me.ValidationArg == 0)
			{
				me.Validated = /^$|^[0-9](\.[0-9]+)$|^[1-9][0-9]*(\.[0-9]+)$/.test(me.Element.value);
			}
			else
			{
				var re = new RegExp("^$|^[0-9](\\.[0-9]{" + me.ValidationArg + "})$|^[1-9][0-9]*(\\.[0-9]{" + me.ValidationArg + "})$");
				me.Validated = re.test(me.Element.value);
			}
		}
		else if (me.ValidationType == "uk-date")
		{
			var re = new RegExp("^$|^([1-9]|0[1-9]|[12][0-9]|3[0-1])/((0)?[13578]|(1)[02])/[1-9][0-9]{0,3}$|^([1-9]|0[1-9]|[12][0-9]|30)/((0)?[469]|(11))/[1-9][0-9]{0,3}$|^([1-9]|0[1-9]|[12][0-9])/(0)?2/[1-9][0-9]{0,3}$");
			me.Validated = re.test(me.Element.value);
		}
		else if (me.ValidationType == "us-date")
		{
			var re = new RegExp("^$|^((0)?[13578]|(1)[02])/([1-9]|0[1-9]|[12][0-9]|3[0-1])/[1-9][0-9]{0,3}$|^((0)?[469]|(11))/([1-9]|0[1-9]|[12][0-9]|30)/[1-9][0-9]{0,3}$|^(0)?2/([1-9]|0[1-9]|[12][0-9])/[1-9][0-9]{0,3}$");
			me.Validated = re.test(me.Element.value);
		}
		else if (me.ValidationType == "time-24")
		{
			me.Validated = /^$|^([01][0-9]|[2][0-3])[:][0-5][0-9]$/.test(me.Element.value);
		}
		else if (me.ValidationType == "time-12")
		{
			me.Validated = /^$|^([0]?[0-9]|[1][0-2])[:\.][0-5][0-9](pm|PM|am|AM)$/.test(me.Element.value);
		}
		else if (me.ValidationType == "email")
		{
			me.Validated = /^$|^([a-zA-Z0-9_'+*$%=~\?\{\}\^&!\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9:]{2,4})+$/.test(me.Element.value);
		}
		else if (me.ValidationType == "select")
		{
			me.Validated = me.Element.value != me.ValidationArg;
		}
		else if (me.ValidationType == "checkbox")
		{
			me.Validated = me.Element.checked;
		}
		else if (me.ValidationType == "radio")
		{
			if (isArray(me.Element))
			{
				me.Validated = false;
				for (var i = 0; i < me.Element.length; i++)
				{
					me.Validated = me.Validated || me.Element[i].checked;
				}
			}
			else
			{
				me.Validated = me.Element.checked;
			}
		}
		else if (me.ValidationType == "s_radio")
		{
			if (isArray(me.Element))
			{
				me.Validated = false;
				for (var i = 0; i < me.Element.length; i++)
				{
					me.Validated = me.Validated || (me.Element[i].checked && (me.Element[i].value == me.ValidationArg));
				}
			}
			else
			{
				me.Validated = (me.Element[i].checked && (me.Element[i].value == me.ValidationArg));
			}
		}
		else if (me.ValidationType == "jpg")
		{
			me.Validated = /^$|\.jpg$|\.JPG|\.jpeg|\.JPEG/.test(me.Element.value);
		}
		else
		{
			alert("Error:\nInvalid Validation Type:\n\t" + me.ValidationType + "\nFor:\n\t" + me.Element.name );
		}
		
		me.Tested = true;
		if (me.Validated)
		{
			me.onPass(me.Element);
		}
		else
		{
			me.onFail(me.Element);
		}
		return me.Validated;
	}
	
	
}

function getValidationType(rule, vType)
{
	if (/^decimal\[(.)+\]$/.test(vType))
	{
		rule.ValidationArg = parseInt(vType.substring(8,vType.lastIndexOf("]")));
		return "decimal";
	}
	else if (/^select\[(.)+\]$/.test(vType))
	{
		rule.ValidationArg = vType.substring(7,vType.lastIndexOf("]"));
		return "select";
	}
	else if (/^s_radio\[(.)+\]$/.test(vType))
	{
		rule.ValidationArg = vType.substring(8,vType.lastIndexOf("]"));
		return "s_radio";
	}
	else
	{
		return vType;
	}
}