/*******************************
 * CHAMPS DE TYPE TEXT
 *******************************/
/** 
 * Retourne le code ASCII associé à l'évènement Event
 *
 * @param   event   Evènement
 * @return  int
 */
function getCarFromEvent(event) {
    if (is_gecko) var keyCode = event.which;
    else          var keyCode = event.keyCode; 
    
    return String.fromCharCode(keyCode);
}



/** 
 * <input type="text" onkeypress="return keyCheck(event,'point');" />
 * Vérifie que la touche appuyée (sur evenement onkeypress) est numérique ou contient un "."
 *
 * @param     event, évenement
 * @param separator, séparateur décimal accepté (point ou virgule)
 * @return
 */
function keyCheck(event, separator) {
    
    //x08 : backspace    x00 : Home, End, Del, Tab et Flèches
    var specialsKey = /[\x00\x08]/;
    
    //Nombres numériques et "."
    var validKey    = /[\d]/;
    
    if (separator == "virgule")     var separatorKey = /[,]/;
    else if (separator == "point")  var separatorKey = /[.]/;
    else                            var separatorKey = /[.]/;
    
    var car = getCarFromEvent(event);
    
    //La fonction test renvoie true si le caractère appartient à l'expression reg. ou false dans le cas contraire
    if (validKey.test(car) || specialsKey.test(car) || separatorKey.test(car)) return true;
    else return false;
}


/**
 * Fonction générique de vérification des nombres entiers ou décimaux lors de la saisie.
 * Utilisez de préférence les raccourcis formatFloat() ou numberOnly().
 * 
 * @param   event   event           Ressource évènement
 * @param   bool    intOnly         Entier uniquement
 * @param   bool    negValAllowed   Valeur négative autorisée (false par défaut)
 */
function numberKeyCheck(event, intOnly, negValAllowed) {


    // event.cancel() => échec de l'évènement. C'est ce qui permet de ne pas avoir à placer le mot clé "return" avant
    // l'appel de la fonction
    if (is_gecko) {
        var field    = event.target;
        event.cancel = new Function("this.preventDefault()");
    }
    else {
        var field    = event.srcElement;
        event.cancel = new Function("this.returnValue = false");
    }

    // Code du caractère que l'on vient de taper
    var car = new String(getCarFromEvent(event));
    
    
    
    /** 
     * Etape 1 : Tester si le caractère tapé est valide
     */
    
    // x08 : backspace
    // x00 : Home, End, Del, Tab et Flèches
    var navKeys = /[\x00\x08]/;
    
    // Les touches de navigation sont toujours autorisées. On peut arrêter le traitement ici.
    if (navKeys.test(car))
        return;
    
    // Test sur les autres touches valide
    if (intOnly) var validKeys = (negValAllowed) ? /\d|-/ : /\d/;
    else         var validKeys = (negValAllowed) ? /\d|\.|-/ : /\d|\./;
    
    
    
    if (!validKeys.test(car)) {
        event.cancel();
        return;
    }

    // N'autorise qu'un seul point dans la chaine.
    if (car == "." && field.value.search(/\./) != -1) {
        event.cancel();
        return;
    }
    
    
    /** 
     * Etape 2 : Gestion du signe négatif
     * 
     */
      
    // Si on veut saisir un "-"
    if (car == "-") {
        
        var ereg = /^-/;

        // GECKO
        if (is_gecko) {
            
            // Si le curseur n'est pas au début du champ
            if (field.selectionStart != 0) {
                // Si un "-" n'est pas déjà présent on l'ajoute en début de chaine
                if (!ereg.test(field.value)) 
                    field.value = "-" + field.value;
                // Dans tous les cas (dejà un "-" ou non), on n'insère pas la touche saisie.  
                event.cancel();
            }
            
            // Si le curseur est juste au début de la chaîne et qu'il existe déjà un "-"
            if  (field.selectionStart == 0 && field.selectionEnd == 0 && ereg.test(field.value))
                event.cancel();
        }
        // IE
        else {
            
            // Texte sélectionné
            var selectedRange = document.selection.createRange();
            // Debut du champ text contenant le même nbre de caractères que la sélection (permet de comparer ses 2 champs)
            var beginingText = field.value.substr(0, selectedRange.text.length);
            
            // Si le texte sélectionné n'est pas égal au début du champ texte OU si il n'y a aucun caractère sélectionné
            if (selectedRange.text != beginingText || selectedRange.text.length == 0) {
                
                // Si un "-" est déjà présent on n'insère pas le nouveau
                if (ereg.test(field.value))
                    event.cancel();
                // Si un "-" n'est pas déjà présent dans la chaine on l'insère en début de chaine
                else {
                    // Les 2 lignes suivantes permetent de se positionner au début du champ text
                    selectedRange.moveStart("character", 0 - field.value.length);
                    selectedRange.moveEnd("character"  , 0 - field.value.length);
                    selectedRange.text = "-";
                    event.cancel(); 
               }
            }
        }
    }
}


function checkTelFR(element, obligatoire, separateur) {
    var tel = element.value;
    
	if (tel == '')
        return !obligatoire;
    
    var expr = new RegExp("^([0-9]{2})(.?)([0-9]{2})(.?)([0-9]{2})(.?)([0-9]{2})(.?)([0-9]{2})$", "i");
    
    if (expr.test(tel) === false) {
        alert('"' + tel + '" n\'est pas un numéro de téléphone valide !\nFormat du champ attendu : 99' + separateur + '99' 
        																							   + separateur + '99' 
        																							   + separateur + '99' 
        																							   + separateur + '99');
        return false;
    }
    
    var matches = tel.match(expr);
    
    // Force le separateur avec un tiret, dernière lettre en majuscule
    tel = new String(matches[1] + separateur + matches[3] + separateur + matches[5] + separateur + matches[7] + separateur + matches[9]);
    
    element.value = tel;
    
    return true;
}

/**
 * Format d'un email : xxx@xxx.xx
 * 
 * @param object element
 * @param bool   obligatoire
 */
function checkEmail(element, obligatoire)
{
	var email = trim(element.value);
	
	if (email == '')
        return !obligatoire;
	
	var expr = /^\w+([\.'-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,})+$/;
	
	if (expr.test(email) === false)
	{
		alert('"' + email + '" n\'est pas une adresse e-mail valide !');
		return false;
	}
	return true;
}

/**
 * Format d'un code INE : 99-99-999999-X
 * 
 * @param object element
 * @param bool   obligatoire
 */
function checkINE(element, obligatoire) {

    var ine = trim(element.value);
    
	if (ine == '')
        return !obligatoire;
    
    var expr = new RegExp("^([0-9]{2})(-?)([0-9]{2})(-?)([0-9]{6})(-?)([a-zA-Z]{1})$", "i");
    
    if (expr.test(ine) === false) {
        alert('"' + ine + '" n\'est pas un numéro INE valide !\nFormat du champ attendu : 99-99-999999-X\n(10 chiffres plus une lettre)');
        return false;
    }

    var matches = ine.match(expr);

    ine = new String(matches[1] + '-' + matches[3] + '-' + matches[5] + '-' + matches[7].toUpperCase());
    element.value = ine;
    return true;

    /* Permet de faire le vrai test de l'INE mais il est en commentaire coté YPareo, donc il est en commentaire pour l'instant coté portail
    if(testINE(matches[1] + matches[3] + matches[5] + matches[7].toUpperCase()) === false){
        alert('"' + ine + '" n\'est pas un numéro INE valide');
        return false;
    }else{
        ine = new String(matches[1] + '-' + matches[3] + '-' + matches[5] + '-' + matches[7].toUpperCase());
        element.value = ine;
        return true;
    }*/
}


/*
 * Vrai test de l'INE, basé sur l'algo de wincfa
 *
 * $param ine (INE au format 0123456789A)
 */
function testINE(ine){
    var j;
    var alphabet = 'ABCDEFGHJKLMNPRSTUVWXYZ';
    var academie = ine.substr(0,2);
    var eleve = ine.substr(2,2);
    var a = ine.substr(4,1);
    var ordre = ine.substr(5,5);
    var cle = ine.substr(10,1);
    var result = true;
    var myText = academie + eleve + a + ordre;

    if (a != 'A'){
        while(myText.length > 9){
            myText = ((myText.substr(0,9))%23) + myText.substr(9,myText.length);
        }
        j = (myText.substr(0,9)%23) + 1;
        if (cle != alphabet[j]){
            result = false;
        }
    }
    return result;
}

/** 
 * Sur évènement onKeyPress : interdit la saisie autre que ##.##
 * 
 * @param   event   Touche enfoncée
 * @param   objet   field
 */
function floatMask(event, field) {
    
    if (!keyCheck(event, 'point'))
        return false;
    
    var RE  = /\d|\./;
    var car = getCarFromEvent(event);
    
    if (RE.test(car)) {
        var RE  = /^\d*(\.{1}\d*){0,1}$/;
        var str = new String(field.value + car);
    
        if (RE.test(str)) return true;
        else return false;
    }
}

/** 
 * N'autorise que l'utilisation du pavé numérique (sans séparateur décimal)
 *
 * @param   event   Evenement
 * @return  bool
 */
function numberOnly(event) {
    //x08 : backspace    x00 : Home, End, Del, Tab et Flèches
    var specialsKey = /[\x00\x08]/;
    
    //Nombres numériques
    var validKey = /[0-9]/;
    var car      = getCarFromEvent(event);
    
    if (validKey.test(car) || specialsKey.test(car)) return true;
    else return false;
}

 
/** 
 * Teste l'équivalence de deux champs
 *
 * @param val1, l'objet de formulaire contenant la première valeur à tester
 * @parma val2, l'objet de formulaire contenant la seconde valeur à tester
 * @param nom1, libellé du premier objet
 * @param nom2, libellé du second objet
 * @return
 */
function isEqual(val1, val2, nom1, nom2) {
	value1 = val1.value;
	value2 = val2.value;
	
	if (value1 != value2) {
		alert("La valeur du champ \""+ nom1 +"\" ne correspond pas à celle du champ \""+ nom2 +"\". Merci de vérifier");
		val2.focus();
		return false;
	}
	
	return true;
}



/** 
 * Teste un champ obligatoire
 *
 * @param champ, l'objet du formulaire à vérifier
 * @param nom, le libellé de l'objet
 * @return
 */
function isEmpty(champ, nom) {
	
	if (trim(champ.value) == "") {
 		alert("Merci de saisir une valeur pour le champ \""+ nom +"\"");
 		champ.focus();
 		return(false);
	}
	
	return true;
}



/** 
 * IsDecimal(test, 'test') => vérifiera un nombre décimal d'une précision 2 positif avec un point comme séparateur
 * IsDecimal(test, 'test', ',' , '4', 'false') => vérifiera un nombre décimal d'une précision 4 signé avec une virgule comme séparateur
 *
 * @param   objet   champ
 * @param   string  libelle
 * @return  boolean
 */
function isDecimal(champ, libelle) {
    // Paramétrage
    if (isDecimal.arguments.length == 2) {
        separateur = '.';
        precision  = 2;
        positif    = true;
    } else {
        separateur = isDecimal.arguments[2];
        precision  = isDecimal.arguments[3];
        positif    = isDecimal.arguments[4];;
    }
    // Vérifie la numérotation avec un "." comme séparateur
    tmp_val = champ.value;
    
    // On passe en point
    p = /[,]/; // chaine à rechercher
    valeur  = tmp_val.replace(p, '\.');
    
    // si le champ vaut 0, on arrête les traitements
    if (valeur == 0) {
        // Pour éviter les cas "0.00" ou ".00"...
        if (champ.value != '') {
            champ.value = "0.00";
        }
        
        return true;
    }
    
    // Déclaration objet Number
    var valeur = new Number(valeur);
    
    // Vérifie qu'il s'agit d'un nombre décimal
    if (!parseFloat(valeur)) {
        alert("Le champ \"" + libelle +"\" doit être un nombre décimal.");
        champ.focus();
        return false;
    }
    
    // Vérifie valeur positive
    if ( (positif) && (valeur<0) ) {
        alert("Le champ \"" + libelle + "\" doit être un nombre décimal positif.");
        champ.focus();
        return false;
    }
    
    // Limite le nombre de chiffre après la virgule à la précision spécifiée
    valeur = valeur.toFixed(precision); 
    
    // Si c'est ',' en tant que séparateur décimal
    if (separateur == ',') {
        p       = '\.';  // à rechercher
        tmp_val = valeur;
        valeur  = tmp_val.replace(p, ',');
    }
    
    // Retour du résultat
    champ.value=valeur;
    return true;
}



/** 
 * Vérification sur un nombre entier
 *
 * @param   objet   champ
 * @param   string  libelle
 * @return  boolean
 */
function isNumber(champ, libelle) {
    if (champ.value != parseInt(champ.value) || champ.value=="") {
        alert("Le champ \"" + libelle + "\" doit être un nombre entier.");
        champ.value = "";
        champ.focus();   
        return false;   
    }
    else return true;
}



/** 
 * Teste si la valeur de champ est compris entre iMin et iMax
 *
 * @param   objet   champ
 * @param   string  libelle
 * @param   int     iMin
 * @param   int     iMax
 * @return  boolean
 */
function isBetween(champ, libelle, iMin, iMax) {
    valeur = VirguleEnPoint(champ.value);
    
    if ((valeur < iMin) || (valeur > iMax)) {
        alert("Le champ " + libelle + " doit être compris entre " + iMin + " et " + iMax + ".");
        champ.focus();
        return false;
    } else return true;
}



/*******************************
 * CHAMPS DE TYPE RADIO
 *******************************/



/** 
 * Retourne la valeur du bouton radio sélectionné dans le formulaire spécifié par la propriété "formName".
 * Retourne "false" si aucun élément sélectionné.
 * 
 * @param   string  formName    Nom du formulaire
 * @param   string  radioName   Nom de l'objet formulaire
 * @return  string/boolean
 */
function valueOfRadio(formName, radioName) {
    
    eval("radioObj = window.document." + formName + "." + radioName);
    nbRadio = radioObj.length;
    
    for (i=0; i < nbRadio; i++) {
        if (radioObj[i].checked) {
            return radioObj[i].value;
            break;
        }        
    }
    
    return false;    
}



/*******************************
 * CHAMPS DE TYPE SELECT
 *******************************/



/** 
 * Compte le nombre d'éléments sélectionnés dans une liste de type "select"
 *
 * @params liste, l'objet "select"
 * @return int le nombre d'éléments sélectionnés dans la liste
 */
function countSelOpt(liste) {
    nbselect = 0;
    
    for (i=0; i!=liste.length; i++)
        if (liste.options[i].selected == true) nbselect++;
    
    return nbselect;
}



/** 
 * Vérifie si une valeur a été sélectionnée dans une liste déroulante "select" en partant du principe
 * qu'une liste sans résultat ou avec une première option vide aura pour valeur "-1".
 *
 * @param   object  champ   La liste déroulant à vérifier
 * @param   string  libelle Nom du champ pour personnalisation du message d'erreur
 * @return  boolean
 */
function valueInSelect(champ, libelle) {
    
    if (champ.value == '-1') {
        alert('Merci de sélectionner une valeur dans la liste "' + libelle + '".');
        return false;
    }
    
    return true;
}



/** 
 * Sert à positionner comme valeur sélectionnée dans une liste déroulante spécifiée par son identifiant IdObj 
 * l'option contentant la valeur defaultVal.
 * 
 * @param
 * @return
 */
function setValueForSelect(IdObj, defaultVal) {
    objSelect = document.getElementById(IdObj);
    
    for (var i = 0; i < objSelect.length; i++) {    
        if (objSelect.options[i].value == defaultVal) {
            index = i;
            break;
        }
    }
    
    objSelect.options[i].selected = true;
}



/*******************************
 * CHAMPS DE TYPE CHECKBOX
 *******************************/



/**
 * Coche / décoche un groupe de case à cocher.
 * 
 * @param Le nombre de checkbox à cocher/décocher    
 * @param idStartText L'id des checkBoxs doivent être composées de la sorte : idStartText + Number (example : id="checkBox1", id="checkBox2" => idStartText = checkBox)
 * @param formulaire L'objet formulaire
 *
 * <code>
 * <form name="formulaire">
 * <input type="checkbox" id="toggle" name="toggle" onClick="checkAll('checkBox', 5, document.formulaire)">Tous / Aucun<br>
 * 
 * <input type="checkbox" id="checkBox1">1<br>
 * <input type="checkbox" id="checkBox2">2<br>
 * <input type="checkbox" id="checkBox3">3<br>
 * <input type="checkbox" id="checkBox4">4<br>
 * 
 * </form>
 * </code>
 * 
 * Compatibilité: Moz 1.0.1=OK, Moz 1.4=OK, Moz 1.7=OK
 * DOM Level 2
 */
function checkAll(idStartText, n, formulaire) {
    var f = formulaire;
	var c = f.toggle.checked;
	var n2 = 0;
    
	for (i=0; i < n; i++) {
        cb = document.getElementById(idStartText + i);
		
        if (cb) {
			cb.checked = c;
			n2++;
		}
	}
}



/** 
 * Même objectif que checkAll mais bcp plus simple à mettre en place. 
 * Il suffit de passer l'objet formulaire en paramètre et toutes les cases à cocher
 * sont changées de statut en fonction de la valeur de la première case.
 *
 * @param   object  theform
 * @return  void
 */
function checkUncheckAll(theform) {
    var count  = theform.elements.length;
    var newVal = "-";
    
    for (i=0; i <count; i++) {
        // Nous prenons comme valeur pour cocher / décocher l'inverse de la valeur de la première case trouvée
        if (newVal == "-") {
            if (theform.elements[i].checked == false) newVal = true
            else                                      newVal = false; 
        }
    
        theform.elements[i].checked = newVal;
	}
}



/*******************************
 * CHAMPS DE TYPE TEXTAREA
 *******************************/



// Limite le nombre de caractères max d'un champ de type textarea
function compter(Target, max) {
	var StrLen = Target.value.length;
	if (StrLen > max ) {
		Target.value = Target.value.substring(0,max);
		alert("Attention, votre texte dépasse les " + max + " caractères, celui-ci sera  tronqué pour respecter cette limite");
		CharsLeft = max;	
	}
}



/** 
 * Compte le nombre de lignes d'une zone de texte spécifiée par "area"
 * Le comptage est basée sur les sauts de ligne de type /n
 *
 * @param  objet area  Objet TextArea
 * @return int
 */
function countLines(area) {
    var text = area.value.replace(/\s+$/g, "");
    var split = text.split("\n");
    
    return split.length;
}




/** 
 * la fonction formatArea permet de limiter la taille, spécifiée en caractère, d'une ligne d'un textarea
 *
 * Dû à la récursivité de la fonction, à utiliser sur des zones de texte pas trop grande.
 * Ex : <textarea cols="50" id="text_spec" rows="5" name="appreciation" wrap="hard" class="button" onFocus="formatArea(this, 50)" onBlur="formatArea(this, 50)"><#APPR_GEN></textarea>
 * On peut ajouter une police à chasse fixe (courier par ex) pour que la transformation du texte soit transparente pour l'utilisateur.
 * Utilisée conjointement avec CountLines, on peut tout à fait limiter la saisie d'un textarea à un certain nombre de lignes
 * 
 * Fonctionne avec un champ textarea d'au moins 28 caractères en longueur
 *
 * @param objet area (le champ textarea)
 * @param integer maxLineLength
 * @return
 */
function formatArea(area, maxLineLength) {
    // découpage de la zone de texte suivant les retours chariots, en ayant pris soin de supprimer les espaces inutiles ainsi que les retours chariots inutiles
    var text    = area.value.replace(/\s+$/g, "");
    var aLignes = text.split("\n");
    
    // Si jamais une ligne fait plus de 50 caractères :
        // 1. Découper suivant les espaces
        // 2. Tant que la ligne n'est pas <= à 50 caractères, rajouter le dernier mot à la ligne suivante
        // 3. Relancer l'opération
    for (i=0; i < aLignes.length; i++) {
        
        if (aLignes[i].length >= maxLineLength) {
            
            var aMots = aLignes[i].split(" ");
            aLignes[i] = "";
            
            // le mot le plus long = 26 caractères. Si plus, ça veut dire que c'est une connerie
            // on tronque sans s'emmerder au 26ème caractère.
            for (z=0; z<aMots.length; z++)
                if (aMots[z].length > 26) aMots[z] = Trim(aMots[z].substr(0, 26) + " " + aMots[z].substr(26));
            
            // on recompose la ligne sans le dernier mot
            for (z=0; z<(aMots.length-1); z++)
                aLignes[i] = aLignes[i] + " " + aMots[z];
            
            // Ajout du dernier mot à la ligne n+1
            i++;
            
            if (aLignes[i]) aLignes[i] = Trim(aMots[(aMots.length-1)]) + " " + aLignes[i];
            else            aLignes[i] = Trim(aMots[(aMots.length-1)]);
            
            aLignes[i] = Trim(aLignes[i]);
            
            // les lignes ont changé, on "recompile" le texte et on relance la fonction
            text = "";
            
            for (i=0; i<aLignes.length; i++)
                text = text + Trim(aLignes[i]) + "\n";
           
            area.value = "" + text;
            formatArea(area, maxLineLength);
        }
    }
}