////////////////////////////////////////////////////////////////////////////////
//
//	JavaScript File
//
//	Package:
//		Form Validator
//
//	Purpose:
//		Constructor and validation functions
//
//	Version 1.0
//
//	Author:
//		Grégory Despagne
//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Constructor

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.checkRegExp=formValidator_checkRegExp;

	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;
	// PostCode
	this.isPC=formValidator_isPC;
	// Date
	this.isDate=formValidator_isDate;
	// Timestamp
	this.isTimestamp=formValidator_isDate;
	// One of the values of the provided array
	this.isEnum=formValidator_isEnum;
	// Number
	this.isNumber=formValidator_isNumber;
	// Numeric (Only 0-9)
	this.isNumeric=formValidator_isNumeric;
	// Alphabetic (Only a-z)
	this.isAlpha=formValidator_isAlpha;
	// Alphanumeric (Only a-z & 0-9)
	this.isAlphaNumeric=formValidator_isAlphaNumeric;
	// Selected index > 0
	this.isSelected=formValidator_isSelected;
	// At least 'x' options selected in a combo box
	this.atLeastXOptionsSelected=formValidator_AtLeastXOptionsSelected;
	// E-mail
	this.isEmail=formValidator_isEmail;
	// Hexadecimal
	this.isHexa=formValidator_isHexa;
	// Telephone - NICO
	this.isTel=formValidator_isTel;

	//
	////////////////////////////////////////////////////////////////////////////////
}

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

////////////////////////////////////////////////////////////////////////////////
// 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':
				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 dans la saisie du formulaire.\nMerci de 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 + "\"\nConseil : \"" + 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)?

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

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

	return bReturnValue;
}

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

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

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

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

	return bReturnValue;
}

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

////////////////////////////////////////////////////////////////////////////////
// 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_isPC(oInput, aLabel) {
	var bReturnValue;
	expressionReguliere=/(\d{4,5})|(b\d{4})|(l\d{2,5})/gi;

	bReturnValue=formValidator_checkRegExp(oInput[0].value, /^(\d{4,5})|(b\d{4})|(l\d{2,5})$/gi, []);

	return bReturnValue;
}

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

////////////////////////////////////////////////////////////////////////////////
// Is it a valid Date (params are nb of chars [6, 8, 12 or 14], if the year is before [true] or after [false], the minimal date and the maximal date [8 or 14 chars with year before])?

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

	var iNbChars=8;
	var bYearBefore=true;
	var dFirstDate=false;
	var dLastDate=false;

	if (aParams.length>0) { iNbChars=Math.abs(parseInt(aParams[0])); }
	if (aParams.length>1) { bYearBefore=aParams[1]; }
	if (aParams.length>2) { dFirstDate=new Date(aParams[2].substr(0, 4), parseInt(aParams[2].substr(4, 2))-1, aParams[2].substr(6, 2), aParams[2].substr(8, 2), aParams[2].substr(10, 2), aParams[2].substr(12, 2)); }
	if (aParams.length>3) { dLastDate=new Date(aParams[3].substr(0, 4), parseInt(aParams[3].substr(4, 2))-1, aParams[3].substr(6, 2), aParams[3].substr(8, 2), aParams[3].substr(10, 2), aParams[3].substr(12, 2)); }

	if (dFirstDate && dLastDate && dFirstDate>dLastDate) { var tempDate=dFirstDate; dFirstDate=dLastDate; dLastDate=tempDate; }

	if (formValidator_checkRegExp(oInput[0].value, new RegExp('^[0-9]{' + iNbChars + '}$', 'gi'), [])) {
		var iOffset=0;
		if (iNbChars==8 || iNbChars==14) { iOffset=2; }

		var dValue=new Date(oInput[0].value.substr(0, 4-(2-iOffset)), parseInt(oInput[0].value.substr(iOffset+2, 2))-1, oInput[0].value.substr(iOffset+4, 2), oInput[0].value.substr(iOffset+6, 2), oInput[0].value.substr(iOffset+8, 2), oInput[0].value.substr(iOffset+10, 2));

		if (!dFirstDate && !dLastDate) { bReturnValue=true; }
		else if (dFirstDate && !dLastDate && dValue>=dFirstDate) { bReturnValue=true; }
		else if (dFirstDate && dLastDate && dValue>=dFirstDate && dValue<=dLastDate) { bReturnValue=true; }
		else { bReturnValue=false; }
	}
	else { bReturnValue=false; }

	return bReturnValue;
}

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

////////////////////////////////////////////////////////////////////////////////
// Is the first option selected (should be empty)?

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

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

	return bReturnValue;
}

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

////////////////////////////////////////////////////////////////////////////////
// Is it in the provided values array?

function formValidator_isEnum(oInput, aLabel, aParams) {
	var bReturnValue;
	var bCaseSensitive=true;
	var aAuthValues=new Array();

	if (aParams.length>0 && typeof(aParams[0])=='boolean') { var bCaseSensitive=aParams[0]; }

	if (aParams.length>1 && typeof(aParams[1])=='object' && aParams[1].length>0) { aAuthValues=aParams[1]; }

	var sValue=oInput[0].value;

	var bValueFound=false;

	var i=0;
	while (i<aAuthValues.length && !bValueFound) {
		if (bCaseSensitive && sValue==aAuthValues[i]) { bValueFound=true; }
		else if (!bCaseSensitive && sValue.toLowerCase()==aAuthValues[i].toLowerCase()) { bValueFound=true; }
		i++;
	}

	bReturnValue=bValueFound;

	return bReturnValue;
}

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

////////////////////////////////////////////////////////////////////////////////
// Are there at least 'x' options selected?

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

	var minSelection=1;
	var maxSelection=1;

	if (aParams.length>0 && !isNaN(parseInt(aParams[0]))) { minSelection=parseInt(aParams[0]); }

	if (aParams.length>1 && !isNaN(parseInt(aParams[1]))) { maxSelection=parseInt(aParams[1]); }

	if (minSelection>maxSelection) { minSelection+=maxSelection; maxSelection=minSelection-maxSelection; minSelection-=maxSelection; }

	var nbSelectedOptions=0;
	for (var i=0; i<oInput[0].options.length; i++) {
		if (oInput[0].options[i].selected) { nbSelectedOptions++; }
	}

	if (nbSelectedOptions>=minSelection && nbSelectedOptions<=maxSelection) { bReturnValue=true; }
	else { bReturnValue=false; }

	return bReturnValue;
}

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

////////////////////////////////////////////////////////////////////////////////
// Is it a correct e-mail address?

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;
}

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

////////////////////////////////////////////////////////////////////////////////
// Is it a correct hexadecimal value?

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

	var minLength=1;
	var maxLength=1;
	var numberSignBefore=true;

	if (aParams.length>0 && !isNaN(parseInt(aParams[0]))) { var minLength=parseInt(aParams[0]); }

	if (aParams.length>1 && !isNaN(parseInt(aParams[1]))) { var maxLength=parseInt(aParams[1]); }

	if (aParams.length>2 && typeof(aParams[2])=='boolean') { var numberSignBefore=aParams[2]; }

	if (numberSignBefore) {
		var regularExpression=/^#[a-f0-9]+$/gi;
		var minLength=minLength+1;
		var maxLength=maxLength+1;
	}
	else { var regularExpression=/^[a-f0-9]+$/gi; }

	bReturnValue=formValidator_checkRegExp(oInput[0].value, regularExpression, [minLength, maxLength]);

	return bReturnValue;
}

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


////////////////////////////////////////////////////////////////////////////////
// Est-ce un numero de telephone valide ? - NICO

function formValidator_isTel(oInput, aLabel) {
	var bReturnValue;

	bReturnValue=formValidator_checkRegExp(oInput[0].value, /^0[1-68]([-. ]?[0-9]{2}){4}$/, []);

	return bReturnValue;
}

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

