/*********************************************************************
JavaScript 1.2 Validation Script (IE and Netscape)
	version 1.0.0

There are no warranties expressed or implied.  This script may be
re-used and distrubted freely provided this header remains intact.

If you are interested in keeping up with the latest releases of this
script or asking questions about its implementation, think about joining
the Incysive Groups discussion forum dedicated to Forms Validator:

NOTE : This script is based on matthew frank validation 

	http://www.incysivemedia.com/DWHelpExtension/FormsValidator/forum.asp
******************************************************************************/

function FormsValidator()
{
	this.ERR_MINLENGTH		= "Please enter a value at least #MINLENGTH characters";
	this.ERR_MAXLENGTH 		= "Please enter a value less than #MAXLENGTH characters";
	this.ERR_REAL			= "Please enter a valid real";
	this.ERR_CURRENCY		= "Please enter a valid currency";
	this.ERR_DATE			= "Please enter a valid date";
	this.ERR_MIN			= "Please enter a value greater or equal to #MIN";
	this.ERR_MAX			= "Please enter a value less or equal to #MAX";
	this.ERR_INTEGER		= "Please enter a valid integer";
	this.ERR_REQUIRED		= "Please enter a value";
	this.ERR_REGEXP 		= "Please enter correct regular expression";
	this.ERR_MASK			= "Please enter mask like #MASK";
	this.isDOMCompliant 	= !!document.getElementById;
	this.isInitialFocusSet	= false;
	this.initialFocus		= "";
}

/*======================================
 *	Function: setProperty
 *	Purpose:  Set property value of element
 *	Inputs:   object   - object reference
 *	          property - string
 *	          value    - value to give property
 *	Returns:  undefined
 =====================================*/
FormsValidator.prototype.setProperty=function(object,property,value){
	if(object.setAttribute)
		object.setAttribute(property,value);
	else
		object[property]=value;
}

/*======================================
 *	Function: getProperty
 *	Purpose:  Retrieve property value of element
 *	Inputs:   object   - object reference
 *	          property - string
 *	Returns:  variant
 *	NOTE: IE supports case-sensitivity with the getAttribute method.
 =====================================*/
FormsValidator.prototype.getProperty=function(object, property){
	var returnValue;
	if(object){
		returnValue = object[property];
		if(!this.propertyOn(returnValue) && object.getAttribute)
			returnValue=object.getAttribute(property);
	}
	return returnValue;
}

/*======================================
 *	Function: propertyOn
 *	Purpose:  Check that at least one property is turned on (defined, non-null, non-false)
 *	Inputs:   attribute list - values of attributes (e.g. results of getProperty call)
 *	Returns:  boolean
 =====================================*/
FormsValidator.prototype.propertyOn=function(/* attribute list */){
	var isOn,attribute,length=arguments.length;
	for(var i=0;i<length;i++){
		attribute = arguments[i];
		if(typeof attribute=="string")attribute=attribute.toLowerCase();
		isOn = typeof attribute!="undefined" &&
		       attribute!=null &&
			   attribute!="false" &&
			   attribute!="off" &&
		       attribute!=false;
		if(this.isDOMCompliant) isOn &= (attribute!="");
		if(isOn) break;
	}
	return !!isOn;
}

/*======================================
 *	Function: trim
 *	Purpose:  Remove leading and trailing spaces
 *	Inputs:   string
 *	Returns:  string
 =====================================*/
String.prototype.trim=function(){
	return string.replace(/^\s+/,"").replace(/\s+$/,"");	
}

/*======================================
 *	Function: pad
 *	Purpose:  Left pad a number with zeros to a given width
 *	Inputs:   value, width (defaults to 2)
 *	Returns:  numeric string of width characters
 =====================================*/
FormsValidator.prototype.pad=function(value, width){
	width=this.choose(width,2);
	var returnValue=value.toString();
	for(var i=width-value.length;i>0;i--)
		returnValue="0"+returnValue;
	return returnValue;
}

/*======================================
 *	Function: toFunction
 *	Purpose:  Transforms value into function if it is not
 *	Inputs:   value - function pointer
 *	Returns:  function
 =====================================*/
FormsValidator.prototype.toFunction=function(value){
	if(value){
		if(typeof value!="function")
			value = new Function(value);
	}else
		value = function(){return;}
	return value;
}
	
/*======================================
 *	Function: dateOrTime
 *	Purpose:  Determines whether a data type is date, time or datetime
 *	          Accepted tokens: d dd m mm yyyy hh hh24 nn ss ap
 *	Inputs:   format
 *	Returns:  string
 =====================================*/
FormsValidator.prototype.dateOrTime=function(format){
	var date=false,time=false;
	with(format){
		date=search(/mm?/i)>-1||search(/dd?/i)>-1||search(/yyyy/i)>-1;
		time=search(/hh?/i)>-1||search(/nn/i)>-1||search(/ss/i)>-1||search(/ap/i)>-1;
	}
	return (date?"date":"")+(time?"time":"");
}

/*======================================
 *	Function: toDate
 *	Purpose:  Converts string to date based on format
 *	          Accepted tokens: d dd m mm yyyy hh hh24 nn ss ap
 *	Inputs:   date, format
 *	Returns:  string (YYYYMMDDHH24NNSS), undefined indicates failure to match format
 =====================================*/
FormsValidator.prototype.toDate=function(date,format){
	var i, regex, index=new Array;
	var day, month, year, hour, minute, second, ampm;
	
	// Determine order of datetime tokens
	with(format){
		index[search(/dd?/i)]="day";
		index[search(/mm?/i)]="month";
		index[search(/yyyy/i)]="year";
		index[search(/hh/i)]="hour";
		index[search(/nn/i)]="minute";
		index[search(/ss/i)]="second";
		index[search(/ap/i)]="ampm";

		// timing of replaces is quite important!
		regex=format.replace(/(\$|\^|\*|\(|\)|\+|\.|\?|\\|\{|\}|\||\[|\])/g,"\\$1");
	
		// only allow one pass for day and month
		if(search(/dd/i)>-1)
			regex=regex.replace(/dd/i,"(0[1-9]|[1-2]\\d|3[0-1])");
		else
			regex=regex.replace(/d/i,"(0?[1-9]|[1-2]\\d|3[0-1])");
	
		if(search(/mm/i)>-1)
			regex=regex.replace(/mm/i,"(0[1-9]|1[0-2])");
		else
			regex=regex.replace(/m/i,"(0?[1-9]|1[0-2])");
	
		regex=regex.replace(/nn/i,"([0-5]\\d)")
				.replace(/ss/i,"([0-5]\\d)")
				.replace(/yyyy/i,"(\\d{4})")
				.replace(/\s+/g,"\\s*");
		if(search(/hh24/i)>-1)
			regex=regex.replace(/hh24/i,"([0-1]\\d|2[0-3])");
		else
			regex=regex.replace(/hh/i,"(0\\d|1[0-2])").replace(/ap/i,"([ap]m?)");
	}
	
	// test date against format
	if(!new RegExp("^"+regex+"$","i").test(date))
		return;
	
	// set values from user input
	year=month=day=hour=minute=second=0,ampm="";
	for(var key=0,i=0;key<index.length;key++)
		if(index[key]) eval(index[key]+"=RegExp.$"+ ++i);

	// set default values
	if(hour<12&&/^pm?$/i.test(ampm))
		hour+=12;
	else if(hour==12&&/^am?$/i.test(ampm))
		hour=0;
	if(year==0) year=1;
	if(month==0) month=1;
	if(day==0) day=1;

	// check days in month
	if(month==2 && day>((year%4==0&&year%100!=0||year%400==0)?29:28) || day>((month-1)%7+1)%2+30)
		return;

	// build result value
	return ""+this.pad(year,4)+this.pad(month)+this.pad(day)+this.pad(hour)+this.pad(minute)+this.pad(second);
}

/*======================================
 *	Function: choose
 *	Purpose:  Return the first non-null, non-empty parameter value
 *	Inputs:   variant list
 *	Returns:  variant
 =====================================*/
FormsValidator.prototype.choose=function(/* list */){
	var i, value, iArguments=arguments.length;
	for(i=0;i<iArguments;i++){
		value = arguments[i];
		if(typeof value!="undefined" && value!=null && value!="")
			return value;
	}
}

/*======================================
 *	Function: getValueOf
 *	Purpose:  Return the value of a form field as seen at server
 *	Inputs:   element - form field
 *	Returns:  variant
 =====================================*/
FormsValidator.prototype.getValueOf=function(element){
	var returnValue=null;
	switch (element.type){
		case "text" : case "textarea" : case "file" : case "password" : case "hidden" :
			returnValue = element.value;
			break;
		case "select-one" :
			if(element.selectedIndex>=0)
				returnValue=element.options[element.selectedIndex].value;
			break;
		case "select-multiple" :
			for(var i=0,iOptions=element.options.length; i<iOptions; i++)
				if(element.options[i].selected && trim(element.options[i].value.toString())){
					returnValue=true;
					break;
				}
			break;
		case "radio" : case "checkbox" :
			returnValue=element.checked;
			break;
		default:
			returnValue = null;
	}
	if (this.propertyOn(this.getProperty(element,"format"))) {
		if (this.getProperty(element,"realValue"))  
			returnValue = this.getProperty(element,"realValue");
	}		
	return returnValue;
}

/*======================================
 *	Function: isValidForm
 *	Purpose:  Validate a form's fields based on the attributes provided in the HTML text
 *	Inputs:   form - HTML form object
 *	Returns:  boolean
 =====================================*/
FormsValidator.prototype.isValidForm=function(form){
	var i,iElements,orderBy,position;
	var element,elementList = form.elements;
	this.restoreForm(form);
		
	// Execute onbeforevalidate processing
	if(form.onbeforevalidate()==false)
		return false;
		
	// Check Form logical expression
	if (!this.CheckExp(form))
		return false;
	
	// Validate inspanidual elements
	var validForm = true;
	for(i=0,iElements=elementList.length;i<iElements;i++) {
		if (!elementList[i].validate()) 
			validForm = false;
	}
	if (!validForm) {
		this.displayErrors(form);
		return false;
	}	
	
	// Unformatted Element (submitFormat="on")
	for(i=0,iElements=elementList.length;i<iElements;i++) {
		this.cancelFormat(elementList[i]);
	}	
	
	// Execute onaftervalidate processing
	if(form.onaftervalidate()==false)
		return false;
	
	return true;
}

/*======================================
 *	Method:  FormsValidator.CheckExp
 *	Purpose: Check logical form conditions
 *	Inputs:  None
 *	Returns: True
 =====================================*/
FormsValidator.prototype.CheckExp=function(){
	return true;
}

/*======================================
 *	Method:  FormsValidator.keyPressMask
 *	Purpose: Set keyPressMask
 *	Inputs:  mask , regExp
 *	Returns: Current Mask
 =====================================*/
FormsValidator.prototype.keyPressMask=function(mask,regExp){
	if (mask != "") {
		if (mask.indexOf(regExp)==-1)
			mask = mask + "|" + regExp;
	} else {
		mask = mask + regExp;
	} 
	return mask;
}

/*======================================
 *	Method:  FormsValidator.setElement
 *	Purpose: Create element handler
 *	Inputs:  elememt
 *	Returns: undefined
 =====================================*/
FormsValidator.prototype.setElement = function(element)	{
	if(!this.isInitialFocusSet && this.propertyOn((this.initialFocus=this.getProperty(element,"initialfocus")))){
		element.focus();
		if(/^select$/i.test(this.initialFocus)) element.select();
		this.isInitialFocusSet = true;
	}
	
	// Capture existing event handlers
	element._onkeypress_		= this.toFunction(this.getProperty(element,"onkeypress"));
	element._onchange_			= this.toFunction(this.getProperty(element,"onchange"));
	element._onblur_			= this.toFunction(this.getProperty(element,"onblur"));
	element._onfocus_			= this.toFunction(this.getProperty(element,"onfocus"));
	element._onpropertychange_	= this.toFunction(this.getProperty(element,"onpropertychange"));

	// Create methods on element
	element.onkeypress			= function(oEvent){return FormsValidator.onkeypress(this,oEvent)};
	element.onchange			= function(oEvent){return FormsValidator.onchange(this)};
	element.onblur				= function(oEvent){return FormsValidator.onblur(this)};
	element.onfocus				= function(oEvent){return FormsValidator.onfocus(this)};
	element.validate			= function(){return FormsValidator.isValidElement(this)}
	element.onbeforevalidate	= this.toFunction(this.getProperty(element,"onbeforevalidate"));
	element.onvalidate			= this.toFunction(this.getProperty(element,"onvalidate"));
	element.onaftervalidate		= this.toFunction(this.getProperty(element,"onaftervalidate"));
	element.onautosubmit		= this.toFunction(this.getProperty(element,"onautosubmit"));
	element.onreset				= this.toFunction(this.getProperty(element,"onreset"));
	element.onpropertychange	= function(oEvent){
		oEvent=FormsValidator.choose(oEvent, window.event);
		if(oEvent.propertyName && oEvent.propertyName =="required")
			this.form.markRequired();
		if(this._onpropertychange_)this._onpropertychange_(oEvent);
	}
	element._=true;
}						

/*======================================
 *	Method:  FormsValidator.onkeypress
 *	Purpose: Set up keyPress handler
 *	Inputs:  none
 *	Returns: true / false
 =====================================*/
FormsValidator.prototype.onkeypress=function(element,oEvent){
	
	// Replace onkeypress event handler
	oEvent=FormsValidator.choose(oEvent, window.event);
	if(element._onkeypress_ && element._onkeypress_(oEvent)==false) return false;
		
	// Check mask attribute
	var mask=this.getProperty(element,"mask");
	if(this.propertyOn(mask)){
		oEvent=this.choose(oEvent, window.event);
		var keyCode=this.choose(oEvent.which,oEvent.keyCode);
		var keyChar=String.fromCharCode(keyCode);
			
		// Authorized : "Backspace","Delete";
		if(keyCode==8 || keyCode==46) 	
			return true;
			
		// Unauthorized : "Arrows";
		if(keyCode==36 || keyCode==37 || keyCode==38 || keyCode==39) 	
			return false;
			
		// Stored element value position
		var iElementPosition = element.value.length;
			
		// Check # parameter
		if (mask.charAt(0) == "#" && element.value.charAt(0) != "-" && iElementPosition != 0) 
			iElementPosition = iElementPosition + 1;
			
		// Build Reg Exp
		var sCurrentMask = "";
		var sRegExp= ""; 
		var sDataType = this.getProperty(element,"datatype")	;		
		sCurrentMask = mask.substring(iElementPosition,iElementPosition+1);
		switch (sCurrentMask) {
			case "9" : case "Y" : case "M" : case "D" : case "H" : case "N" : case "S" : // 9 - Digit 
				sRegExp = this.keyPressMask(sRegExp,"[0-9]");
				if ((sDataType == "real" || sDataType == "currency") && mask.indexOf(".") != -1 && iElementPosition != 0) {
					if (element.value.indexOf(".") == -1) {
						sRegExp = this.keyPressMask(sRegExp,".");
					} else {
						if (this.decimalNumber(element.value) < this.decimalNumber(mask)) {
							sRegExp = this.keyPressMask(sRegExp,"[0-9]");
						} else {
							return false;
						} 					
					}
				}
				break;			
			case "#" :	// # - Digit or [+] or [-] 
				sRegExp = this.keyPressMask(sRegExp,"[0-9-]");
				break;		
			case "C" :	// C - Characters
				sRegExp = this.keyPressMask(sRegExp,"[A-Za-z]");					
				break;		
			case "L" :	// L - Characters or Digit
				sRegExp = this.keyPressMask(sRegExp,"[A-Za-z0-9]");					
				break;	
			case "W" :	// W - All Characters
				sRegExp = this.keyPressMask(sRegExp,"\\w");					
				break;				
			case "A" :	// A - [A;P]
				sRegExp = this.keyPressMask(sRegExp,"[A|a|P|p]");		
				break;				
			case "P" :	// P - [M]
				sRegExp = this.keyPressMask(sRegExp,"[M|m]");		
				break;		
			case "." :	// Decimal Point
				if (sDataType == "real" || sDataType == "currency") {
					if (element.value.indexOf(".") != -1) {
						if (this.decimalNumber(element.value) < this.decimalNumber(mask)) {
							sRegExp = this.keyPressMask(sRegExp,"[0-9]");
						} else {
							return false;
						} 		
					} else {
						sRegExp =  this.keyPressMask(sRegExp,"\\" + sCurrentMask);							
					}
				} else {
					sRegExp =  this.keyPressMask(sRegExp,"\\" + sCurrentMask);		
				}
			default : // Others
				sRegExp =  this.keyPressMask(sRegExp,"\\" + sCurrentMask);		
				break;				
		}
		sRegExp = "^" + sRegExp + "$";
			
		// Test current regular expression
		var oRegExp = new RegExp(sRegExp);
		if(keyCode!=0 && keyCode!=9 && keyCode!=13 && keyCode!=10 && !oRegExp.test(keyChar)) {
			oEvent.returnValue = false;
			return false;
		} else {
			
		}	
	}
	
	// Check filter attributes
	var filter=this.getProperty(element,"filter");
	if(this.propertyOn(filter)){
		var sKey=String.fromCharCode(oEvent.keyCode);
		var re=new RegExp(sFilter);
	
		// Do not filter out ENTER!
		if(sKey!="\r" && !re.test(sKey))
			oEvent.returnValue=false;
		oEvent.keyCode=sKey.charCodeAt(0);
	}
	return true;
}

/*======================================
 *	Method:  FormsValidator.onchange
 *	Purpose: Replace onchange event handler
 *	Inputs:  none
 *	Returns: true / false
 =====================================*/
FormsValidator.prototype.onchange=function(element){
	this.restoreElement(element);
	if(this.propertyOn(this.getProperty(element, "validateOnChange"),this.getProperty(element.form, "validateOnChange"),this.getProperty(element, "format"))){
		if(element.validate()) this.deleteError(element);
		this.displayErrors(element.form);						
	}
	if(element._onchange_ && element._onchange_()==false)
		return false;
	var autoSubmit = this.getProperty(this, "autoSubmit");
	if(this.propertyOn(autoSubmit) && element.onautosubmit()!=false && element.form.onautosubmit()!=false)
		element.form.submit();
}

/*======================================
 *	Method:  FormsValidator.onblur
 *	Purpose: Replace onblur event handler
 *	Inputs:  none
 *	Returns: true / false
 =====================================*/
FormsValidator.prototype.onblur=function(element){
	if(this.propertyOn(this.getProperty(element, "format"))){
		this.formatElement(element)
		if(element._onblur_ && element._onblur_()==false)
			return false;
	}		
}


/*======================================
 *	Method:  FormsValidator.onfocus
 *	Purpose: Set up keyPress handler
 *	Inputs:  none
 *	Returns: true / false
 =====================================*/
FormsValidator.prototype.onfocus=function(element){
	if (this.propertyOn(this.getProperty(element,"format"))) {
		if (this.getProperty(element,"realValue")) { 
			element.value = this.getProperty(element,"realValue");
		}		
		if (element.createTextRange) {
			var r = element.createTextRange();
			if (r) {
				r.moveStart('character', element.value.length);
				r.collapse();
				r.select();
			}			
		}		
	}	
}

/******************************************************************************
 *	Function: isValidElement
 *	Purpose:  Validate an element based on the attributes provided in the HTML text
 *  @property	nospace 			all whitespace is removed from the field.
 *  @property	uppercase			all letters become uppercase.
 *  @property	lowercase			all letters become lowercase.
 *  @property	minLen				defines the minimum len value the field may have. 
 *  @property	maxLen				defines the maximum len value the field may have.
 *  @property	format				the field must contain a valid date as specified by the property (e.g. date="YYYY/MM/DD").
 *  @property	floatPoint			the field must contain a valid floating point number. The value of the attribute (e.g., float=","). 
 *  @property	signed				when used this attribute further allows the user to use plus (+) or minus (-) sign in element.
 *  @property	min 				defines the minimum value the field may have. 
 *  @property	max 				defines the maximum value the field may have.
 *  @property	required			the field must have a non-whitespace value.
 *  @property	regexp				the field value must be consistent with the given regular expression.
 *  @property	mask				the mask allows you to define an expected format for the given field.
 *  @property	filter				only the specified key characters are accepted as input.
 *  @property	and 				if the field contains a value, all the fields whose names appear in this comma-delimited list must also contain values.
 *  @property	or					if the field does not contain a value, at least one of the fields whose names appear in this comma-delimited list must contain a value. Use this FormsValidator on the default field for the group.
 *  @property	span 				span ID for displayin g error message for this element.
 *	Inputs:   element - form field
 *	Returns:  boolean
 ******************************************************************************/
FormsValidator.prototype.isValidElement=function(element){

	// Do not validate label or fieldset elements
	if(typeof element.type == "undefined"||element.__||this.propertyOn(this.getProperty(element,"disabled"))||this.propertyOn(this.getProperty(element,"readOnly")))
		return true;
	element.__=true;

	var sValue=this.getValueOf(element);
	
	// Execute onbeforevalidate processing
	if(element.onbeforevalidate()==false)
		return false;
	
	//======================================
	// Check SPECIFIC attributes by type
	//======================================
	if (!this.isAbsent(sValue)) {
		switch (this.getProperty(element,"datatype")){
		
			//======================================
			// Check STRING specifics attributes
			//======================================
			case "string" :

				// NOSPACE
				if (this.propertyOn(this.getProperty(element,"nospace")))
					element.value = element.value.replace(/\s/g,"");
	
				// UPPERCASE
				if (this.propertyOn(this.getProperty(element,"uppercase")))
					element.value=element.value.toUpperCase();
	
				// LOWERCASE
				if (this.propertyOn(this.getProperty(element,"lowercase"))) 
					element.value=element.value.toLowerCase();	
					
				// MINLENGTH
				var sMinLen = parseInt(this.getProperty(element,"minlength"));
				if (sMinLen > 0) { 
					if (sValue.length < sMinLen) {
						this.addError(element, this.ERR_MINLENGTH.replace("#MINLENGTH",sMinLen),"Minlength");
						return false;
					}	
				}	
				
				// MAXLEN
				var sMaxLen = parseInt(this.getProperty(element,"maxlength"));
				if (sMaxLen > 0) { 
					if (sValue.length > sMaxLen) {
						this.addError(element, this.ERR_MAXLENGTH.replace("#MAXLENGTH",sMaxLen),"Maxlength");
						return false;
					}	
				}	
				break;
				
			//======================================
			// Check DATETIME specifics attributes
			//======================================
			case "datetime" :
				
				// MASK
				var sMask=this.getProperty(element,"mask");
				if(sMask==""||typeof sMask!="string") sMask="MM/DD/YYYY";
				var iMin = this.getProperty(element,"min");
				var iMax = this.getProperty(element,"max");
				var minDate=this.toDate(iMin,sMask);
				var maxDate=this.toDate(iMax,sMask);

				// Check Date
				if(typeof (sDate=this.toDate(sValue,sMask))=="undefined") {
					this.addError(element, this.ERR_MASK.replace("#MASK",sMask),"Datatype");
					return false;
				}
				
				// MIN
				if(this.propertyOn(iMin)&& typeof minDate!="undefined" && sDate<minDate) {
					this.addError(element, this.ERR_MIN.replace("#MIN",iMin),"Min");
					return false;
				}	
								
				// MAX
				if(this.propertyOn(iMax)&&typeof maxDate!="undefined" && sDate>maxDate) {
					this.addError(element, this.ERR_MAX.replace("#MAX",iMax),"Max");
					return false;
				}	
				break;
				
			//======================================
			// Check REAL specifics attributes
			//======================================
			case "real" :

				// REAL
				var bSigned = (this.getProperty(element,"mask").charAt(0) == "#");
				if(!new RegExp("^"+(this.propertyOn(bSigned)?"-?":"")+"(\\d*(,?\\d{3})*\\.?\\d+|\\d+(,?\\d{3})*\\.?\\d*)$").test(sValue)) {
					this.addError(element, this.ERR_REAL,"Datatype");
					return false;
				}
				
				// MIN
				sMin = this.getProperty(element,"min")
				if (this.propertyOn(sMin)) { 
					if (parseFloat(sValue) < parseFloat(sMin)) {
						this.addError(element, this.ERR_MIN.replace("#MIN",sMin),"Min");
						return false;
					}	
				}	
								
				// MAX
				sMax = this.getProperty(element,"max")
				if (this.propertyOn(sMax)) { 
					if (parseFloat(sValue) > parseFloat(sMax)) {
						this.addError(element, this.ERR_MAX.replace("#MAX",sMax),"Max");
						return false;
					}	
				}	
				break;
				
			//======================================
			// Check CURRENCY specifics attributes
			//======================================
			case "currency" :
				var bSigned = this.getProperty(element,"mask");
				if (bSigned) {
					bSigned = bSigned.charAt(0) == "#";
				} else {
					bSigned = false;
				}
				
				if(!new RegExp("^"+(this.propertyOn(bSigned)?"-?":"")+"(\\d*(,?\\d{3})*\\.?\\d+|\\d+(,?\\d{3})*\\.?\\d*)$").test(sValue)) {
					this.addError(element, this.ERR_CURRENCY,"Datatype");
					return false;
				}
			    
				// MIN
				sMin = this.getProperty(element,"min")
				if (this.propertyOn(sMin)) { 
					if (parseFloat(sValue) < parseFloat(sMin)) {
						this.addError(element, this.ERR_MIN.replace("#MIN",sMin),"Min");
						return false;
					}	
				}	
								
				// MAX
				sMax = this.getProperty(element,"max")
				if (this.propertyOn(sMax)) { 
					if (parseFloat(sValue) > parseFloat(sMax)) {
						this.addError(element, this.ERR_MAX.replace("#MAX",sMax),"Max");
						return false;
					}	
				}				    
				break;

			//======================================
			// Check INTEGER specifics attributes
			//======================================
			case "integer" :

				// INTEGER
				var bSigned = (this.getProperty(element,"mask").charAt(0) == "#");
				var re=new RegExp(((bSigned)?"[\\-\\+]?":"")+"\\d|\\s");
				if (!re.test(sValue)) {				
					this.addError(element, this.ERR_INTEGER,"Datatype");
					return false;
				}
				
				// MIN
				sMin = this.getProperty(element,"min")
				if (this.propertyOn(sMin)) { 
					if (parseInt(sValue) < parseInt(sMin)) {
						this.addError(element, this.ERR_MIN.replace("#MIN",sMin),"Min");
						return false;
					}	
				}	
								
				// MAX
				sMax = this.getProperty(element,"max")
				if (this.propertyOn(sMax)) { 
					if (parseInt(sValue) > parseInt(sMax)) {
						this.addError(element, this.ERR_MAX.replace("#MAX",sMax),"Max");
						return false;
					}	
				}	
				break;
		}
	}
			
	//======================================
	// Check GENERALS attributes
	//======================================
				
	// REQUIRED
	if(this.propertyOn(this.getProperty(element,"required")) && !sValue){
		if (element.type == "radio") {
			var i, iFields = element.form.elements[element.name].length;
			var bAccum = false;
			for(i=0; i<iFields; i++){
		
				// Search in the "elements" Collection 
				var oNewElement= element.form.elements[element.name][i];
				var sReturnValue = null;
				if(oNewElement.checked){
					sReturnValue = oNewElement.value ? oNewElement.value : true;
					this.restoreElement(oNewElement);
				}	
				bAccum |= !this.isAbsent(sReturnValue);		
			}
			if(!bAccum){
				this.addError(element, this.ERR_REQUIRED,"Required");
				return false;
			}
		} else {
			this.addError(element, this.ERR_REQUIRED,"Required");
			return false;
		}	
	}				
	
	// MASK
	var sMask = this.getProperty(element,"mask")
	if(sMask && sValue && this.getProperty(element,"datatype")!="datetime"){
		var sPattern=sMask.replace(/(\$|\^|\*|\(|\)|\?|\\|\{|\}|\||\[|\])/g,"\\$1");
		sPattern=sPattern.replace(/#/g ,"[-]?");
		sPattern=sPattern.replace(/9/g ,"\\d?");
		sPattern=sPattern.replace(/C/g ,"[A-Za-z]");
		sPattern=sPattern.replace(/L/g ,"[A-Za-z0-9]");
		sPattern=sPattern.replace(/W/g ,"\\w");
		sPattern=sPattern.replace(/AP/g ,"[A|a|P|p][M|m]");
		sPattern=sPattern.replace(".","\\.?");
		var re=new RegExp("^"+sPattern+"$");
		if(!re.test(sValue)){
			this.addError(element, this.ERR_MASK.replace("#MASK", sMask),"Mask");
			return false;
		}
	}
	
	// REGEXP
	if(this.propertyOn(oRegexp=this.getProperty(element,"regexp"))&& sValue){
		if(oRegexp.constructor!=RegExp)
			oRegexp = new RegExp(oRegexp, "i");
		if(!oRegexp.test(sValue)){
			this.addError(element, this.ERR_REGEXP,"Regexp");
			return false;
		}
	}
				
	// OR
	var sOr = this.getProperty(element,"or")
	var sIndex = new String(element.index);
	if (sIndex == "undefined")
		sIndex = false;
	if(sOr && !sValue){
		var aOr=sOr.split(/,/);
		var i, iFields=aOr.length;
		var bAccum = false;
		for(i=0; i<iFields; i++){
		
			// Search in the "elements" Collection 
			if (sIndex){
				var oNewElement = element.form.elements[aOr[i]][oSrc.index];
			} else {
				var oNewElement = element.form.elements[aOr[i]];
			}	
			bAccum |= !this.isAbsent(this.getValueOf(oNewElement));		
		}
		if(!bAccum){
			this.addError(element, this.ERR_REQUIRED,"Required");
			return false;
		}
	}

	// AND
	if(this.propertyOn(vAnd=this.getProperty(element,"and"))&&sValue){
		// If not an array, create one
		if(typeof vAnd == "string") vAnd=vAnd.toString().split(/,/);
		// Require each element in the list
		for(var oNewElement,i=0,iFields=vAnd.length; i<iFields; i++){
			oNewElement =(typeof vAnd[i].form=="object")?vAnd[i]:element.form.elements[vAnd[i]];
			if(oNewElement){
				if(!this.getValueOf(oNewElement)){
					this.addError(oNewElement, this.ERR_REQUIRED,"Required");
					return false;
				}
			}
		}
	}
	
	// Perform onvalidate event handler
	if(element.onvalidate()==false)
		return false;
	
	// Execute onaftervalidate processing
	if(element.onaftervalidate()==false)
		return false;
	
	// element is valid
	return true;
}

/*======================================
 *	Method:  FormsValidator.formatElement
 *	Purpose: Format current element
 *	Inputs:  Element
 *	Returns: none
 =====================================*/
FormsValidator.prototype.formatElement=function(element){
	
	if (!element.value) return false

	// Store non formatted value
	this.setProperty(element,"realValue",element.value) 

	sValue = String(element.value);
	formatValue = "";

	// Format Element	
	var format = this.getProperty(element,"format");
	var datatype = this.getProperty(element,"datatype");
	
	// Check Datetime Format
	if (datatype=="datetime") {
		this.formatDateTime(element)
		return true;	
	}	
		
	//  Fill in zeros (if necessary) to show two digits to the right 
    //  of the decimal
	if ((datatype == "real" || datatype=="currency")) {
		if (sValue.indexOf(".")== -1) {
			sValue = this.complete(sValue + ".","0",this.decimalNumber(format));
		} else {
			sValue = this.complete(sValue,"0",this.decimalNumber(format)-this.decimalNumber(sValue));
		}	
	}
	
	// Format Element
	var indexValue = sValue.length - 1;
	for(i=format.length-1;i!=-1;i--){
		switch (format.charAt(i)) {
			case "9" : case "." :
				if (indexValue != -1) {
					formatValue = sValue.charAt(indexValue) + formatValue;
					indexValue-- 
				}	
				break;
			case "#" :
				break;
			case "$" :
				break;
			case " " :
				if (indexValue != -1) {
					if (datatype == "real" || datatype=="currency" || datatype=="integer") {
						var re=new RegExp(/\d/);
						if(re.test(sValue.charAt(indexValue)))
							formatValue = format.charAt(i) + formatValue;					
					} else {
						formatValue = format.charAt(i) + formatValue;					
					}
				}	
				break;
			default :
				formatValue = format.charAt(i) + formatValue;				
		}
	}
	
	// Check for [#] Format
	if ((format.charAt(0)== "#"&&formatValue.charAt(0)!= "-")||(format.charAt(1)=="#"&&formatValue.charAt(1)!="-")) {
		if (element.value > 0) {
			formatValue = "+" + formatValue;				
		} else {
			formatValue = "-" + formatValue;				
		}
	}
	
	// Check for [$] Format
	if (format.charAt(0)== "$")
		formatValue = "$" + formatValue;
	element.value = formatValue;
}

/*======================================
 *	Method:  FormsValidator.formatDateTime
 *	Purpose: Return formatted Date time
 *	Inputs:  Element
 *	Returns: none
 =====================================*/
FormsValidator.prototype.formatDateTime=function(element){
	
	// Array of months
	var myMonths = new Array ('January','February','March','April','May','June','July','August','September','October','November','December');
	var myDays= new Array ("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday");
		
	// Determine order of datetime tokens
	var index=new Array;
	index["YYYY"]	= this.partDateTime(element,"YYYY","2003");
	index["YY"]		= index["YYYY"].substring(2,4);
	index["MN"]		= this.partDateTime(element,"MM","02");
	index["DN"]		= this.partDateTime(element,"DD","05");
	index["H12"]	= this.partDateTime(element,"HH","1");
	index["H24"]	= index["H12"];
	index["NN"]		= this.partDateTime(element,"NN","0");
	index["SS"]		= this.partDateTime(element,"SS","0");
	index["AP"]		= this.partDateTime(element,"AP","pm");
	
	// Check Am Pm
	if (index["AP"] == "pm")
		index["H24"] = Number(index["H24"]) + 12;
	
	// Create new Date object
	var oDate = new Date(index["YYYY"] + "/" + index["MN"] + "/" + index["DN"] + " " + index["H24"] + ":" + index["NN"] + ":" + index["SS"]);
	
	// Set finals values
	var iDay = oDate.getDay();
	var iMonth = oDate.getMonth();
	var iYear = oDate.getFullYear();
	index["DDD"]= myDays[iDay];
	index["MMM"]= myMonths[iMonth];	
	index["DD"]	= myDays[iDay].substring(0,3);
	index["MM"]	= myMonths[iMonth].substring(0,3);
	
	// Replace values
	var sPattern = this.getProperty(element,"format");
	sPattern=sPattern.replace(/YYYY/g ,index["YYYY"]);
	sPattern=sPattern.replace(/YY/g ,index["YY"]);
	sPattern=sPattern.replace(/MMM/g ,index["MMM"]);
	sPattern=sPattern.replace(/MM/g ,index["MM"]);		
	sPattern=sPattern.replace(/MN/g ,index["MN"]);	
	sPattern=sPattern.replace(/DDD/g ,index["DDD"]);
	sPattern=sPattern.replace(/DD/g ,index["DD"]);
	sPattern=sPattern.replace(/DN/g ,index["DN"]);
	sPattern=sPattern.replace(/H24/g ,index["H24"]);
	sPattern=sPattern.replace(/H12/g ,index["H12"]);
	sPattern=sPattern.replace(/NN/g ,index["NN"]);
	sPattern=sPattern.replace(/SS/g ,index["SS"]);
	sPattern=sPattern.replace(/AP/g ,index["AP"]);
	
	// Affect value
	element.value = sPattern;
}	

/*======================================
 *	Method:  FormsValidator.partDateTime
 *	Purpose: Return Part Date time
 *	Inputs:  Element,Part,Default
 *	Returns: Date Part
 =====================================*/
FormsValidator.prototype.partDateTime=function(element,part,sDefault){
	var mask = new String(this.getProperty(element,"mask"));
	var start = mask.indexOf(part);
	if (start !=-1) {
		var end = start + part.length;
		var sPart = element.value.substring(start, end)
	} else {
		sPart = sDefault;
	}	
	return sPart;	
}	

/*======================================
 *	Method:  FormsValidator.cancelFormat
 *	Purpose: Return unformatted value
 *	Inputs:  Element
 *	Returns: none
 =====================================*/
FormsValidator.prototype.cancelFormat=function(element){
	if(this.propertyOn(this.getProperty(element,"submitFormat"))&&element.value!="")
		element.value = this.getProperty(element,"realValue");
}	

/*======================================
 *	Method:  FormsValidator.decimalNumber
 *	Purpose: Return number decimal of the number
 *	Inputs:  number
 *	Returns: integer
 =====================================*/
FormsValidator.prototype.decimalNumber=function(sNumber){
	var decimalNumber = 0
	var indexDec = sNumber.indexOf(".");
	if (indexDec != -1) {
		decimalNumber = sNumber.length - (indexDec + 1);
	}
	return decimalNumber;
}

/*======================================
 *	Method:  FormsValidator.complete
 *	Purpose: Complete a string with N characters
 *	Inputs:  sValue,sChar,Times
 *	Returns: String
 =====================================*/
FormsValidator.prototype.complete=function(sValue,sChar,Times){
	for(i=0; i<Times; i++){
		sValue = sValue + sChar;
	}
	return sValue;
}

/*======================================
 *	Method:  FormsValidator.setRequired
 *	Purpose: Create markRequired method
 *	Inputs:  oForm
 *	Returns: undefined
 =====================================*/
FormsValidator.prototype.setRequired=function(oForm){
	oForm.markRequired = function(){
		var element;
		for(var k=0;(element=this.elements[k]);k++){
			if(FormsValidator.propertyOn(FormsValidator.getProperty(element,"required"))) 
				element.className = "required";
			FormsValidator.setProperty(element,"old-class-name",element.className);	
		}
	}
}

/*======================================
 *  Method: FormsValidator.paintElement
 *  Purpose:  Give visual cue to user that field has failed FormsValidator
 *	Inputs:   element - form field
 *	Returns:  undefined
 =====================================*/
FormsValidator.prototype.paintElement=function(element){
	
	// Paint element by changing class 
	element.className = "invalid";
		
	// Execute onvalidatefocus processing
	this.toFunction(this.getProperty(element,"onvalidatefocus"))();
}

/*======================================
 *	Method: FormsValidator.restoreElement
 *	Purpose:  Restore element to original style
 *	Inputs:   element - form field
 *	Returns:  undefined
 =====================================*/
FormsValidator.prototype.restoreElement=function(element){
	element.__=null;
	
	// Revert to previous background color
	var oldClassName = this.getProperty(element,"old-class-name");
	element.className=oldClassName;

	// Display Error message
	span = FormsValidator.getProperty(element,"span");
	if (span)
		document.getElementById(span).innerHTML="";
}

/*======================================
 *	Method: FormsValidator.restoreForm
 *	Purpose:  Restore all elements in FORM to original style
 *	Inputs:   form   - HTML form object
 *	          bReset - boolean flag: call the onreset handler for the form's elements
 *	Returns:  undefined
 =====================================*/
FormsValidator.prototype.restoreForm=function(form, bReset){
	this.clearErrors(form);	
	for(var i=0,elements=form.elements,iElements=elements.length;i<iElements;i++){
		this.restoreElement(elements[i]);
		if(bReset)elements[i].onreset();
	}
}

/*======================================
 *	Method:  FormsValidator.setup
 *	Purpose: Set up methods and event handlers for all forms and elements
 *	Inputs:  none
 *	Returns: undefined
 =====================================*/
FormsValidator.prototype.setUp=function(){
	
	// Fan through forms on page to perform initializations
	for(var i=0,oForm,iForms=document.forms.length; i<iForms; i++){
		oForm=document.forms[i];
		if(!oForm._){
			
			// Capture current event handlers
			oForm._onsubmit_		= this.toFunction(this.getProperty(oForm,"onsubmit"));
			oForm._onreset_			= this.toFunction(this.getProperty(oForm,"onreset"));
			
			// Create methods on form
			oForm.validate			= function(){return FormsValidator.isValidForm(this);}
			oForm.onbeforevalidate	= this.toFunction(this.getProperty(oForm,"onbeforevalidate"));
			oForm.onaftervalidate	= this.toFunction(this.getProperty(oForm,"onaftervalidate"));
			
			// Replace onsubmit event handler
			oForm.onsubmit			= function(oEvent){ //NN passed event
				if(!this.validate(false))  
					return false;
				
				// Perform original onsubmit event handler
				if (this._onsubmit_ && this._onsubmit_(oEvent)==false)
					return false;
				return true;
			}
			
			// Replace onreset event handler
			oForm.onreset=function(oEvent){
				FormsValidator.restoreForm(this, true);
				
				// Perform original onreset event handler
				if (this._onreset_ && this._onreset_(oEvent)==false)
					return false;
			}
			
			// Create markRequired method
			this.setRequired(oForm);
			oForm._=true;
		}
		
		// Set up all form input elements
		for(var j=0,element,iElements=oForm.elements.length;j<iElements;j++){
			element=oForm.elements[j];
			if(!element._) 
				this.setElement(element);
		}
		oForm.markRequired();
	}
}

/*======================================
 *	Method: FormsValidator.isAbsent
 *	Purpose:  Check element value
 *	Inputs:   value    - value to give property
 *	Returns:  Boolean
 =====================================*/
FormsValidator.prototype.isAbsent = function(sValue) {
	if (!sValue || sValue == '' || sValue == null || sValue == undefined || sValue == "undefined") {
		return true;
	} else {
		return false;
	}	
}	

/*======================================
 *	Method: FormsValidator.Err
 *	Purpose:  Create an Error Object
 *	Inputs:   None
 *	Returns:  None
 =====================================*/
FormsValidator.prototype.Err = new Array();

/*======================================
 *	Method: FormsValidator.clearErrors
 *	Purpose:  Clear values from Error object
 *	Inputs:   oForm : Form Object
 *	Returns:  None
 =====================================*/
FormsValidator.prototype.clearErrors = function (oForm){
	this.Err = new Array();
	if (oForm.displayMode)
		document.getElementById(this.getProperty(oForm,"span")).innerHTML = "";	
}

/*======================================
 *	Method: FormsValidator.addError
 *	Purpose:  Adds error to Error object
 *	Inputs:   
 *			element	: form element 
 *			message	: error message		
 *	Returns:  None
 =====================================*/
FormsValidator.prototype.addError=function (element,message,attribut) {
	var oErr = new Object();
	oErr.source = element;
	message = this.choose(this.getProperty(element,"errorMessage"),message);
	message = this.choose(this.getProperty(element,"errorMessage" + attribut),message);
	oErr.message = message;
	var isNew = true;
	for(i=0;i<this.Err.length;i++){	
		if (element.name == this.Err[i].source.name){
			this.Err[i] = oErr;
			isNew = false;
			break;
		}
	}
	if (isNew) 
		this.Err[this.Err.length++] = oErr;
}

/*======================================
 *	Method: FormsValidator.deleteError
 *	Purpose:  Delete error to Error object
 *	Inputs:   
 *			element	: form element 
  *	Returns:  None
 =====================================*/
FormsValidator.prototype.deleteError=function(element) {
	var ErrTemp = new Array();
	for(i=0;i<this.Err.length;i++){	
		oErr = this.Err[i];
		if (element.name == oErr.source.name){
			var span = this.getProperty(oErr.source,"span");
			if (span) {
				document.getElementById(span).innerHTML = "";
			}
		} else {	
			ErrTemp[ErrTemp.length++] = this.Err[i];				 
		}		
	}
	this.Err = ErrTemp;
}


/*======================================
 *	Method: FormsValidator.displayErrors
 *	Purpose:  Display errors message
 *	Inputs:  oForm    Form Object 
 *	Returns:  None
 =====================================*/
FormsValidator.prototype.displayErrors=function (oForm) {
	var sErrBox ="";
	var oErr;
	for(i=0;i<this.Err.length;i++){	
		oErr = this.Err[i];
		this.paintElement(oErr.source);
		if (this.getProperty(oForm,"span")) {
			sErrBox += "\n     <li> " + oErr.source.title + " : " + oErr.message + "</li>";
		} else {		
			var span = this.getProperty(oErr.source,"span");
			if (span) {
				document.getElementById(span).className = "message";	
				document.getElementById(span).innerHTML = "<br>" + oErr.message;
			} else {
				sErrBox += "\n     * " + oErr.source.title + " : " + oErr.message;
			}
		}	
	}
	if (this.Err.length > 0) sErrBox = "Errors come from those fields :" + sErrBox  
	
	if (sErrBox != "" && !this.getProperty(oForm,"span")) {
		if (this.Err.length > 0) alert(sErrBox);
	} else {
		var span = this.getProperty(oForm,"span");
		document.getElementById(span).className = "message";	
		document.getElementById(span).innerHTML = sErrBox;	
	}
}

// Limit use of script to valid environments
if(!!window.RegExp && !!"".replace && "ab".replace(/a/,"")=="b" && !!document.forms) {
	FormsValidator=new FormsValidator;
	FormsValidator.setUp();
}