function FormValidator(sValidImgSrc, sInvalidImgSrc, sHelpImgSrc) {
	this.maxNbOfErrorsWhenAlert=10;

	this.validImgSrc=sValidImgSrc;
	this.invalidImgSrc=sInvalidImgSrc;
	this.helpImgSrc=sHelpImgSrc;
	this.errorsFound=new Array();

	this.fieldsToCheck=new Object();
	this.addFieldCheck=formValidator_addField;

	this.numErrors=formValidator_numErrors;
	this.displayErrors=formValidator_displayErrors;
	this.clearErrors=formValidator_clearErrors;

	////////////////////////////////////////////////////////////////////////////////
	// CHECK FUNCTIONS

	// Check ONE field
	this.checkField=formValidator_checkField;
	// Check ALL fields
	this.checkFields=formValidator_checkFields;

	// NOT Empty string
	this.isNotEmpty=formValidator_isNotEmpty;
	// Checked
	this.isChecked=formValidator_isChecked;



	this.isAlphaNumeric=formValidator_isAlphaNumeric;
	// Selected index > 0
	this.isSelected=formValidator_isSelected;


	// E-mail
	this.isEmail=formValidator_isEmail;
	// Hexadecimal
	
	////////////////////////////////////////////////////////////////////////////////
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Add a field to the FormValidator

function formValidator_addField(sFieldLabel, sInputField, sFieldCheck, bFieldMandatory, sCheckLabel, bUseImage) {
	if (sInputField && document.getElementsByName) {
		var oInputField=document.getElementsByName(sInputField);

		if (oInputField && oInputField.length>0) {
			switch (oInputField[0].type.toLowerCase()) {
				case 'select-one':
				if (oInputField[0].type.toLowerCase()=='select-one') { sFieldCheck='isSelected'; }
					else { sFieldCheck='atLeastXOptionsSelected'; }

				case 'text':
					if (document.getElementById(sInputField + 'Img')) { var oResultImg=document.getElementById(sInputField + 'Img'); }
					else if (bUseImage && oInputField[0].insertAdjacentHTML) {
						oInputField[0].style.width=parseInt(oInputField[0].style.width)-20;
						oInputField[0].insertAdjacentHTML('afterEnd', '&nbsp;<img id="' + sInputField + 'Img" src="checkHelp.gif" width="16" height="16" border="0" alt="' + sCheckLabel.replace(/\"/g, "'") + '">');
						var oResultImg=document.getElementById(sInputField + 'Img');
					}
					break;
				case 'select-multiple':
					if (oInputField[0].type.toLowerCase()=='select-one') { sFieldCheck='isSelected'; }
					else { sFieldCheck='atLeastXOptionsSelected'; }

				case 'text':
					if (document.getElementById(sInputField + 'Img')) { var oResultImg=document.getElementById(sInputField + 'Img'); }
					else if (bUseImage && oInputField[0].insertAdjacentHTML) {
						oInputField[0].style.width=parseInt(oInputField[0].style.width)-20;
						oInputField[0].insertAdjacentHTML('afterEnd', '&nbsp;<img id="' + sInputField + 'Img" src="checkHelp.gif" width="16" height="16" border="0" alt="' + sCheckLabel.replace(/\"/g, "'") + '">');
						var oResultImg=document.getElementById(sInputField + 'Img');
					}
					break;

				case 'radio':
				case 'checkbox':
					sFieldCheck='isChecked';
					if (document.getElementById(sInputField + 'Img')) { var oResultImg=document.getElementById(sInputField + 'Img'); }
					else if (bUseImage && oInputField[oInputField.length-1].insertAdjacentHTML) {
						oInputField[oInputField.length-1].insertAdjacentHTML('afterEnd', '&nbsp;<img id="' + sInputField + 'Img" src="checkHelp.gif" width="16" height="16" border="0" alt="' + sCheckLabel + '">');
						var oResultImg=document.getElementById(sInputField + 'Img');
					}
					break;

				default:
					break;
			}

			if (arguments.length>6) { var sErrorClassName=arguments[6]; }

			if (arguments.length>7) {
				var aFieldCheckParams=new Array();
				for (var i=7; i<arguments.length; i++) {
					aFieldCheckParams[aFieldCheckParams.length]=arguments[i];
				}
			}

			this.fieldsToCheck[sFieldLabel]={
				'label': sFieldLabel,
				'name': sInputField,
				'input': oInputField,
				'check': eval('this.' + sFieldCheck),
				'checkLabel': sCheckLabel,
				'mandatory': bFieldMandatory,
				'checkParams': aFieldCheckParams,
				'baseCN': oInputField[0].className,
				'errorCN': sErrorClassName,
				'fieldImg': oResultImg
			};
		}
	}
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Check ONE field

function formValidator_checkField(sFieldLabel) {
	var bFieldValueValid;
	var field=this.fieldsToCheck[sFieldLabel];

	if (field.mandatory || this.isNotEmpty(field.input)) {
		if (!field.check(field.input, field.label, field.checkParams)) { bFieldValueValid=false; }
		else { bFieldValueValid=true; }
	}

	return bFieldValueValid;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Check ALL fields

function formValidator_checkFields(bDisplayErrors) {
	var bFormValid=true;
	var fields=this.fieldsToCheck;

	for (var sFieldId in fields) {
		if (fields[sFieldId].mandatory || this.isNotEmpty(fields[sFieldId].input)) {
			if (fields[sFieldId].check(fields[sFieldId].input, fields[sFieldId].label, fields[sFieldId].checkParams)) { fields[sFieldId].error=false; }
			else {
				fields[sFieldId].error=true;
				bFormValid=false;
			}
		}
	}

	if (!bFormValid) { this.displayErrors(bDisplayErrors); }

	return bFormValid;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Get the number of errors

function formValidator_numErrors() {
	var fields=this.fieldsToCheck;
	var sNbErrors=0;

	for (var sFieldId in fields) {
		if (fields[sFieldId].error) { sNbErrors++; }
	}

	return sNbErrors;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Display errors (with or without alert)

function formValidator_displayErrors(bAlert) {
	var fields=this.fieldsToCheck;
	var sAlert="Il y a des erreurs.\nVeuillez Vérifier ces champs:\n\n";
	var sAlertLink='';

	var sNbErrors=this.numErrors();

	for (var sFieldId in fields) {
		if (fields[sFieldId].error) {
			if (sNbErrors>this.maxNbOfErrorsWhenAlert) { sAlert+=sAlertLink + '"' + fields[sFieldId].label + '"'; }
			else { sAlert+=sAlertLink + 'Champ: "' + fields[sFieldId].label + "\"\nErreur: \"" + fields[sFieldId].checkLabel.replace(/\"/g, "'").replace(/\n/g, ' ') + "\"\n"; }
			sAlertLink="\n";
			for (var i=0; i<fields[sFieldId].input.length; i++) {
				if (fields[sFieldId].errorCN) { fields[sFieldId].input[i].className=fields[sFieldId].errorCN; }
				if (fields[sFieldId].fieldImg) { fields[sFieldId].fieldImg.src=this.invalidImgSrc; }
			}
		}
		else {
			for (var i=0; i<fields[sFieldId].input.length; i++) {
				if (fields[sFieldId].baseCN) { fields[sFieldId].input[i].className=fields[sFieldId].baseCN; }
				else { fields[sFieldId].input[i].className=''; }
				if (fields[sFieldId].fieldImg) { fields[sFieldId].fieldImg.src=this.validImgSrc; }
			}
		}
	}

	if (bAlert) { alert(sAlert); }
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Clear errors

function formValidator_clearErrors() {
	var fields=this.fieldsToCheck;

	for (var sFieldId in fields) {
		if (!fields[sFieldId].check(fields[sFieldId].input, fields[sFieldId].label, fields[sFieldId].checkParams)) {
			fields[sFieldId].error=false;
			for (var i=0; i<fields[sFieldId].input.length; i++) {
				if (fields[sFieldId].baseCN) { fields[sFieldId].input[i].className=fields[sFieldId].baseCN; }
				else { fields[sFieldId].input[i].className=''; }
				if (fields[sFieldId].fieldImg) { fields[sFieldId].fieldImg.src=this.helpImgSrc; }
			}
		}
		else {
			for (var i=0; i<fields[sFieldId].input.length; i++) {
				if (fields[sFieldId].baseCN) { fields[sFieldId].input[i].className=fields[sFieldId].baseCN; }
				else { fields[sFieldId].input[i].className=''; }
				if (fields[sFieldId].fieldImg) { fields[sFieldId].fieldImg.src=this.validImgSrc; }
			}
		}
	}
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Not empty?

function formValidator_isNotEmpty(oInput) {
	var bReturnValue;

	oInput[0].value=oInput[0].value.replace(/(^ *)|( *$)/g, '');

	if (oInput[0].value.length>0) { bReturnValue=true; }
	else { bReturnValue=false; }

	return bReturnValue;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Is it an Number ('x' decimals and between min and max)?

function formValidator_isNumber(oInput, aLabel, aParams) {
	var bReturnValue;

	if (oInput[0].value=='' || isNaN(oInput[0].value)) { bReturnValue=false; }
	else {
		iValue=oInput[0].value=parseFloat(oInput[0].value);

		var iNbDecimals=0;
		var iValueMin='';
		var iValueMax='';

		if (aParams.length>0) { iNbDecimals=Math.abs(aParams[0]); }
		if (aParams.length>1) { iValueMin=parseFloat(aParams[1]); }
		if (aParams.length>2) { iValueMax=parseFloat(aParams[2]); }

		if (!isNaN(iValueMin)) {
			if (!isNaN(iValueMax)) {
				if (iValueMin>iValueMax) { iValueMin+=iValueMax; iValueMax=iValueMin-iValueMax; iValueMin-=iValueMax; }
			}
			else {
				iValueMax=iValueMin;
				iValueMin='';
			}
		}

		if (formValidator_checkRegExp(oInput[0].value, new RegExp('^\-?[0-9]+(\.[0-9]{0,' + iNbDecimals + '})?$', 'gi'), [])) {

/*
4 Possibilities:
		iValueMin isNaN & iValueMax isNaN
				value must be valid float
		iValueMin isNaN & iValueMax isNumber
				value must be a float < iMaxValue
		iValueMin isNumber & iValueMax>iValueMin
				value must be a float between iValueMin and iValueMax
		iValueMin isNumber & iValueMax=iValueMin
				value must be equal to iValueMin (or iValueMax)
*/

			if (isNaN(iValueMin) && isNaN(iValueMax)) { bReturnValue=true; }
			else if (isNaN(iValueMin) && !isNaN(iValueMax) && iValue<=iValueMax) { bReturnValue=true; }
			else if (!isNaN(iValueMin) && iValueMax>iValueMin && iValue>=iValueMin && iValue<=iValueMax) { bReturnValue=true; }
			else if (!isNaN(iValueMin) && iValueMax==iValueMin && iValue==iValueMin) { bReturnValue=true; }
			else { bReturnValue=false; }
		}
		else { bReturnValue=false; }
	}

	return bReturnValue;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Is it a Numeric (between min and max chars)?


////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Is it an Alphabetic value (between min and max chars)?



//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Is it an Alphanumeric value (between min and max chars)?

function formValidator_isAlphaNumeric(oInput, aLabel, aParams) {
	var bReturnValue;

	bReturnValue=formValidator_checkRegExp(oInput[0].value, /^[a-z0-9]*$/gi, aParams);

	return bReturnValue;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Generic function for a regular expression match

function formValidator_checkRegExp(sValue, oRegularExpression, aParams) {
	var bReturnValue;

	var iMinChars=0;
	var iMaxChars=0;

	if (aParams.length>0) { iMinChars=Math.abs(parseInt(aParams[0])); }
	if (aParams.length>1) { iMaxChars=Math.abs(parseInt(aParams[1])); }

	if (iMinChars>iMaxChars) { iMinChars+=iMaxChars; iMaxChars=iMinChars-iMaxChars; iMinChars-=iMaxChars; }

/*
4 Possibilities:
		iMinChars<=0 & iMaxChars<=0
				value must be Alpha
		iMinChars<=0 & iMaxChars>iMinChars
				value must contain less than (including) iMaxChars Alpha chars
		iMinChars>0 & iMaxChars>iMinChars
				value must contain between (including) iMinChars and iMaxChars Alpha chars
		iMinChars>0 & iMaxChars=iMinChars
				value must contain iMinChars (or iMaxChars) Alpha chars
*/

	if (iMinChars<=0 && iMaxChars<=0 && oRegularExpression.test(sValue)) { bReturnValue=true; }
	else if (iMinChars<=0 && iMaxChars>iMinChars && sValue.length<=iMaxChars && oRegularExpression.test(sValue)) { bReturnValue=true; }
	else if (iMinChars>0 && iMaxChars>iMinChars && sValue.length>=iMinChars && sValue.length<=iMaxChars && oRegularExpression.test(sValue)) { bReturnValue=true; }
	else if (iMinChars>0 && iMaxChars==iMinChars && sValue.length==iMinChars && oRegularExpression.test(sValue)) { bReturnValue=true; }
	else { bReturnValue=false; }

	return bReturnValue;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Is it checked?

function formValidator_isChecked(oInput, aLabel) {
	var bReturnValue;

	var iCpt=0;
	bReturnValue=false;
	while (iCpt<oInput.length && !bReturnValue) {
		if (oInput[iCpt].checked) { bReturnValue=true; }

		iCpt++;
	}

	return bReturnValue;
}

//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Is it a valid PostCode?




function formValidator_isSelected(oInput, aLabel, aParams) {
	var bReturnValue;

	if (oInput[0].selectedIndex==0) { bReturnValue=false; }
	else { bReturnValue=true; }

	return bReturnValue;
}




function formValidator_isEmail(oInput, aLabel) {
	var bReturnValue;

	bReturnValue=formValidator_checkRegExp(oInput[0].value, /^[a-z0-9_\-]+(\.[a-z0-9_\-]+)*@[a-z0-9\-]*[a-z0-9](\.[a-z0-9\-]*[a-z0-9])*\.[a-z]{2,3}$/gi, []);

	return bReturnValue;
}

