
//==================================================================================
//
//	Class: FormValidator
//
//	Author: Barak Ulmann, Netica LTD
//
//	Description: form validator class.
//
//	Compatibilty: IE, FireFox, ASP.NET form
//
//	Properties:
//		method	-	enum. FormValidator.Methods enumerator type
//		action	-	enum. FormValidator.Actions enumerator type
//		nonValidFields	-	array. non valid fields array. each entry is an object
//					with following properties:
//					elm:		object. form element reference
//					mandatoryFailure:	boolean. indicates whether mandatory validation failure
//					noAction: 	boolean. indicates whether an action is to be applied on validation failure
//					groupName: 	string. form element's group name. for checkboxes and radio buttons
//					message:	string. validation failure message
//
//	Methods:
//		setForm()	-	set form reference and create a form elements collection
//		validate()	-	validate form
//
//	Dependencies:
//		This file uses validation functions defined in the form_functions.js file.
//
//	Usage:
//		The form validator requires non standard (expando) attributes to be defined on
//		the form fields:
//			validationSkip	-	optional attribute. requires no value. if defined the field is not validated
//			mandatory		-	optional attribute. value=true|false. required for mandatory fields. when true
//								generic mandatory validation is applied to the field according to its type:
//								text, password, textarea	-	field's trimmed value length > 0.
//								select-one	-	first option is not selected. can be applied only if first
//											option is non valid saying "choose one" and all other options
//											are valid for selection.
//								select-multiple	-	atleast one option is selected. can be applied only if
//											all options are valid for selection.
//								checkbox, radio - atleast one option is checked.
//			validationType	-	optional attribute. value=integer|numeric|alphanumeric|name|email. if defined
//								a generic validation is applied according to the specified value. if value is"name"
//								an additional validationLang can be specified. otherwise assumption is the an English
//								name is validated. name is a string the contains all language alphabet characters, and
//								any of the following characters: [-"'_.] and space.
//			validationFunc	-	optional attribute. value=<any string that evaluates to boolean>. the value can contain
//								the 'this' keyword.
//			validationMessage	-	optional attribute. value=<string>. if specified this message will be displayed,
//								according to the action taken, when this field is not valid, unless mandatory validation
//								failed and the validationManadtoryMessage is specified.
//			validationManadtoryMessage	-	optional attribute. if specified this message will be displayed,
//								according to the action taken, when this field is mandatory and the mandatory validation
//								failed.
//			validationLang	-	optional attribute. used only when validationType=name
//			validationNoAction	-	optional attribute. requires no value. if specified no action will be applied when
//								field is not valid.
//
//			Atleast one of the following attributes must be specified to validate a foem field: mandatory, validationType or
//			validationFunc.
//
//		If labels are used validation messages are auto generated for the non valid fields in case either validationMessage
//		and validationManadtoryMessage are not specified (according to the reason the validation has failed). These messaged
//		are built using predefined strings containing placeholders. The plcaeholders are replaced with the label's text.
//		In case labels are not used and either validationMessage and validationManadtoryMessage are not specified, auto
//		generated fixed messages are used.
//
//		For radio buttons and checkboxes list a container with its id set to the group's name should be used. In case a 
//		mandatory group is not valid then this container will be used to make graphical indication according to the chosen
//		action defined. More over if a non standard label with its id set to the group's name then this label text is
//		used to generate the validation message.
//
//		Set the FormValidator.Defaults defined below to set the default behavior for your entire application.
//		
//		Set the FormValidator.Messages defined below to set the auto generated messages.
//
//		Here's a sample HTML demonstraiting the FormValidator usage:
/*
<html>
<head>
<title>Form Validator Test</title>
</head>
<body>
<form name="mainForm" onsubmit="return o.validate();">
	<a id="a1"></a><b id="b1"></b>
	<p id="p1"><a id="a2"></a>
	<label for="i1">i1</label>: <input type="text" id="i1" name="i1" mandatory="true"><br>
	<label for="i2">i2</label>: <input type="text" id="i2" name="i2" validationType="integer"><br>
	<label for="group">Group</label>: 
	<table border="0" cellpadding="0" celspacing="0" id="group">
		<tr>
			<td><input type="checkbox" id="chb1" name="group:0" mandatory="true"></td><td><label for="chb1">Family</label></td>
		</tr>
		<tr>
			<td><input type="checkbox" id="chb2" name="group:1" mandatory="true" validationFunc="!this.checked || this.form.elements['group:0'].checked" validationMessage="Family group must be checked too"></td><td><label for="chb2">Friends</label></td>
		</tr>
		<tr>
			<td><input type="checkbox" id="chb3" name="group:2" mandatory="true"></td><td><label for="chb3">Work</label></td>
		</tr>
	</table>
	<label for="gender">Gender</label>:
	<table border="0" cellpadding="0" cellspacing="0" id="gender">
		<tr>
			<td><input type="radio" id="rdb1" name="gender" value="mail" mandatory="true"></td><td><label for="rdb1">Mail</label></td>
			<td><input type="radio" id="rdb2" name="gender" value="femail" mandatory="true"></td><td><label for="rdb2">Femail</label></td>
		</tr>
	</table>
	</p>
	<label for="i3">i3</label> <input type="text" id="i3" name="i3" mandatory="true">
	<input type="submit" value="submit">
</form>
<script src="form_functions.js"></script>
<script src="form_validator.js"></script>
<script>
var o = new FormValidator(document.forms.mainForm);//document.getElementById("p1"));
o.method = FormValidator.Methods.ValidateAll;
o.action = FormValidator.Actions.Alert | FormValidator.Actions.ShowIcon | FormValidator.Actions.HighLight | FormValidator.Actions.Tooltip;
</script>
</body>
</html>
*/
//==================================================================================

//==================================================================================
//	Function: FormValidator()
//
//	Description: FormValidator class constructor
//
//	Parameters:
//		i_oForm_or_Container	-	object. form object or container reference
//==================================================================================
function FormValidator(i_oForm_or_Container)
{
	this.setForm(i_oForm_or_Container);
	this.method = FormValidator.Defaults.Method;
	this.action = FormValidator.Defaults.Action;
	this.nonValidFields = new Array();
}

//==================================================================================
//	Function: FormValidator.prototype.setForm()
//
//	Description: set form reference and create a form elements collection
//
//	Parameters:
//		i_oForm_or_Container	-	object. form object or container reference. if
//				a container then the elements collection contains all form elements
//				that are decendents of the container
//===================================================================================
FormValidator.prototype.setForm = function(i_oForm_or_Container)
{
	// build elements collection from form element
	if (i_oForm_or_Container && i_oForm_or_Container.tagName == "FORM") 
	{
		this.m_oForm = i_oForm_or_Container;
		this.m_oElements = this.m_oForm.elements;
	}
	// build elements collection from container
	else if (i_oForm_or_Container && i_oForm_or_Container.firstChild) 
	{
		this.m_oContainer = i_oForm_or_Container;
		var oFormElems1 = this.m_oContainer.getElementsByTagName("INPUT");
		var oFormElems2 = this.m_oContainer.getElementsByTagName("SELECT");
		var oFormElems3 = this.m_oContainer.getElementsByTagName("TEXTAREA");
		this.m_oElements = new Array();
		this.m_oForm = oFormElems1.length > 1? oFormElems1.item(0).form: 
			oFormElems2.length > 1? oFormElems2.item(0).form: 
			oFormElems3.length > 1? oFormElems3.item(0).form: 
			null;
		if (this.m_oForm) 
		{
			for (var i = 0; i < this.m_oForm.elements.length; i++)
				if ((this.m_oForm.elements[i].tagName == "INPUT" && FormValidator.isIn(this.m_oForm.elements[i], oFormElems1, true)) ||
					(this.m_oForm.elements[i].tagName == "SELECT" && FormValidator.isIn(this.m_oForm.elements[i], oFormElems2, true)) ||
					(this.m_oForm.elements[i].tagName == "TEXTAREA" && FormValidator.isIn(this.m_oForm.elements[i], oFormElems3, true)))
					this.m_oElements.push(this.m_oForm.elements[i]);
		}
	}
	
	// build labels collection
	if (this.m_oForm) 
	{
		var oLabels = this.m_oForm.getElementsByTagName("LABEL");
		this.m_oLabels = new Object();
		for (var i = 0; i < oLabels.length; i++)
			if (oLabels[i].attributes["for"].value)
				this.m_oLabels[oLabels[i].attributes["for"].value] = oLabels[i];
	}
}

//==================================================================================
//	Function: FormValidator.prototype.validate()
//
//	Description: validate form
//
//	Returns:
//		boolen. indicates whether form is valid
//==================================================================================
FormValidator.prototype.validate = function()
{
	if (!this.m_oForm)
		return;
	
	var bValid;
	var oFormElm;
	
	// reset previous non valid fields collection
	for (var i = 0; i < this.nonValidFields.length; i++) 
	{
		oFormElm = this.nonValidFields[i].elm;
		oFormElm.style.cssText = oFormElm.orgCssText;
		if (oFormElm.validationIcon) 
			oFormElm.validationIcon.style.visibility = "hidden";
	}
	this.nonValidFields.length = 0;
	
	bValid = true;
	
	// validate all fields
	for (var i = 0; i < this.m_oElements.length; i++) 
	{
		oFormElm = this.m_oElements[i];
		
		// validate form element
		bFieldValid = this._validateFormElm(oFormElm);
		
		if (!bFieldValid)
			bValid = false;
		
		if (!bFieldValid && this.method == FormValidator.Methods.ExitOnFirstNonValid) 
			break;
	}
	
	// apply actions on validation failure
	if(!bValid)
		this._applyActionsOnFailure();
	
	// return valid indicator
	return bValid;
}

//
// private methods
//

//==================================================================================
//	Function: FormValidator.prototype._validateFormElm()
//
//	Description: validate a form element private method
//
//	Parameters:
//		i_oFormElm	-	object. form element reference
//
//	Returns: boolean. true if valid
//==================================================================================
FormValidator.prototype._validateFormElm = function(i_oFormElm)
{
	var oCaller = FormValidator.prototype._validateFormElm.caller;
	if (!FormValidator.isIn(oCaller, FormValidator.prototype))
		return false;
	
	var bIsChoice, sGroupName;
	var bMandatory, bMandatoryFailure, bFieldValid, oFieldTempObj;
	var bNoAction, oLabel, sLabelText, sMessage;
	var oNonValidField;
	
	if (!i_oFormElm || i_oFormElm.disabled || typeof(FormValidator.getExpandoValue(i_oFormElm, "validationSkip")) == "string")
		return true;
	
	bMandatory = (FormValidator.getExpandoValue(i_oFormElm, "mandatory") == "true");
	bMandatoryFailure = false;
	bFieldValid = true;
	bIsChoice = false;
	
	if (FormValidator.debug)
		alert("name=" + i_oFormElm.name + 
			"\nid=" +  i_oFormElm.id + 
			"\ntype=" + i_oFormElm.type + 
			"\nvalue=" + i_oFormElm.value + 
			"\nbMandatory=" + bMandatory +
			"\nvalidationType=" + FormValidator.getExpandoValue(i_oFormElm, "validationType") + 
			"\nvalidationFunc=" + FormValidator.getExpandoValue(i_oFormElm, "validationFunc") + 
			"\nvalidationMessage=" + FormValidator.getExpandoValue(i_oFormElm, "validationMessage") + 
			"\nvalidationManadtoryMessage=" + FormValidator.getExpandoValue(i_oFormElm, "validationManadtoryMessage")
			);
	
	// validate text boxes
	if (FormValidator.isIn(i_oFormElm.type, ["text", "password", "textarea"])) 
	{
		// mandatory validation
		if (bMandatory && i_oFormElm.value.replace(/^\s+|\s+$/g,"").length == 0) 
		{
			bMandatoryFailure = true;
			bFieldValid = false;
		}
		
		// generic syntax validation. requires 'validationType' expando attribute
		else if (i_oFormElm.value.length > 0 && FormValidator.getExpandoValue(i_oFormElm, "validationType")) 
		{
			switch(FormValidator.getExpandoValue(i_oFormElm, "validationType")) 
			{
				case "integer": // digits only validation
					bFieldValid = isInteger(i_oFormElm.value);
					break;
				case "numeric": // any numeric string validation
					bFieldValid = isNumeric(i_oFormElm.value);
					break;
				case "alphanumeric": // alphanumeric string validation
					bFieldValid = isAlphaNumeric(i_oFormElm.value);
					break;
				case "name":	// name validation
					bFieldValid = isName(FormValidator.getExpandoValue(i_oFormElm, "validationLang"));
					break;
				case "email":	// email validation
					bFieldValid = (isValidEmail(i_oFormElm.value) == 0);
					break;
			}
		}
	}
	
	// generic combo-boxes validation. this validation can only be applied to combo-boxes
	// with a non valid default first option saying "choose one"
	else if (i_oFormElm.type == "select-one" && bMandatory) {
		bIsChoice = true;
		if (i_oFormElm.selectedIndex == 0) { // default option selected
			bMandatoryFailure = true;
			bFieldValid = false;
		}
	}
	
	// generic multiple selection validation. this validation can only be applied to combo-boxes
	// where all selection options are valid
	else if (i_oFormElm.type == "select-multiple" && bMandatory) {
		bIsChoice = true;
		for (var j = 0; j < i_oFormElm.options.length; j++)
			if (i_oFormElm.attributes.options[j].selected)
				break;
		if (j == i_oFormElm.attributes.options.length) { // no option selected
			bMandatoryFailure = true;
			bFieldValid = false;
		}
	}
	
	// generic checkbox/radio button validation
	else if ((i_oFormElm.type == "radio" || i_oFormElm.type == "checkbox") && bMandatory) 
	{
		bIsChoice = true;
		
		// single radio button or checkbox
		if (isNaN(this.m_oForm.elements[i_oFormElm.name].length)) {
			// .NET solution where check box list component render each checkbox with a
			// unique name attribute in the form <group name>:<index> e.g. "group:0", "group:1", ..., "group:n"
			if (/^.+?:\d+$/.test(i_oFormElm.name)) {
				sGroupName = i_oFormElm.name.split(":")[0];
				// perform mandatory validation for 1st element only
				if (i_oFormElm.name == sGroupName + ":0") {
					for (var j = 0; this.m_oForm.elements[sGroupName + ":" + j]; j++) {
						if (this.m_oForm.elements[sGroupName + ":" + j].checked)
							break;
					}
					if (!this.m_oForm.elements[sGroupName + ":" + j]) // no checked checkbox found
						bMandatoryFailure = true;
				}
			}
			// standard HTML
			else
				bMandatoryFailure = !i_oFormElm.checked;
		}
		// radio buttons or check boxes list. perform mandatory validation for 1st element only
		else if (i_oFormElm == this.m_oForm.elements[i_oFormElm.name][0]) {
			sGroupName = i_oFormElm.name;
			for (var j = 0; j < this.m_oForm.elements[sGroupName].length; j++) {
				if (this.m_oForm.elements[sGroupName][j].checked)
					break;
			}
			if (j == this.m_oForm.elements[sGroupName].length) // no checked checkbox/radio found
				bMandatoryFailure = true;
		}
		
		bFieldValid = !bMandatoryFailure;
	}
	
	// if valid reset the "is chioce" and "group name" parameters
	if (bFieldValid) {
		bIsChoice = false;
		sGroupName = null;
	}
	
	// user defined boolean function/string
	if (bFieldValid && FormValidator.getExpandoValue(i_oFormElm, "validationFunc")) {
		// use the ThisImpersonator object to evaluate the validationFunc string which
		// could contain 0 or more appearences of the 'this' keyword
		var oFieldTempObj = new FormValidator.ThisImpersonator(i_oFormElm);
		bFieldValid = oFieldTempObj.eval(FormValidator.getExpandoValue(i_oFormElm, "validationFunc"));
	}
	
	// handle non valid form element
	if (!bFieldValid) {
		// unless 'validationNoAction' attribute specified, build validation failure message
		bNoAction = typeof(FormValidator.getExpandoValue(i_oFormElm, "validationNoAction")) == "string";
		if (!bNoAction)
			sMessage = this._buildMessage(i_oFormElm, bMandatoryFailure, bIsChoice);
		
		// push non valid form element to non valid fields collection
		oNonValidField = {elm: i_oFormElm, mandatoryFailure: bMandatoryFailure, noAction: bNoAction, groupName: sGroupName, message: sMessage};
		this.nonValidFields.push(oNonValidField);
	}
	
	return bFieldValid;
}

//==================================================================================
//	Function: FormValidator.prototype._applyActionsOnFailure()
//
//	Description: apply actions on validation failure
//==================================================================================
FormValidator.prototype._applyActionsOnFailure = function()
{
	var oCaller = FormValidator.prototype._applyActionsOnFailure.caller;
	if (!FormValidator.isIn(oCaller, FormValidator.prototype))
		return;
	
	var oFormElm;
	var sGroupName;
	var oObj;
	var sEval;
	var sSummaryMessage = "";
	
	if (!this.m_oIcon && (this.action & FormValidator.Actions.ShowIcon)) 
	{
		this.m_oIcon = document.createElement("DIV");
		this.m_oForm.appendChild(this.m_oIcon);
		this.m_oIcon.style.cssText = "position:absolute;top:0;left:0;visibility:hidden;z-index:1;padding:1px;width:20;height:20;background-color:lightyellow;border:1px solid red;";
		this.m_oIcon.innerHTML = "<font face=\"webdings\" style=\"font: 15px/15px;color:red;\">&#105;<!-- 114 --></font>"
	}
	for (var i = 0; i < this.nonValidFields.length; i++) 
	{
		if (this.nonValidFields[i].noAction)
			continue;
		
		oFormElm = this.nonValidFields[i].elm;
		// different handling for checkboxes and radio buttons
		sGroupName = this.nonValidFields[i].groupName;
		oObj = sGroupName && document.getElementById(sGroupName)? document.getElementById(sGroupName): oFormElm;
		this.nonValidFields[i].elm = oObj;
		
		// build summary message
		sMessage = this.nonValidFields[i].message;
		if (sMessage)
			sSummaryMessage += sMessage + (i < this.nonValidFields.length - 1? "\n": "");
		
		// apply action per field
		oObj.orgCssText = oObj.style.cssText;
		if ((this.action & FormValidator.Actions.Focus) && FormValidator.focusEnabled(oFormElm) && oFormElm.focus)
			oObj.focus();
		if ((this.action & FormValidator.Actions.Select) && FormValidator.focusEnabled(oFormElm) && oFormElm.select)
			oFormElm.select();
		if (this.action & FormValidator.Actions.HighLight)
			oObj.style.cssText += (oObj.style.cssText? ";": "") + FormValidator.Defaults.HighLightStyle;
		if ((this.action & FormValidator.Actions.Tooltip) && sMessage)
			oObj.title = sMessage;
		if (this.action & FormValidator.Actions.ShowIcon) {
			if (!oObj.validationIcon) {
				oObj.validationIcon = this.m_oIcon.cloneNode(true);
				oObj.validationIcon.id = oObj.name + "ValidationIcon";
				this.m_oForm.appendChild(oObj.validationIcon);
				var offsetLeft = 0, offsetTop = 0;
				for (var oTmpObj = oObj; oTmpObj; oTmpObj = oTmpObj.offsetParent) {
					offsetLeft += oTmpObj.offsetLeft;
					offsetTop += oTmpObj.offsetTop;
				}
				oObj.validationIcon.style.pixelLeft = offsetLeft + oObj.offsetWidth - 5;
				oObj.validationIcon.style.pixelTop = offsetTop - 5;
				oObj.validationIcon.title = sMessage;
			}
			oObj.validationIcon.style.visibility = "visible";
		}
		sEval = "this.style.cssText = this.orgCssText;if (this.validationIcon) this.validationIcon.style.visibility = \"hidden\";"
		oObj.onfocus = new Function(sEval);
		if (oObj.id == sGroupName) {
			sEval = sEval.replace(/this/g, "document.getElementById(\"" + oObj.id + "\")");
			var oCollection = oObj.getElementsByTagName("INPUT");
			for (var j = 0; j < oCollection.length; j++) {
				oCollection.item(j).onfocus = new Function(sEval);
				if (this.m_oLabels[oCollection.item(j).id])
					this.m_oLabels[oCollection.item(j).id].onfocus = new Function(sEval);
			}
		}
	}
	
	// alert summary message
	if (sSummaryMessage && (this.action & FormValidator.Actions.Alert))
		alert(sSummaryMessage);
}

//==================================================================================
//	Function: FormValidator.prototype._buildMessage()
//
//	Description: build validation message private method
//
//	Parameters:
//		i_oFormElm	-	object. form element reference
//		i_bMandatoryFailure	-	boolean. indicating whether mandatory failure
//		i_bIsChoice	-	boolean. indicating whether form element is a choice type
//
//	Returns:
//		string. validation message
//==================================================================================
FormValidator.prototype._buildMessage = function(i_oFormElm, i_bMandatoryFailure, i_bIsChoice)
{
	var oCaller = FormValidator.prototype._buildMessage.caller;
	if (!FormValidator.isIn(oCaller, FormValidator.prototype))
		return;
	
	var sGroupName;
	var oLabel, sLabelText;
	var sMessage;
	
	if (FormValidator.isIn(i_oFormElm.type, ["radio", "checkbox"])) 
	{
		sGroupName = i_oFormElm.name;
		if (/^.+?:\d+$/.test(sGroupName))
			sGroupName = sGroupName.split(":")[0];
	}
	
	if (i_bMandatoryFailure && FormValidator.getExpandoValue(i_oFormElm, "validationManadtoryMessage"))
		sMessage = FormValidator.getExpandoValue(i_oFormElm, "validationManadtoryMessage");
	else if (FormValidator.getExpandoValue(i_oFormElm, "validationMessage"))
		sMessage = FormValidator.getExpandoValue(i_oFormElm, "validationMessage");
	else 
	{
		oLabel = sGroupName? this.m_oLabels[sGroupName]: this.m_oLabels[i_oFormElm.id];
		if (oLabel && oLabel.innerText)
			sLabelText = oLabel.innerText.toLowerCase();
		if (i_bMandatoryFailure && i_bIsChoice)
			sMessage = sLabelText? FormValidator.Messages.ChooseOne.replace("$1", sLabelText): FormValidator.Messages.DefaultChooseOne;
		else if (i_bMandatoryFailure)
			sMessage = sLabelText? FormValidator.Messages.Mandatory.replace("$1", sLabelText): FormValidator.Messages.DefaultMandatory;
		else
			sMessage = sLabelText? FormValidator.Messages.NotValid.replace("$1", sLabelText): FormValidator.Messages.DefaultNotValid;
	}
	
	return sMessage;
}

//
// static methods
//

//==================================================================================
//	Function: FormValidator.isIn()
//
//	Description: check if an element is in a collection
//
//	Parameters:
//		i_oElm	-	object. element to look for
//		i_oCollection	-	object. a collection to look in
//		i_bUseIndexed	-	boolean. indicating whether indexed search should be applied. false by default
//
//	Returns:
//		boolean
//==================================================================================
FormValidator.isIn = function(i_oElm, i_oCollection, i_bUseIndexed)
{
	if (!i_oElm || typeof(i_oCollection) != 'object')
		return false;
	
	if (i_bUseIndexed) {
		for (var i = 0; i < i_oCollection.length; i++)
			if (i_oElm == i_oCollection[i])
				return true;
	}
	else {
		for (var i in i_oCollection)
			if (i_oElm == i_oCollection[i])
				return true;
	}
	return false;
}

//==================================================================================
//	Function: FormValidator.getExpandoValue()
//
//	Description: get expando attribute value
//
//	Parameters:
//		i_oObj	-	object. object to get its attribute
//		i_sAttrName	-	string. attribute name
//
//	Returns:
//		string. attribute value or null
//==================================================================================
FormValidator.getExpandoValue = function(i_oObj, i_sAttrName)
{
	if (!i_oObj || !i_oObj.attributes || !i_oObj.attributes[i_sAttrName])
		return null;
	else
		return i_oObj.attributes[i_sAttrName].value;
}

//==================================================================================
//	Function: FormValidator.focusEnabled()
//
//	Description: check if focus enabled on object
//
//	Parameters:
//		i_oObj	-	object. object to check
//
//	Returns:
//		boolean
//==================================================================================
FormValidator.focusEnabled = function(i_oObj)
{
	if (!i_oObj || i_oObj.type == "hidden" || !i_oObj.style || i_oObj.style.visibility == "hidden" || i_oObj.style.display == 'none')
		return false;
	while (i_oObj.parentNode && i_oObj.parentNode.style) 
	{
		if (i_oObj.parentNode.style.visibility == "hidden" || i_oObj.parentNode.style.display == 'none')
			return false;
		i_oObj = i_oObj.parentNode;
	}
	return true;
}

//==================================================================================
//	Class: FormValidator.ThisImpersonator
//
//	Description:
//		this impersonator object 'assigns' a given object to the this pointer
//		used to evaluate strings containing the 'this' keyword when the this pointer
//		does not reference the required object.
//
//	Parameters:
//		i_oObj	-	object. object to evaluate on
//==================================================================================
FormValidator.ThisImpersonator = function(i_oObj)
{
	this.name = "ThisImpersonatorObject";
	this.object = i_oObj;
	eval(this.name + " = this.object");
}

//==================================================================================
//	Function: FormValidator.ThisImpersonator.prototype.replace
//
//	Description:
//		replace all appearences of 'this' keyword with the object's name which
//		references the object property
//
//	Parameters:
//		i_sEvaluable	-	string. string to replace
//==================================================================================
FormValidator.ThisImpersonator.prototype.replace = function(i_sEvaluable)
{
	return i_sEvaluable.replace(/(\b)(this)(\b)/g,"$1" + this.name + "$3");
}

//==================================================================================
//	Function: FormValidator.ThisImpersonator.prototype.eval
//
//	Description:
//		evaluate a string containg 0 or more  appearences of 'this' keyword
//
//	Parameters:
//		i_sEvaluable	-	string. string to evaluate
//==================================================================================
FormValidator.ThisImpersonator.prototype.eval = function(i_sEvaluable)
{
	i_sEvaluable = this.replace(i_sEvaluable);
	return eval(i_sEvaluable);
}

// emulate some IE properties for mozilla
if (navigator.appName == "Netscape")
{
	if (HTMLElement.prototype.__defineGetter__)
	{
		HTMLElement.prototype.__defineGetter__("innerText", function() {
			return this.textContent;
		});
		HTMLElement.prototype.__defineSetter__("innerText", function(value) {
		    this.innerHTML = "";
		    this.appendChild(document.createTextNode(value));
		});
	}
	if (CSSStyleDeclaration.prototype.__defineGetter__)
	{
		// mimic microsoft's pixel representations of left/top/width/height
		// the getters only work for values that are already pixels
		CSSStyleDeclaration.prototype.__defineGetter__("pixelLeft", function() {
			return parseInt(this.left) || 0;
		});
		CSSStyleDeclaration.prototype.__defineSetter__("pixelLeft", function(value) {
			this.left = value + "px";
		});
		CSSStyleDeclaration.prototype.__defineGetter__("pixelTop", function() {
			return parseInt(this.top) || 0;
		});
		CSSStyleDeclaration.prototype.__defineSetter__("pixelTop", function(value) {
			this.top = value + "px";
		});
	}
}

//
// static variables
//

FormValidator.debug = false;
FormValidator.Methods = {ExitOnFirstNonValid: 1, ValidateAll: 2};
FormValidator.Actions = {None: 0, Alert: 1, Focus: 2, Select: 4, HighLight: 8, Tooltip: 16, ShowIcon: 32};
FormValidator.Messages = {
	DefaultMandatory: "This field is mandatory", 
	Mandatory: "$1 is mandatory", 
	DefaultNotValid: "This field is not valid", 
	NotValid: "$1 is not valid", 
	DefaultChooseOne: "Please select one", 
	ChooseOne: "Please select $1"
	};
FormValidator.Defaults = {
	Method: FormValidator.Methods.ExitOnFirstNonValid,
	Action: FormValidator.Actions.Alert | FormValidator.Actions.Focus,
	HighLightStyle: "border: 1px solid red; background-color: lightyellow; color: black;"
	};
