/*******************************
 * 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 retour;
    var ine = trim(element.value);

	if (ine == '')
        return !obligatoire;

	else{
		var expr = new RegExp("^([0-9]{2})(-?)([0-9]{2})(-?)([0-9]|A|a)([0-9]{5})(-?)([a-zA-Z]{1})$", "i");

		if (expr.test(ine) === false) {
			alert('"' + ine + '" n\'est pas un numéro INE valide !\nFormat du champ attendu :\n99-99-999999-X (10 chiffres plus une lettre)\nou\n99-99-A99999-X');
			return false;
		}else{
			var sousChaineINE = ine.split('-');
			if (sousChaineINE.length > 1)
			{
				ine = '';
				for (pos in sousChaineINE)
					ine += sousChaineINE[pos];
			}
			else
				ine = sousChaineINE[0];

			// Appel du test via l'algo WinCFA
			var valide = testINE(ine);
			if (!valide)
				alert('Le numéro INE n\'a pas pu être validé, la clé ne correspond pas');
			return valide;
		}
	}
}


/*
 * 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;
        result = (cle == alphabet[j - 1]);
    }
    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
 * @param   withSlash   Permet d'indiquer si le slash est autorisé
 * @return  bool
 */
function numberOnly(event, withSlash) {
    //x08 : backspace    x00 : Home, End, Del, Tab et Flèches
    var specialsKey = /[\x00\x08]/;

    //Nombres numériques
    var validKey = (withSlash === true) ? /\/|[0-9]/ : /[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) {

	setValueForSelectElt(document.getElementById(IdObj), defaultVal);
}

function setValueForSelectElt(objSelect, defaultVal) {

	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);
        }
    }
}
