/**
 * commun.js : fonctions communes
 * PVE 22/10/7 - (c) 2007 4DConcept 
 */


//######################################################################## LAYER

/**----------------------------------------------------- showLayer()/hideLayer()
 * afficher/masquer un layer
 * PV 3/12/7 - unused ROI, see global.js afficherLayer()/masquerLayer()
 */
function showLayer(layerId)
{
  $(nom).style.visibility = "visible";
}
function hideLayer(layerId,keepBackground)
{
  $(nom).style.visibility = "hidden";
  if(!keepBackground)  $("background_opacity").style.visibility = "hidden";
}
function setVisibility(layerId,visible)
{
  $(layerId).style.visibility =( visible ? "visible" : "hidden" );
}

/**------------------------------------------------------------------- showDiv()
 * affichage d'un div via display none/block
 * PV 17/1/8
 */
function showDiv(id,visible)
{
  $(id).style.display = visible ? "block" : "none";
}

//######################################################################## RADIO

/**---------------------------------------------------------------- radioValue()
 * valeur du radiobutton coché
 * PV 27/8/7
 */
function radioValue(radioGroup)
{
//alert(radioGroup);
  for (var i=0;i<radioGroup.length;i++)
    if (radioGroup[i].checked)
      return radioGroup[i].value;
  return '';
}


//##################################################################### CHECKBOX

/**--------------------------------------------------------------- cocherSelon()
 * coche une série de cases à cocher selon la valeur en paramètre
 * from http://www.javascriptfr.com/codes/CHECKBOX-SELECTIONNE-TOUTE-AUTRES_30690.aspx
 * <form name="monform">
 * <input type="checkbox" name="all" onclick="cocherSelon(document.monform.choix,this.checked)">
 * puis un liste de checkbox
 * <input type="checkbox" name="choix" value="1">
 * <input type="checkbox" name="choix" value="2">
 * <input type="checkbox" name="choix" value="3"></form>
 * PV 23/10/7 
 */
function cocherSelon(casacs,coche) {
  for (var i=0; i<casacs.length; i++)  casacs[i].checked = coche;
}

/**-------------------------------------------------------------- activerSelon()
 * même principe pour (dés)activation
 * PV 23/10/7 
 */ 
function activerSelon(champs,actif) {
  for (var i=0; i<champs.length; i++)  champs[i].disabled = !actif;  //alert(champs[i].id+" est "+(actif?"":"dés")+"activé");
}

/**--------------------------------------------------------------------- vider()
 * vide le champ
 * PV 14/12/7
 */
function vider(champ)
{
  switch(champ.type)
  {
    case "checkbox":     champ.checked = false;  break;
    case "text":
    case "hidden":
                         champ.value = "";  break;
    case "select-one":   champ.selectedIndex = 0;  break;
    default:
      alert("activerViderSelon("+champ.name+") : type "+champ.type+" non pris en charge !");
  }
}

/**--------------------------------------------------------------- vider_liste()
 * vide l'ensemble des champs et les réactive
 * PV 14/12/7
 */
function viderActiver_liste(champs)
{
  for (var i=0; i<champs.length; i++)
  {
    vider(champs[i]);
    champs[i].disabled = false;
  }
}

/**--------------------------------------------------------- activerViderSelon()
 * même principe + vide le champ si désactivé
 * PV 26/10/7 
 */ 
function activerViderSelon(champ,actif) {
  if (!actif)  vider(champ);  // vider le champ s'il est désactivé
  champ.disabled = !actif;
}

/**--------------------------------------------------------- activerViderSelon()
 * même principe + vide le champ si désactivé
 * PV 26/10/7 
 */ 
function activerViderSelon_liste(champs,actif) {
  for (var i=0; i<champs.length; i++)  activerViderSelon(champs[i],actif);
}

/**---------------------------------------------------------- aucuneCaseCochee()
 * définit si aucune case à cocher du groupe (casacs du même "name") est cochée
 * PV 26/11/7
 */
function aucuneCaseCochee(casacs)
{
  for (var i=0; i<casacs.length; i++)  if (casacs[i].checked)  return false;
  return true;
}   

/**--------------------------------------------------------------- champRempli()
 * indique si un champ de saisie de formulaire est rempli ou coché
 * (objets DOM de checkbox, text/hidden ou select)
 * PV 26/11/7, 7+12/12/7, 18/2/8 radio
 */
function champRempli(champ)
{
  if (isArray(champ))
  {
    // radio group
    for (var i=0;i<champ.length;i++)
      if (champ[i].checked && !champ[i].disabled)  return true;  // un des boutons radio est coché
    return false;
  }
  if (champ.disabled)  return false;
  switch(champ.type)
  {
    case "checkbox":
      return champ.checked;
    case "text":
    case "hidden":
      return champ.value.trim()!="";
    case "select-one":
      return champ.value!="";
    default:
      alert("champRempli("+champ.name+") : type "+champ.type+" non pris en charge !");
  }
  return false;
}

/**-------------------------------------------------------------- aucuneValeur()
 * définit si aucune valeur n'est définie pour une liste de champs de formulaire
 * (objets DOM de checkbox ou select)
 * PV 26/11/7
 */
function aucuneValeur(champs)
{
  for (var i=0; i<champs.length; i++)  if (champRempli(champs[i]))  return false;
  return true;
}   

/**----------------------------------------------------------- gererExclusions()
 * gestion d'exclusions mutuelles de groupes de cases à cocher au sein d'un formulaire
 * le tableau exclusion est sous la forme suivante : [[ groupe1, groupe2 ], ... ]
 * il définit les groupes de cases à cocher qui sont mutuellement exclusifs
 * un groupe peut être constitué d'une unique case à cocher ou d'un tableau de cases à cocher (objets DOM)
 * dès l'instant où au moins une des cases à cocher d'un groupe est cochée, toutes les cases à cocher de l'autre groupe sont desactivées
 * PV 26/11/7
 */
function gererExclusions(exclusions)
{
  var champsAactiver = new Array();
  var champsAdesactiver = new Array();
  exclusions.forEach( function(groupesMutuellementExclusifs)
  {
    // groupesMutuellementExclusifs est un tableau de 2 éléments définissant 2 groupes mutuellement exclusifs
    for(var i=0;i<=1;i++)
    {
      if (aucuneValeur(groupesMutuellementExclusifs[i]))
        groupesMutuellementExclusifs[1-i].forEach( function(champAactiver) 
        {
          // on met le champ dans la liste des champs à activer s'il ne fait pas déjà partie de la liste des champs à désactiver (et s'il n'y est pas déjà)
          if (!champsAdesactiver.in_array(champAactiver,true) && !champsAactiver.in_array(champAactiver,true))  champsAactiver.push(champAactiver);
        } );
      else
      {
        // une valeur est définie pour le premier groupe => désactiver les champs de l'autre groupe
        groupesMutuellementExclusifs[1-i].forEach( function(champAdesactiver) 
        {
          // on met le champ dans la liste des champs à désactiver (s'il n'y est pas déjà) et on le supprime de la liste des champs à activer s'il est dedans
          if (!champsAdesactiver.in_array(champAdesactiver,true))  champsAdesactiver.push(champAdesactiver);
          champsAactiver.deleteAll(champAdesactiver,true);
        } );
      }
    }
  } );
  // activations et désactivations
/*
  var msg = "a activer : ";
  champsAactiver.forEach(function(champ){msg+=champ.id+" ";});
  alert(msg);
*/
  activerSelon(champsAactiver,true);
/*
  var msg = "a désactiver : ";
  champsAdesactiver.forEach(function(champ){msg+=champ.id+" ";});
  alert(msg);
*/
  activerSelon(champsAdesactiver,false);
} 

//############################################################### ARRAY & STRING

// equiv. explode : chn.split(","); ATT! si on l'appelle sur une chaîne vide, retourne un tableau contenant une chaîne vide au lieu d'un tableau vide ==> utiliser explode ci-dessous
// equiv. implode : tab.join(","); ATT! ajoute le sep à la fin systématiqt ==> utiliser implode ci-dessous

/**------------------------------------------------------------------ in_array()
 * indique si un élément est dans un tableau
 * PV 22/10/7 from http://www.codingforums.com/showthread.php?t=63796
 * ["a", "b", "c"].in_array("b") // true
 * {a: 1, b: 2, c: 3 }.in_array(2) // true
 * { a: 1, b: 2, c: 3 }.in_array("2", true) // false
 */
Array.prototype.in_array = function(elt, strict) {
  if (strict) function equals(a,b) { return a === b }
  else function equals(a,b) { return a == b }

  for (var i in this)
    if (equals(this[i], elt)) return true;
  return false;
}

/**----------------------------------------------------------------- deleteAll()
 * supprime du tableau toutes les occurences de l'élément en paramètre
 * PV 26/10/7
 */
Array.prototype.deleteAll = function(elt, strict) {
  if (strict) function equals(a,b) { return a === b }
  else function equals(a,b) { return a == b }

  var i=0;
  while( i < this.length )
    if (equals(this[i], elt))  this.splice(i,1);
    else  i++;
}

/**------------------------------------------------------------------- isArray()
 * indique si l'argument est de type tableau
 * PV 11/12/7
 */
function isArray(val)
{
  return val instanceof Array || typeof val.length=="number";  // le premier pour les tableaux déclarés [], le second pour les radio groupes
}


/**------------------------------------------------------------------- implode()
 * tableau --> chaine
 * génère une chaîne à partir d'un tableau en intercalant le séparateur {sep}
 * PV 22/10/7
 */
Array.prototype.implode = function(sep) {
  var ret="";
  for (var i=0; i<this.length; i++)
  {
    ret += this[i];
    if (i<this.length-1)  ret += sep;
  } 
  return ret;
}

/**------------------------------------------------------------------- forEach()
 * fonction de parcours de tableau (standard sur FF, non implémenté sur IE)
 * PV 26/11/7
 */
if (typeof Array.prototype.forEach == "undefined")
  Array.prototype.forEach = function( fun )
  {
    for (var i=0; i<this.length; i++)  fun(this[i]);
  }

/**------------------------------------------------------------------- explode()
 * chaine --> tableau
 * éclate une chaîne en un tableau de valeurs selon le séparateur {sep} indiqué
 * chn.split(sep) retourne un tableau contenant une chaîne vide au lieu d'un tableau vide lorsqu'on l'appelle sur une chaîne vide
 * PV 22/10/7
 */
String.prototype.explode = function(sep) {
  if (this.length==0) return new Array();
  return this.split(sep);
}


/**-------------------------------------------------------------------- starts()
 * indique si la chaîne commence par la chaîne en paramètre
 * PV 8/1/8
 */
String.prototype.starts = function(chn) {
  return this.substr(0,chn.length)==chn;
}

/**------------------------------------------------------------------ lastChar()
 * retourne le dernier caractère de la chaîne
 * PV 3/5/8
 */
String.prototype.lastChar = function() {
  if (this.length==0)  return null;
  return this.charAt(this.length-1);
}

/**------------------------------------------------------------------ contains()
 * indique si la chaîne contient un (ou plusieurs) caractères ou sous-chaînes
 * on peut fournir en paramètres :
 * - une sous-chaîne dont on veut vérifier la présence
 * - une liste de sous chaînes sous la forme d'un tableau
 * - les sous-chaînes séparées par un "|"
 * PV 11/12/7
 */
function contains(chaine,caracs) {
  if (chaine.length==0) return false;
  if (isArray(caracs))  caracs = caracs.implode('|');
  var reg=new RegExp(caracs,"g");
  return chaine.match(reg);
}

/**---------------------------------------------------------------------- trim()
 * élimine les espaces aux extrémités
 * PV 30/11/7
 */
String.prototype.trim = function(){
  return this.replace(/^\s+/, "").replace(/\s+$/, "");
}

/**----------------------------------------------------------------- toIsoDate()
 * retourne la date (FR) convertie au format ISO
 * PV 6/12/7
 */
String.prototype.toIsoDate = function(){
  if (this.length==0)  return "";
  var tmp = this.explode("/");
  if (tmp.length!=3)  return "";
  return tmp[2]+"-"+tmp[1]+"-"+tmp[0];
}


/**--------------------------------------------------------------------- toInt()
 * conversion en entier
 * PV 25/3/8
 */
String.prototype.toInt = function(){
  return this-0;  // parseInt("09") retourne 0 ; avec -0 ça marche !
}
/**------------------------------------------------------------------ zeroFill()
 * ajoute des zéros à gauche pour obtenir nbCar caractères
 * PV 6/12/7
 */
function zeroFill(nombre,nbCar)
{
  var ret = ""+nombre;
  while (ret.length<nbCar)  ret = "0"+ret;
  return ret;
}


/**-------------------------------------------------------------- formatDateFR()
 * reformatte la date FR en ajoutant les 0 s'ils sont manquants
 * retourne null si la date n'a pas pu être analysée 
 * PV 6/12/7, 25/3/8
 */
function formatDateFR(date)
{
  if (date.length==0)  return null;
  date = date.explode("/");
  if (date.length!=3)  return null;
  var j = date[0].toInt();
  var m = date[1].toInt();
  var a = date[2].toInt();
  if (isNaN(j) || isNaN(m) || isNaN(a) || j<1 || j>31 || m<1 || m>12 || a<0 || a>2020) return null;
  if (a<20)   a += 2000;
  else if (a<100)  a += 1900;
  return zeroFill(j,2)+"/"+zeroFill(m,2)+"/"+a;
}


/**--------------------------------------------------------------- traiterDate()
 * traitement des champs date (formulaire de recherche ROI utilisant helper_calendar)
 * - reformatte la date dans le champ de saisie pour avoir jj/mm/aaaa (ajoute les 0)
 *   si la date est erronée retourne null  
 * - retourne la date au format ISO
 * PV 6+14/12/7
 */
function traiterDate(champDate)
{
  var date = champDate.value;
  if (champDate.disabled || date.length==0)  return "";
  date = formatDateFR(date);
  if (date==null)
  {
    alert("Format de date erroné !");
    return null;
  }
  champDate.value = date;
  return date.toIsoDate();
}


/**------------------------------------------------------------ submit_deb_fin()
 * contrôle de soumission d'un formulaire pour dates de début et de fin
 * on vérifie que les dates sont bien formées, et que deb<=fin
 * si ok on met les dates au format ISO dans les champs
 * PV +14/12/7 
 */
function submit_deb_fin(myForm)
{
  // dates de début et de fin de période converties au format ISO
  var deb = traiterDate(myForm.deb);
  var fin = traiterDate(myForm.fin);
  if (deb==null || fin==null)  return false;  // erreur dans le format de date
  if (deb.length>0 && fin.length>0)
    if (deb>fin)
    {
      alert("La date de début doit être inférieure à la date de fin !");
      return false;
    }
  // les valeurs au format ISO sont copiées dans les champs avant soumission
  myForm.deb.value = deb;
  myForm.fin.value = fin;
  return true;
}

/**---------------------------------------------------------------- submit_dat()
 * contrôle de soumission d'un formulaire pour date
 * on vérifie que la date est bien formée
 * si ok on met la dates au format ISO dans le champ
 * PV +14/12/7
 */
function submit_dat(myForm)
{
  // convertie au format ISO
  var dat = traiterDate(myForm.dat);
  if (dat==null)  return false;  // erreur dans le format de date
  // la valeur au format ISO est copiée dans le champs avant soumission
  myForm.dat.value = dat;
  return true;
}



//######################################################################### FORM

/**------------------------------------------- form_desactiver_champs_si_vides()
 * désactivation des champs vides pour éviter de surcharger l'adresse GET
 * - myForm est l'objet DOM correspondant à la balise <form>
 * - champs est un tableau du type [ "deb", "fin", "rch", "tit" ]
 * - note : il est impossible d'éviter l'envoi des coordonnées d'un <input type="image" name="toto" /> (ne peut pas être désactivé),
 *          mais en le rendant anonyme on passe &x=11&y=22 au lieu de &toto.x=11&toto.y=22
 * PV 23/11/7, 14/12/7
 */    
function form_desactiver_champs_si_vides(myForm,champs)
{
  champs.forEach( function(champ) {
    var o = myForm.elements[champ];
    if (o)  o.disabled = o.disabled || (o.value.length==0);  // laisser désactivé s'il l'est déjà
    else alert("Champ inconnu: "+champ);
  } );
  return true;  // peut ainsi être appelé directement par le "onSubmit", par exemple : <form onSubmit="return form_desactiver_champs_si_vides(this,['champ1','champ2'])" ... >
}


/**============================== gestion d'une liste d'ids dans un champ hidden
 * Principe :
 * - une série de cases à cocher auxquelles des ids sont associés
 * - un champ hidden qui contient la liste des identifiants cochés
 * Les fonctions ci-dessous sont là pour ajouter ou supprimer les ids du champ hidden
 * PV 22/10/7 - utilise Prototype
 */ 

/**------------------------------------------------------------------ majListe()
 * mise à jour de la liste de valeurs contenue dans le {champListe}, séparées par {sep}
 * en ajoutant ou en supprimant de la liste {val} selon {isIn} (false=>supprimer, true=>ajouter)
 * PV 22/10/7
 */  
function majListe(champListe,sep,val,isIn)
{
//alert("majListe "+champListe+" "+val+" "+isIn);
  champListe = $(champListe);
  var liste = champListe.value.explode(sep);
  // suppression de val dans le tableau
  var i=0;
  while (i<liste.length)
    if (liste[i]==val)  liste.splice(i,1);
    else i++;
  if (isIn)
    // val doit être dans le tableau
    liste.unshift(val);
  // on remet les valeurs dans le champ hidden
  champListe.value = liste.implode(sep);
}
