// JavaScript Document
function Formulaire(formulaire){
// constructeur de la classe (en entrée : l'attribut "name" du formulaire à valider)
// Etabli les règles et fonctions à appliquer à la classe
   // variables membres
   this.form=formulaire; // nom du formulaire
   this.erreurs=new Array(); // tableau des champs contenant des erreurs de saisie

   // tableaux des règles de validation appliquées aux champs
   this.regles=new Array();
   this.messages=new Array();
   this.validations=new Array();
   this.params=new Array();

   // méthodes
   this.regle=regleChamp;
   this.nettoyer=nettoyerChaine;
   this.valider=validerForm;
   this.liste=listeErreurs;
}

function regleChamp(champ, type, message, param){
/* ajoute une règle de validation :
- "champ" est la valeur de l'attribut "name" du champ
- "type" est la règle de validation proprement dite
- "message" est le message d'erreur en cas de validation erronée
- "param" est un paramètre facultatif, utilisé par ceratines règles */
	this.regles.push(champ);
	this.validations.push(type);
	this.messages.push(message);
	this.params.push(param);
}

function listeErreurs(){
// retourne la liste des erreurs
	var x, liste="";
	// construction de la chaîne
	for(x=0; x<this.erreurs.length; x++) liste+="- "+this.erreurs[x]+"\n";
    return liste;
}

function nettoyerChaine(chaine){
// supprime les espaces en début et fin de chaîne (équivalent à la fonction PHP "trim()")
	regex=new RegExp("(^ +)|( +$)", "g");
	chaine=chaine.replace(regex, "");
	return chaine;
}
//=================================================== ValidateDATE
// valide une date au format DD/MM/YYYY ou DD-MM-YYYY
// la coherence de la date est verifie (nbre de jour selon mois et annee bissextile)
function validateDATE(fieldVal){
// Begin
// Checks for the following valid date formats:
// DD/MM/YYYY  DD-MM-YYYY
// Also separates date into month, day, and year variables
	var datePat = /^([0-9]{1,2})(\/|-)([0-9]{1,2})\2([0-9]{4})$/;
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Recherche
// Chaque () delimite un gpe de test sur un nbre variable de caracteres
// les caracteres testes par le gpe suivant dependent des resultats du test
// effectué par le gpe precedent
// ^          : matche le debut
// ([0-9]{1,2}): au moins un chiffre , au plus 2
// (\/|-)     : le caractere doit etre un / ou un -
// ([0-9]{1,2}): au moins un chiffre, au plus 2
// \2         : repete le test 2 (\/|-)
// ([0-9]{4}) : 4 chiffres necessaires
// $          : Fin de l'expression -> il ne doit plus rien y avoir derriere
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
/*
^^^^ Information about this string ^^^^
Ignore first and last '/' it is code for RegExp
Anything between () will be matched and remembered for later use
      
^ matches first input
$ matches last input
\ means that the next char after the '\' has a special meaning
\2 means same thing as second operation in this case its : (\/|-)
d means digit, it matches a number from 0 to 9
{n,m] = matches at least N and at most M occurences. N & M are assumed to be positive
*/

	var matchArray = fieldVal.match(datePat); // is the format ok?
    if (matchArray == null){
        errMsg ='Format date invalide.\nUtilisez le format JJ/MM/AAAA.'
        isError=true
        return false;
    }
    month = matchArray[3]; // parse date into variables
    day = matchArray[1];
    year = matchArray[4];
    if(day==0 && month==0 && year==0){
      // on accepte les dates nulles (indefinies ds mySQL)
      return true;
    }
	else{
      if (month < 1 || month > 12){  // check month range
        errMsg ='Le numero du mois doit etre compris entre 1 et 12.'
        isError=true
        return false;
      }
      if (day < 1 || day > 31) {
        errMsg ='Un jour doit etre compris entre 1 et 31.'
        isError=true
        return false;
      }
      if ((month==4 || month==6 || month==9 || month==11) && day==31) {
        errMsg ="Ce mois "+month+" n'a pas 31 jours!"
        isError=true
        return false
      }
      if (month == 2){  // check for february 29th
        var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
        if (day>29 || (day==29 && !isleap)) {
          errMsg = "Le mois de Fevrier " + year + " n'a pas " + day + " jours!";
          isError=true
          return false;
        }
      }
      return true;  // date is valid
    }
}

//============================================ Fonction principale ============================================
function validerForm(){
// valide le formulaire : chaque champ doit vérifier les règles qui lui ont été définies
	var x, regex, msg="";
    eval("var formulaire=document."+this.form+";");
       
    // si aucune règle n'a été définie, la validation est toujours vraie
    if(!this.regles.length) return true;
       
    // on examine chaque champ
    for(x=0; x<this.regles.length; x++){
       // on effectue au préalable un petit nettoyage sur le champ à valider
       eval("formulaire."+this.regles[x]+".value=this.nettoyer(formulaire."+this.regles[x]+".value);");
       switch(this.validations[x]){
          // le champ doit avoir le même contenu qu'un autre
          case "comparaison":
              eval("if(formulaire."+this.regles[x]+".value!='"+this.params[x]+"') this.erreurs.push(this.messages[x]);");
              break;
                
/* le champ doit avoir une certaine longueur : c'est le dernier paramètre sous la forme "min,max" (0 signifiant pas de minimum ou de maximum) */
          case "longueur":
              eval("var longueur=formulaire."+this.regles[x]+".value.length;");
              if(longueur){
                var temp=this.params[x].split(",( +)?");
                mini=parseInt(temp[0]);
                maxi=parseInt(temp[1]);
                   
                if((mini && longueur<mini) || (maxi && longueur>maxi)) this.erreurs.push(this.messages[x]);
              }
              break;

// le champ (uniquement s'il est rempli) doit vérifier une expression régulière
// on devrait faire une regle speciale pour les dates pour shunter avant !!!! 
          case "regex":
            valtype=this.params[x];
            if(valtype=="date"){
            // les dates demandant une validation plus poussée
            // on n'utilise pas une expression reguliere mais une fct
            // recupere la valeur du controle:
            	valdate=eval('document.'+this.form+'.'+this.regles[x]+'.value');
				//alert("valeur: "+valdate);//Ok
				if(!validateDATE(valdate)){this.erreurs.push(this.messages[x]);}
			}
			else{
            //xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
            // Pas une date
            //xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                switch(valtype){//(this.params[x])
                // quelques exemples...
                   case "mail":
                      regex=/^[a-z0-9\._-]+@[a-z0-9\._-]+(\.[a-z0-9]{2,4})$/i; // i signifie insensible à la casse
                      // Expression d'origine : regex=new RegExp("^[a-z0-9_]([.-]?[a-z0-9_]+)+@[a-z0-9_]([.-]?[a-z0-9_]+)+\.([a-z]{2,4}|[a-z]{6})$", "gi");
                      break;
                      
                   case "web":
                      regex=/^((http:\/\/)|(https:\/\/))[_a-z0-9-\.]+(\.([a-z0-9]{2,4}))$/i;
                      break;
                      
                   case "alpha_num":
                      regex=/^[_a-z0-9]+$/i;
                      break;
                      
                   case "code_postal":
                      regex=/^(0[1-9]|[1-9][0-9])[0-9]{3}$/;
                      break;
                     
                   // par défaut (non vide)
                   default:
                      regex=/^.+$/;
              }
              // on evalue l'expression reguliere créée en fct du type de validation necessaire
              eval('if(formulaire.'+this.regles[x]+'.value=="" || !regex.exec(formulaire.'+this.regles[x]+'.value)) this.erreurs.push(this.messages[x]);');
              // Original : eval('if(formulaire.'+this.regles[x]+'.value!="" && !regex.exec(formulaire.'+this.regles[x]+'.value)) this.erreurs.push(this.messages[x]);');
            }  // pas une date
            break;
              
          case "requis":// pas de regle de validation -> on passe au default
              
          default:
          // le champ doit juste être rempli
               eval('if(formulaire.'+this.regles[x]+'.value=="") this.erreurs.push(this.messages[x]);');
       }// switch this.validation[x] 
    }// pour chaque regles
       
    // en cas d'erreur, on affiche les différents messages
    if(this.erreurs.length){
       var msg="Le formulaire comporte des erreurs :\n\n"+this.liste()+"\nVeuillez remplir correctement les champs.";
       alert(msg);
       return false;
    }
       
    // en cas de succès, on envoie le formulaire
    return true;
}
