/******
 ** Harmen CHRISTOPHE 2005/06/22 V0.0b
 * Une librairie permettant de valider les formulaires.
 * Usage :
 * 	- pour les formulaires à contrôler, ajouter à l'élément "form" la class "formToControl"
 * 	- pour chacun des champs, l'implémentation doit :
 * 		- associer un élément label de manière explicite (for="id_champ") au champ correspondant (association implicite non prise en charge);
 * 		- pour chacun des champs à contrôler, ajouter une classe à l'élément label (ex : "isControle").
 * 		Ces noms de classes doivent représenter le type de contrôle a réaliser (par exemple "isNotNull", "isDate", "isInt", etc...);
 * - créer des fonctions portant le même non que les classes implémentées (ex : function isControle()).
 *  Ces dernières doivent :
 *  	- recevoir en paramètre une chaîne qui correspondra à la valeur du champ dont le label implémente la classe de même nom (ex: function isControle(s) {...});
 *  	- réaliser le contrôle sur la chaîne reçue;
 *  	- ne pas implémenter d'alert des messages en cas d'erreurs.
 *  	- retourner "true" en cas de succès et "false" si la chaîne n'est pas valide.
 * 	- dans la méthode "formControlListener" :
 * 		- la table "arrSchemes2Eval" doit contenir le nom des classes de contrôle dans l'ordre d'appel.
 * 		par exemple, pour arrSchemes2Eval  = ["isNotNull","isDate","isEmail","extendedControl"]
 * 		le script va exécuter dans l'ordre les  fonctions "isNotNull","isDate" et "isEmail" ("extendedControl" étant réservé à un usage particulier décrit par la suite)
 * 		- dans la section "Test du schéma de contrôle" (...switch (scheme)...) ajouter pour chacune des fonctions, les messages en cas d'erreur (case "isControle": errorMsg = "Le champ \"" + clearedTextLabel + "\" doit...";break;).
 * 		 =>la variable "clearedTextLabel" contenant le contenu textuel du label en cours de contrôle.
 * 	- pour avoir la possibilité de créer un contrôle plus fin et plus spécifique, il suffit d'affecter la class "extendedControl" à l'élément label
 * 	et de créer une fonction extendedControl_"id_du_champ_de_formulaire" (ex: function extendedControl_id() {...}).
 * 	Cette fonction devra retourner true ou false mais également gérer l'alert d'un message en cas d'erreur.
 ******/
/*
 * Corps de fichier :
 * Ajout des eventListeners sur les formulaires ayant la class "formToControl"
//*/
addEventLst(window,"load",addFormsControlListener); 
/**
 * Ajoute un eventListener (fct formControlListener()) sur les formulaires ayant la classe "formToControl"
**/
function addFormsControlListener() {
	var cFormsToControl, nLabel;
	cFormsToControl = getElementsByClass("formToControl");
	for (var i=0; i < cFormsToControl.length; i++) {
		if (cFormsToControl[i].nodeName.toLowerCase()=="form") {
			// On vérifie que l'ensemble des labels on des champs explicites valides
			/*for (var j=0; nLabel=cFormsToControl[i].getElementsByTagName("label")[j];j++) {
				if ((nLabel.htmlFor=="") || ((nLabel.htmlFor!="") && (document.getElementById(nLabel.htmlFor)==null)) ) {
					alert("L'étiquette  \"" + getClearedTextLabel(nLabel) + "\" n'est pas associée de manière explicite à un champ de formulaire valide.");
				}
			}*/
			addEventLst(cFormsToControl[i],"submit",formControlListener);
		}
	}
}
/**
 * EventListener permetant de valider un formulaire avant la soumission
 * En cas d'erreur le formulaire n'est pas envoyé 
 * @param : e : event : evennement envoyé directement par l'implémentation DOM 
**/
function formControlListener(e) {
	var arrSchemes2Eval, scheme, bIsValide, cLabels;
	arrSchemes2Eval = ["isNotNull","isDate","isEmail","extendedControl"];
	bIsValide = true;
	if (document.addEventListener)
		oNode = e.currentTarget;
	else if (window.event)
		oNode = window.event.srcElement;
	else
		oNode = this;
	while (oNode.nodeType==1) {
		if (oNode.nodeName.toLowerCase()=="form") break;
		oNode = oNode.parentNode;
	}
	// Contrôle sur des schémas génériques
	if (arrSchemes2Eval.length>0) {
		try {
			for (var i=0; bIsValide&&(i<arrSchemes2Eval.length);i++) {
				if((arrSchemes2Eval[i]!="extendedControl") && (typeof(eval(arrSchemes2Eval[i]))!="function")) {
					bIsValide=false;
					break;
				}
			}
	
		} catch(err) {bIsValide= false;}
		if (!bIsValide)
			alert("Au moins un élément de la liste des fonctions de contrôle ne semble pas exister (\""+arrSchemes2Eval[i]+"\").");
	}
	if (bIsValide) {
		// Contrôle sur les schémas spécifiques
		var cExtendedControl = getElementsByClass("extendedControl",oNode);
		try {
			for (var i=0; bIsValide&&(i<cExtendedControl.length); i++) {
				if ((cExtendedControl[i].nodeName.toLowerCase()=="label")
					&& (typeof(eval("extendedControl_" + cExtendedControl[i].htmlFor))!="function") ) {
					bIsValide=false;
					break;
				}
			}
		} catch(err) {bIsValide= false;}
		if (!bIsValide) {
			if (cExtendedControl[i])
				alert("Au moins un élément de la liste des fonctions de contrôle étendue ne semble pas exister (\"extendedControl_"+cExtendedControl[i].htmlFor+"\").");
		}
		cExtendedControl= null;
	}
	cLabels = oNode.getElementsByTagName("label");
	for (var i=0; bIsValide && i<cLabels.length; i++) {
		if ((cLabels[i].htmlFor=="") || !(nField=document.getElementById(cLabels[i].htmlFor))) continue;
		clearedTextLabel = getClearedTextLabel(cLabels[i]);
		for (var j=0; bIsValide && (scheme=arrSchemes2Eval[j]); j++) {
			if (hasClassName(cLabels[i],scheme)) {
				if ( (scheme!="extendedControl") && (!eval(scheme+"(nField.value)")) ) {
					switch (scheme) {
						case "isNotNull":
							errorMsg = "Le champ \"" + clearedTextLabel + "\" doit être renseigné.";
							break;
						case "isDate":
							errorMsg = "Le champ \"" + clearedTextLabel + "\" n'est pas une date valide.\nFormat : jj/mm/aaaa.";
							break;
						case "isEmail":
							errorMsg = "Le champ \"" + clearedTextLabel + "\" n'est pas un email valide.";
							break;
					}
					bIsValide = false;
					alert(errorMsg);
				} else if ( (scheme=="extendedControl") ) {
					bIsValide = eval("extendedControl_" + cLabels[i].htmlFor + "(nField);");
				}
				if (!bIsValide) {
					if (nField.focus)
						nField.focus();
					else if (nField.selected)
						nField.selected();
				}
			}
		}
	}
	// En cas d'erreur, le formulaire ne doit pas être envoyé
	if (!bIsValide) {
		if (e.preventDefault) {
			e.preventDefault();
		} else if (e.returnValue) {
			e.returnValue = false;
		} else {
			return false;
		}
	}
}
/*
 * Fonctions annexes utiles :
 * 	- getElementsByClass (lib.dom.js :: core)
 * 	- getOuterText (lib.dom.js :: Html)
 * 	- getInnerText (lib.dom.js :: Html)
 * 	- addEventLst (lib.dom.js :: event)
 * 	- hasClassName (lib.dom.js :: core)
 * 	- trim
 **/ 
	function trim(s) {
		if (!s) return s;
		return s.replace(/(^\s*)|(\s*$)/g,"");
	}
/*
 * Fonctions de contrôle...
 * ["isNotNull","isDate","isEmail"]
**/  
function isNotNull(s) {
	return trim(s)!="";
}
function isEmail(s) {
	var i, j;
	if (isNotNull(s)) {
		i = s.indexOf("@",2);
		j = s.indexOf(".", i + 3);
		if ((i == -1) || (j == -1) || (j + 3 > s.length)) {
			return false;			
		}
	}
	return true;	
}
function isDate(s) {
	var bIsDate, d, m, y;
	bIsDate = true;
	if (isNotNull(s)) {
		if ((s.length != 10) || (s.substring(2,3) != "/") || (s.substring(5,6) != "/")) bIsDate = false;
		var d = s.substring(0,2);
		var m = s.substring(3,5);
		var y = s.substring(6,10);	
		if (m==1 || m==3 || m==5 || m==7 | m==8 || m==10 || m==12) {
			if (d > 31) bIsDate = false;
		} else if (m==4 || m==6 || m==9 || m==11) {
			if (d > 30) bIsDate = false;	
		} else if (m==2) {
			if (y % 4 == 0) {
				if (d > 29) bIsDate = false;	
			} else {
				if (d > 28) bIsDate = false;	
			}
		} else {
			bIsDate = false;	
		}
	}
	return bIsDate;
}
