//************onsubmit="return $V.validate(this,{settingsObject})"**************//
//*****************LOOK AT THE BOTTOM FOR EXPLANATIONS************************//
$V = new function()
{
	var	compiledInvalidMsg	= "",
		invalid 			= false,
		firstFocus 			= null;	
	
	this.config =
	{
		isDebug						: false,
		validPatternAttr			: "validpattern",
		validMessageAttr			: "validmessage",
		validFuncAttr 				: "onvalidate",
		onInvalidAttr 				: "oninvalid",
		onValidAttr 				: "onvalid",
		validHLParentAttr			: "validhlparent",
		invalidHLBGColor			: "yellow",
		invalidHLFGColor			: "#000000",
		displayGlobalInvalidClass	: "err",
		displayInvalidClass			: "err_small",
		highlightInvalid			: true,
		alertGlobalInvalid			: true,
		alertEachInvalid			: false,
		alertCompiledInvalid		: false,
		displayGlobalInvalid		: false,
		displayEachInvalid			: false,
		displayCompiledInvalid		: false,
		globalInvalidMessage 		: "Several entries are invalid.\nPlease enter appropriate values in highlighted fields.",
		compiledInvalidMessage		: "Several entries are invalid:\n\n{compiledMessage}\nPlease enter appropriate values in highlighted fields."
	};
	
	this.setConfig = function(s)
	{
		for(var i in s)
		{
			$V.config[i] = s[i];
		}
	}
	
	this.validate = function(formRef,s)
	{	
		if(!(formRef && formRef.nodeName && formRef.nodeName.toUpperCase() == "FORM"))
		{
			if($V.config.isDebug)
			{
				errmsg ="Validator Function Error:\nForm object reference is INVALID";
				alert(errmsg);
			}
			return false;
		}

		if(formRef.submitted) return false;
		
		if(s)
			$V.setConfig(s);
		
		firstFocus 	= null;

		if($V.config.alertConfirm)
			if(!confirm("Are you sure?"))
				return false;
	
		for(i=0;i<formRef.length;i++)
		{
			invalid = false;

//*************************************************** VALIDATE WITH FUNCTION ***

			if(formRef[i].getAttribute($V.config.validFuncAttr) && !formRef[i].disabled && !formRef[i].readonly)
			{
				var funcResult = true;
				try
				{
					var funcResult = eval(formRef[i].getAttribute($V.config.validFuncAttr));
				}
				catch(e)
				{
					if($V.config.isDebug)
					{
						errmsg ="Validator Function Error:\n" +
						"    Evaluation of OnValidate attribute returned an Error " +
						"\n\nOnValidate:\n" +
						"    "  + formRef[i].getAttribute($V.config.validFuncAttr) +
						"\n\nName:\n" +
						"    "  + formRef[i].name +
						"\n\nId:\n" +
						"    "  + formRef[i].id
						alert(errmsg)
					}
				}
				if(!funcResult)
				{
					doIfInvalid(formRef[i]);
					invalid = true;
				}
				else
					doIfValid(formRef[i]);
			}
			else if(formRef[i].disabled)
			{
				doIfValid(formRef[i])
			}

//************************************************** VALIDATE WITH ATTRIBUTE ***	

			if(formRef[i].getAttribute($V.config.validPatternAttr) && !invalid && !formRef[i].disabled && !formRef[i].readonly)
			{
				switch(formRef[i].nodeName.toLowerCase())
				{
					case "input":
						var sType = formRef[i].type.toLowerCase()
						if(sType=="text" || sType=="password" || sType=="hidden" || sType=="file")
						{
							if(!validStringField(formRef[i]))
								doIfInvalid(formRef[i])
							else
								doIfValid(formRef[i])
						}
						else if(sType=="checkbox" || sType=="radio")
						{
							if(formRef[formRef[i].name].length)
							{
								if(!validMultiCheckField(formRef[formRef[i].name]))
									doIfInvalid(formRef[i])
								else
									doIfValid(formRef[i])
								i+=formRef[formRef[i].name].length-1
							}
							else
							{
								if(!validSinglCheckField(formRef[i]))
									doIfInvalid(formRef[i])
								else
									doIfValid(formRef[i])
							}
						}
					break
					case "textarea":
							if(!validStringField(formRef[i]))
								doIfInvalid(formRef[i])
							else
								doIfValid(formRef[i])
					break
					case "select":
						if(formRef[i].getAttribute("multiple"))
						{
							if(!validMultiSelectField(formRef[i]))
								doIfInvalid(formRef[i])
							else
								doIfValid(formRef[i])
						}
						else
						{
							if(!validSinglSelectField(formRef[i]))
								doIfInvalid(formRef[i])
							else
								doIfValid(formRef[i])
						}
					break
				}
			}
		}
		if(firstFocus)
			return doFinalyIfInvalid(formRef);
		else
			return doFinalyIfValid(formRef);
	}
	
	function doFinalyIfInvalid(formRef)
	{
		if($V.config.alertGlobalInvalid)
			alert($V.config.globalInvalidMessage.replace(/<br>/gi,"\n"));
		if($V.config.alertCompiledInvalid && compiledInvalidMsg.length>3)
			alert($V.config.compiledInvalidMessage.replace(/\{compiledMessage\}/gi, compiledInvalidMsg).replace(/<br>/gi,"\n"));
		
		if($V.config.displayGlobalInvalid)
			displayInvalid(formRef, $V.config.globalInvalidMessage.replace(/\n/gi,"<br>"), $V.config.displayGlobalInvalidClass);
		if($V.config.displayCompiledInvalid && compiledInvalidMsg.length>3)
			displayInvalid(formRef, $V.config.compiledInvalidMessage.replace(/\{compiledMessage\}/gi, compiledInvalidMsg).replace(/\n/gi,"<br>"), $V.config.displayGlobalInvalidClass);
		
		try{firstFocus.focus();}catch(e){}

		if(formRef.getAttribute($V.config.onInvalidAttr))	
		{
			try
			{
				eval(formRef.getAttribute($V.config.onInvalidAttr));
			}
			catch(e)
			{
				if($V.config.isDebug)
				{
					errmsg ="Validator Function Error:\n" +
					"    Evaluation of OnInvalid Form attribute returned an Error " +
					"\n\nOnInalid:\n" +
					"    "  + formRef.getAttribute($V.config.onInvalidAttr);
					alert(errmsg);
				}
			}
		}

		return false;
	}
	
	function doFinalyIfValid(formRef)
	{
		var submitToNew = (typeof event !== "undefined" && event.shiftKey && event.ctrlKey);	
		if(submitToNew && !formRef.submitToNew && (!newWin || newWin.closed))
		{	
			var newWin = open("about:blank","validator_newWin");	
			formRef.submitToNew = true;
			formRef.target_old 	= (formRef.target || "");
			formRef.target 		= "validator_newWin";
		}
		else if(!submitToNew)
		{
			formRef.target = (formRef.target_old || "");

			formRef.submitted = true;
			for(i=0;i<formRef.length;i++)
			{
				if((formRef[i].nodeName.toLowerCase()=="input" || formRef[i].nodeName.toLowerCase()=="button") && formRef[i].type.toLowerCase()=="submit")
					formRef[i].disabled = true;
			}
		}
		
		
		if(formRef.getAttribute($V.config.onValidAttr))	
		{
			try
			{
				eval(formRef.getAttribute($V.config.onValidAttr));
			}
			catch(e)
			{
				if($V.config.isDebug)
				{
					errmsg ="Validator Function Error:\n" +
					"    Evaluation of OnValid Form attribute returned an Error " +
					"\n\nOnValid:\n" +
					"    "  + formRef.getAttribute($V.config.onValidAttr);
					alert(errmsg);
				}
			}
		}

		return true;
	}
	
	function findParent(objRef)
	{
		var
			HLParrentTag = objRef.getAttribute($V.config.validHLParentAttr),
			HLParrentRef = objRef
		while(HLParrentRef.nodeName.toLowerCase()!=HLParrentTag)
			HLParrentRef = HLParrentRef.parentNode
	
		return(HLParrentRef)
	}
	
	function doIfInvalid(objRef)
	{
		if($V.config.highlightInvalid)
		{
			if(objRef.getAttribute($V.config.validHLParentAttr))
			{
				var HLParrentRef = findParent(objRef)
				if(!HLParrentRef.backgroundColor_old)
				{
					if(HLParrentRef.currentStyle) //IE
					{
						HLParrentRef.backgroundColor_old = HLParrentRef.currentStyle.backgroundColor
						HLParrentRef.color_old = HLParrentRef.currentStyle.color
					}
					else if(window.getComputedStyle) //MOZ
					{
						HLParrentRef.backgroundColor_old = window.getComputedStyle(HLParrentRef,null).backgroundColor
						HLParrentRef.color_old = window.getComputedStyle(HLParrentRef,null).color
					}
					else
					{
						HLParrentRef.backgroundColor_old = "#ffffff"
						HLParrentRef.color_old = "#000000"
					}
				}
				HLParrentRef.style.backgroundColor = $V.config.invalidHLBGColor
				HLParrentRef.style.color = $V.config.invalidHLFGColor
	
				if(!firstFocus)
				{
					if(objRef.length)
						firstFocus = objRef[0]
					else if((objRef.type && objRef.type != "hidden") || (!objRef.type))
						firstFocus = objRef
				}
			}
			else
			{
				if(!objRef.backgroundColor_old)
				{
					if(objRef.currentStyle) //IE
					{
						objRef.backgroundColor_old = objRef.currentStyle.backgroundColor
						objRef.color_old = objRef.currentStyle.color
					}
					else if(window.getComputedStyle) //MOZ
					{
						objRef.backgroundColor_old = window.getComputedStyle(objRef,null).backgroundColor
						objRef.color_old = window.getComputedStyle(objRef,null).color
					}
					else
					{
						objRef.backgroundColor_old = "#ffffff"
						objRef.color_old = "#000000"
					}
				}
				objRef.style.backgroundColor = $V.config.invalidHLBGColor
				objRef.style.color = $V.config.invalidHLFGColor
			}
		}
		if($V.config.alertEachInvalid && objRef.getAttribute($V.config.validMessageAttr))
			alert(objRef.getAttribute($V.config.validMessageAttr));
		if($V.config.displayEachInvalid && objRef.getAttribute($V.config.validMessageAttr))
			displayInvalid(objRef, objRef.getAttribute($V.config.validMessageAttr), $V.config.displayInvalidClass);
		if($V.config.alertCompiledInvalid && objRef.getAttribute($V.config.validMessageAttr))
			compiledInvalidMsg +=  objRef.getAttribute($V.config.validMessageAttr) + "\n";
		if(!firstFocus && ((objRef.type && objRef.type != "hidden") || (!objRef.type)))
			firstFocus = objRef;
			
		if(objRef.getAttribute($V.config.onInvalidAttr))	
		{
			try
			{
				eval(objRef.getAttribute($V.config.onInvalidAttr));
			}
			catch(e)
			{
				if($V.config.isDebug)
				{
					errmsg ="Validator Function Error:\n" +
					"    Evaluation of OnInvalid attribute returned an Error " +
					"\n\nOnInvalid:\n" +
					"    "  + objRef.getAttribute($V.config.onInvalidAttr) +
					"\n\nName:\n" +
					"    "  + objRef.name +
					"\n\nId:\n" +
					"    "  + objRef.id
					alert(errmsg)
				}
			}
		}
	}
	
	function doIfValid(objRef)
	{
		if($V.config.highlightInvalid)
		{
			if(objRef.getAttribute($V.config.validHLParentAttr))
			{
				var HLParrentRef = findParent(objRef);
				HLParrentRef.style.backgroundColor = HLParrentRef.backgroundColor_old;
				HLParrentRef.style.color = HLParrentRef.color_old;
			}
			else
				objRef.style.backgroundColor = objRef.backgroundColor_old;
		}
		if($V.config.displayEachInvalid && objRef.getAttribute($V.config.validMessageAttr))
			hideInvalid(objRef, $V.config.displayInvalidClass);
		
		if(objRef.getAttribute($V.config.onValidAttr))	
		{
			try
			{
				eval(objRef.getAttribute($V.config.onValidAttr));
			}
			catch(e)
			{
				if($V.config.isDebug)
				{
					errmsg ="Validator Function Error:\n" +
					"    Evaluation of OnValid attribute returned an Error " +
					"\n\nOnValid:\n" +
					"    "  + objRef.getAttribute($V.config.onValidAttr) +
					"\n\nName:\n" +
					"    "  + objRef.name +
					"\n\nId:\n" +
					"    "  + objRef.id
					alert(errmsg)
				}
			}
		}
	}
	
	function validStringField(objRef, sPattern)
	{
		strToValid = objRef.value
		sPattern = sPattern || objRef.getAttribute($V.config.validPatternAttr)
		try
		{
			var rgxp = new RegExp(sPattern,"gi")
		}
		catch(e)
		{
			if($V.config.isDebug)
			{
				errmsg ="Validator Function Error:\n" +
				"    " + e.description +
				"\n\nPattern String:\n" +
				"    "  + sPattern +
				"\n\nForm Control Name:\n" +
				"    "  + objRef.name +
				"\n\nForm Control Id:\n" +
				"    "  + objRef.id
				alert(errmsg)
			}
			return(false)
		}
		return(rgxp.test(strToValid))
	}
	
	function validSinglCheckField(objRef)
	{
		if(objRef.getAttribute($V.config.validPatternAttr)==1)
			return(objRef.checked);
	}
	
	function validMultiCheckField(objRef, sPattern)
	{
		sPattern = sPattern || objRef[0].getAttribute($V.config.validPatternAttr);
		var strToValid="";
		for(j=0;j<objRef.length;j++)
			if(objRef[j].checked) strToValid+="v";
		return(new RegExp("^v" + sPattern + "$","gi").test(strToValid));
	}
	
	function validSinglSelectField(objRef, notValidIdexes)
	{
		notValidIdexes = notValidIdexes || objRef.getAttribute($V.config.validPatternAttr);
		selectedIndx = objRef.selectedIndex;

		var rgxp = new RegExp("(^|\\|)" + selectedIndx + "(\\||$)");
		return(!rgxp.test(notValidIdexes));
	}
	
	function validMultiSelectField(objRef, sPattern)
	{
		var strToValid = "";
		sPattern = "^v" + (sPattern || objRef.getAttribute($V.config.validPatternAttr)) + "$";
		for(j=0;j<objRef.options.length;j++)
			if(objRef.options[j].selected) strToValid += "v";
		return(new RegExp(sPattern,"gi").test(strToValid));
	}

	function displayInvalid(objRef, message, className)
	{
		var errRef = objRef.previousSibling;
		if(!errRef || errRef.className != className)
		{	
			errRef = document.createElement("SPAN");
			errRef.className = className;
			errRef.innerHTML = message;
			objRef.parentNode.insertBefore(errRef, objRef);
		}
		errRef.style.display = "block";
	}
	function hideInvalid(objRef, className)
	{
		var errRef = objRef.previousSibling;	
		if(errRef && errRef.className == className)
			errRef.style.display = "none";
	}
//******************************************************************************
//********************************************************* UTILITY FUNCTION ***
//******************************************************************************
	
	this.compareFields = function(id1,id2)
	{
		return(document.getElementById(id1).value == document.getElementById(id2).value);
	}
	
	this.testField = function(rgxp,id)
	{
		return rgxp.test(document.getElementById(id).value);
	}
	
	this.numsOnly = function(objRef)
	{
		var pattern = "[^\\d";
		if(arguments.length>1)
		{
			for(i=1;i<arguments.length;i++)
				pattern += arguments[i];
		}
		pattern += "]";
		var rgxp = new RegExp(pattern,"gi");
		if(rgxp.test(objRef.value))
			objRef.value = objRef.value.replace(rgxp,"");
	}
	
	this.validDayOfMonth = function(yid,mid,did)
	{
		var y = document.getElementById(yid).selectedIndex,
			m = document.getElementById(mid).selectedIndex,
			d = document.getElementById(did).selectedIndex;
		if(m==2 && d>=29 && document.getElementById(yid).options[y].value%4==0)
			d = 29;
		else if(m==2 && d>28)
			d = 28;
		else if((m==4 || m==6 || m==9 || m==11) && d>30)
			d = 30;
		document.getElementById(did).selectedIndex = d;
	}

	this.checkLengthOnInput = function(objRef, maxLength)
	{
		if(objRef.value.length > maxLength)
		{
			objRef.value = objRef.value.substr(0,maxLength);
			objRef.focus();
		}
	}
	this.parseDigits = function(str)
	{
		if(typeof str == "string" || typeof str == "number")
		{
			str = str.toString().replace(/\D+/gi,"");
			return str;
		}
		else
			return "";
	}
//******************************************************************************
//************************************************************ DOCUMENTASION ***
//******************************************************************************

/*===================================================================validate===

Add to FORM tag: onsubmit="return $V.validate(this,{settingsObject})"
	
-------------------------------------------------------------------------------
validPatternAttr 		- HTML attribute name - contains RegExp validation pattern
-------------------------------------------------------------------------------
validMessageAttr 		- HTML attribute name - contains message displayed to user if invalid
-------------------------------------------------------------------------------
validFuncAttr 			- HTML attribute name - contains additional validation function
-------------------------------------------------------------------------------
validHLParentAttr 		- HTML attribute name - contains HTML ancestor TAG which 
							will be highlighted if invalid
-------------------------------------------------------------------------------
highlightInvalid 		- If true invalid controls will be highlighted
-------------------------------------------------------------------------------
alertGlobalInvalid 		- If true general invalid alert will be displayed
-------------------------------------------------------------------------------
alertEachInvalid 		- If true for each invalid control alert with <validMessage> will be displayed
-------------------------------------------------------------------------------
alertCompiledInvalid 	- If true single alert with all <validMessage> will be displayed
-------------------------------------------------------------------------------
displayGlobalInvalid 	- If true general invalid error will be displayed above the form
-------------------------------------------------------------------------------
displayEachInvalid 		- If true for each invalid control error with <validMessage> 
							will be displayed above the control
-------------------------------------------------------------------------------
displayCompiledInvalid 	- If true single error with all <validMessage> will be displayed above the form
-------------------------------------------------------------------------------
alertConfirm 			- If true user will be asked for confirmation before taking submiting the form
-------------------------------------------------------------------------------
isDebug 				- IF true alert on errors
-------------------------------------------------------------------------------
firstFocus 				- At end off validation contains first invalid field to set focus to
-------------------------------------------------------------------------------
formRef.submitted 		- Custom property set to true in doFinalyIfValid function
 							at first submit to prevent multiple submits
-------------------------------------------------------------------------------
invalidHLBGColor 		- Background color value to set to invalid controls
-------------------------------------------------------------------------------
invalidHLFGColor 		- Text color value to set to invalid controls
-------------------------------------------------------------------------------

*Set validpattern to 1 to make SINGLE RADIO, CHECKBOX REQUIRED
*For SINGLE SELECT validpattern to numbers of invalid option indexes
	separated by | (pipe character)
	To set first option as invalid selection set validpattern to 0
*In collection of radios, checkboxes validpattern MUST be contained if FIRST control
*In MULTIPLE select, radio and checkbox set validpattern to "{num_1,num_2}"
	num_1 number of MINEMUM required selections
	num_2 number of MAXIMUM required selections
		not setting num_2 makes maximum infenitive: "{num_1,}"

=================================================================doIfInvalid===

What to do if SINGLE CONTROL IS NOT valid.
-------------------------------------------------------------------------------
	objRef - current control reference
-------------------------------------------------------------------------------
*This function may be changed to serve your needs
	by default the background color of INVALID control changed to "invalidHLBGColor"

===================================================================doIfValid===

What to do if SINGLE CONTROL IS valid. Used to reset changes made by doIfInvalid()
-------------------------------------------------------------------------------
	objRef - current control reference
-------------------------------------------------------------------------------
*This function may be changed to serve your needs
	by default the background color of VALID control changed to #ffffff

===========================================================doFinalyIfInvalid===

What to do AT THE END of validation if INVALID control found

===========================================================doFinalyIfInvalid===

What to do AT THE END of validation if all controls validated to true
	By default nothing. Just return true to enable submit.

==================================================================findParent===

Helper function to find parent tag reference for highlighting invalid control

===============================================================compareFields===

compareFields(id1, id2)
	return compareFields("userPass", "userPass_2")	
-------------------------------------------------------------------------------
id1 - ID of first field
-------------------------------------------------------------------------------
id2 - ID if second field
-------------------------------------------------------------------------------

Compare 2 TEXT fields for new user (pass, mail)

====================================================================numsOnly===

onkeyup="return numsOnly(this)" - Add to TEXT type INPUTs to block all but numeric data
To add additional characters add them as arguments to function call
if a char need to be escaped in REGEXP  double escape it:
onkeyup="return numsOnly(this,'\\.','@')"

=============================================================validDayOfMonth===

onchange="validDayOfMonth('yid','mid','did')" - Add to 3 - SELECT tags
Used to set correct day in dates when 3 SELECTs used (year, month, day)
-------------------------------------------------------------------------------
	yid - year SELECT tag id
-------------------------------------------------------------------------------
	mid - month SELECT tag id
-------------------------------------------------------------------------------
	did - day SELECT tag id

=====================================================================REGEXPs===

-------------------------------------------------------------------------------
EMAIL		^\w[-._\w]*\w.?@\w[-._\w]*\w\.\w{2,4}$
			RFC 822: ^([^\[\]()<>@,;:\\".]+|\"([^"\\\r]|\\.)*\")(\.([^\[\]()<>@,;:\\".]+|\"([^"\\\r]|\\.)*\"))*@(\[([^\\\[\]\r]|\\.)*\]|[^\[\]()<>@,;:\\".]+)(\.(\[([^\\\[\]\r]|\\.)*\]|[^\[\]()<>@,;:\\".]+))*$
-------------------------------------------------------------------------------
NIC			^[A-Za-z0-9]{4,12}$
-------------------------------------------------------------------------------
PASS		^[A-Za-z0-9]{4,12}$
-------------------------------------------------------------------------------
TELEPHONES 	^((05[02479])|(07[267])|(0[23489]))-?\d{7}$
-------------------------------------------------------------------------------

******************************************************************************/
}
