/* copyright

L'auteur de ce code est Michel Meyran, pour le compte de SARL Capitalise et Moneyshop et ses affiliés. Toute utilisation de ce code ou une section de celui-ci est soumise à l'autorisation de l'auteur ou de son employeur.

Ce code n'est pas a utiliser tel quel; par souci de performance et de taille, il est preferable de le compresser au prealable, a l'aide du Javascript Compressor de Dean Edwards; cependant, ce compresseur requierrant un code propre, il est preferable de soumettre ce code a JSlint, pour relever les erreurs de type 'used before declared' ou 'missing semicolon'. Note: le compresseur supprimera les commentaires et les retours chariot; conservez une copie 'propre' de ce code dans un coin.

*/

// initedform est une simple variable globale utilisee a la fin par initform() pour determiner si le formulaire a ete initialise ou non; ceci permet de declarer initform() sur les evenement DOMContentLoaded, onLoad etc. sans risquer d'initialiser le formulaire deux fois.
var initedform=false;

//presque chaque fonction de verification commence avec la meme sequence de code, qui n'est la que pour gerer le modele d'evenement IE7-8. Une refactorisation serait d'associer les methodes de verification a chaque instance d'ojet, et selon le navigateur, l'appeler directement.

// Actuellement, toutes les instances ont une methode generique checkme, laquelle appelle, selon l'instance, telle ou telle fonction. Note: ce wrapper pourrait permettre de supprimer les 2 premieres lignes de chaque fonction... A tester.

// rmvdef supprime la valeur par defaut mise dans l'input, pour tout sauf les champs SELECT. Est detachee car peut etre appelee par un event listener */ ?>
function rmvdef(){
  var objet = ((document.addEventListener)||(event.srcElement === null))?this:event.srcElement;
  if (objet.estdefaut()&&(objet.type !== 'select-one')){
    objet.value='';}
}

// checkloyer travaille avec le type de logement, le montant du loyer, le montant des APL et le montant de l'emprunt immo. Certaines verifications sont faites afin de s'assurer que le client ne nous dit pas n'importe quoi

function checkloyer(objet){
  if (typeof(objet) === 'undefined'){objet = this;}
  if (objet.estdefaut()){return;}

  var formelems = document.forms.formulaire.elements,
    logement = formelems.TypeLogement,
    loyer =formelems.Loyer,
    apls = formelems.APLMensuel,
    empruntimmo = formelems.SoldePretMobilier,
    temployer,
    tempapls;

  switch(logement.value){
    case '1':
      loyer.requis = false;
      hidenseek("loyer");
      if (loyer.value > 0){
        if (!confirm("Votre loyer de "+loyer.value+" euros n'est PAS une mensualité d'emprunt!\nVous êtes sûr?")){
          loyer.value = apls.value = '';
          apls.erreur();
          loyer.erreur();}
      else {loyer.erreur(0);}
      }
      if (parseInt(empruntimmo.value,10) <= 0){
        alerte("Si vous ne voulez pas racheter votre emprunt immobilier: mettez-nous quand même le montant restant dû, cochez la case 'Ne pas restructurer l'immobilier'. Si vous êtes propriétaire sans emprunt immobilier, passez outre cet avertissement.");
        break;}
      objet.erreur(0);
      break;
    case '2':
      loyer.requis = true;
      hidenseek("loyer");
      if ((parseInt(loyer.value,10) <= 0) && (isNaN(parseInt(loyer.value,10)))){
        loyer.erreur(2);
        break;
        }
      if ((parseInt(loyer.value,10) > 0) && (parseInt(loyer.value,10) < 300)){
        if (confirm('Votre Loyer est bien bas! Avez-vous deduit les APL?')){
          if (parseInt(loyer.value,10)> 0){
            temployer = parseInt(loyer.value,10);}
          else {temployer = 300;}
          if (parseInt(apls.value,10)> 0){
            tempapls = parseInt(apls.value,10);}
          else {tempapls = 300-temployer;}
          loyer.value=temployer+tempapls;
          if(typeof(apls) !== "undefined"){
            apls.value = tempapls;
            apls.erreur(1);}
          loyer.erreur(1);
        }
        break;
      }
      objet.erreur(0);
      break;
    default:
      loyer.requis = false;
      if (parseInt(loyer.value,10)> 0){
        logement.value = '2';
        hidenseek("loyer");
        objet.checkme();} // recursion de la fonction - permet d'eviter de reecrire du code
      else {
        hidenseek("loyer","none");
        loyer.value = loyer.defaut;
        loyer.erreur();
        if(typeof(apls) !== "undefined"){
          apls.value = apls.defaut;
          apls.erreur();}
        }
      objet.erreur(0);
      break;
  }
  if(!logement.estdefaut()){logement.erreur(0);}
}

function checkpost(objet){
  if (typeof(objet) === 'undefined'){objet = this;}
  if (objet.estdefaut()){return;}

  var chaine = objet.value,
    retourOK = (/^[0-9]{5}$/),
    nombre = parseInt(chaine,10),
    retourCorrige = (/^[0-9]{4}$/);

  if (retourOK.test(chaine)){
    objet.erreur(0);
    return;}

  if (retourCorrige.test(nombre)){
    objet.value = "0"+nombre;
    objet.erreur(1);
    return;}

  alerte("Code postal faux: 5 chiffres, ni lettres ni espaces");
  objet.value = objet.defaut;
  objet.erreur(2);
}

// checknum s'assure que l'objet retourne une valeur composee d'un entier numerique, plus evolue que parseInt()

function checknum(objet){
  if (typeof(objet) === 'undefined'){objet = this;}
  if (objet.estdefaut()){return;}
  var mini = objet.mini?parseInt(objet.mini,10):0,
    maxi = objet.maxi?parseInt(objet.maxi,10):Math.pow(2,32),
    med = objet.med?parseInt(objet.med,10):mini,
    origchaine = objet.value,
    comapos,
    chaine,
    epress = (/[^\d]/g);

  if ((mini >= maxi)||(med >= maxi) || (med < mini)){
    alerte('mini/med/maxi etranges!');
    return;}
  
  comapos=origchaine.search(/,|\./);
  if (comapos < 1){comapos = origchaine.length;}

  chaine = parseInt(origchaine.substr(0,comapos).replace(epress, ""),10);

  if (isNaN(parseInt(chaine,10))){
    objet.value = objet.defaut;
    objet.erreur(2);
    
    return;}

  if ((mini > chaine) || (chaine > maxi)){
    chaine = (chaine <= mini)?mini:maxi;
    alerte("Hors intervalle! Doit etre entre "+mini+" et "+maxi);}

  objet.erreur(((chaine !== parseInt(origchaine,10))||(chaine < med))?1:0);

  if (chaine < med){
    alerte('Le montant ('+chaine+') dans '+detectParent(objet,'fieldset',true).getElementsByTagName('legend')[0].firstChild.firstChild.nodeValue+' est étrangement bas! '+objet.libelle);
  }

  objet.value = chaine;
}

// checkmail verifie que l'adresse email est correctement structuree - et est capable de demander une correction si celle-ci est juste incomplete. Cette correction est necessaire pour les noms de domaines de type .museum, rarissimes mais existants

function checkmail(objet){
  if (typeof(objet) === 'undefined'){objet=this;}
  if (objet.estdefaut()){return;}

  var testmail = objet.value.toLowerCase(),
    retour = (/^[a-z\d._%+\-]+@[a-z\d.\-]+\.[a-z]{2,4}$/), // retourne TRUE si l'adresse est entierement bien formee
    ratrap = (/^[a-z\d._%+\-]+@[a-z\d.\-]/); // retourne TRUE si seule la terminaison d'adresse est fausse

  if (!retour.test(testmail)){
    if (!ratrap.test(testmail)){
      objet.erreur(2);
      objet.value = objet.defaut;
      alerte("Email faux!","La structure d'un email est: nom@domaine.suffixe");
      return;}
    objet.erreur(1);
    objet.value = testmail;
    alerte("email incorrect","Terminaison fausse ou manquante - le suffixe inclut en général entre 2 et 4 caractères (sauf 'museum')");
    return;
  }
  objet.erreur(0);
  objet.value = testmail;
}

// checkdate s'ingenie a reconstituer une date correcte dans le format que nous voulons - et retourne un different niveau d'erreur selon a quel point il a fallu corriger le champ

function checkdate(objet){
  if (typeof(objet) === 'undefined'){objet = this;}
  if (objet.estdefaut()){return;}

  var er = false,
    td = objet.value,
    regx = (/^(0[1-9]|[12]\d|3[01])[\/](0[1-9]|1[012])[\/](18|19|20)\d\d$/),
    dbb = (/\/\//g),
    ste = (/^\/|\/$/g),
    nond = (/[^\d\/]/g),
    an,d,mini,maxi,annee,mois,jour,maxJour;
    mini = objet.mini?parseInt(objet.mini,10):1900;
    maxi = objet.maxi?parseInt(objet.maxi,10):d.getFullYear();

  if (td === ""){ return;}

  if (!regx.test(td)){  // premier cycle de test: on corrige integralement l'input pour ne garder que de l'interessant.
    td = td.replace(nond,"/");
    while (dbb.test(td)||ste.test(td)){
      td = td.replace(dbb,"/").replace(ste,"");
      er = true;}

    if (td.indexOf("/") === -1){
      objet.erreur(2);
      objet.value = objet.defaut;
      return;}

    if (td.substr(1,1) === "/"){td = "0"+td;}
    if (td.substr(4,1) === "/"){td = td.substr(0,3)+"0"+td.slice(3);}

    an = parseInt(td.slice(6),10 );
    d = new Date();

    if ((an >= 0) && (an <= (maxi-2000))){
      an = an+2000;
      er = true;}
    if (an<100){
      an = an+1900;
      er = true;}

    td = td.substr(0,6)+an;}

  if (!regx.test(td)){ // si apres le 1er cycle le resultat n'est toujours pas bon c'est que c'etait irrecuperable - on quitte avec erreur maxi
    objet.value=objet.defaut;
    objet.focus();
    objet.erreur(2);
    
    return;}

  // A ce point on veut verifier que la date est logiquement valide; par defaut, ce code n'est accessible que si une date valide a pu etre reconstituee. Correctif: 'an' reconstitue une annee, millenaire inclus. 'annee' determine la plage d'annees valides selon les parametres de l'input.
  td = td.split("/");
  annee = parseInt(td[2],10);
  mois = parseInt(td[1],10);
  jour = parseInt(td[0],10);
  td = '';
  maxJour = ((mois === 4)||(mois === 6)||(mois === 9)||(mois === 11))?30:(mois === 2)?(((annee % 4 === 0)&&(annee % 100 !== 0))||(annee % 400 === 0))?29:28:31;

  if (jour>maxJour){jour=maxJour;er=true;}

  if (mois < 10){mois = "0"+ mois.toString();}
  if (jour < 10){jour = "0"+ jour.toString();}
  if (annee < mini){annee = mini; er = true;}
  if (annee > maxi){annee = maxi; er = true;}
  objet.erreur(er?1:0);

  objet.value=jour+"/"+mois+"/"+annee;
}

// checkname recupere les proprietes d'un input, et son type de casse - et corrige en fonction de la propriete 'casse' de l'objet. Si l'objet n'a pas de propriete casse, ne change rien.

function checkname(objet){
  if (typeof(objet) === 'undefined'){objet = this;}

  var tn = objet.value.replace(/[^A-Za-z\xC0-\xFF\- ]/g,"").replace(/\-/g," "),// vire les caracteres indesirables
    besp = /^\s|\s$/g,
    dbsp = /\s\s/g,
    i,atn;
  switch (objet.casse){
    case 1 :
      atn = tn.split(" ");
      tn = '';
      for (i = atn.length-1;i >= 0;i=i-1){tn = atn[i].charAt(0).toUpperCase()+atn[i].slice(1).toLowerCase()+" "+tn;}
      break;
    case 2 : tn = tn.toUpperCase();
      break;
    default: break;
  }

  while (besp.test(tn)||dbsp.test(tn)){tn = tn.replace(besp,"").replace(dbsp," ");}// supprime les espaces en trop

  objet.erreur((tn.length === objet.value.length)?0:(tn.length > 0)?1:2);
  if (objet.estdefaut()){return;}
  objet.value = tn;
}

//checktext - ne fait pas grand-chose... Pourrait contenir une fonction pour supprimer tout caractere de controle, mais htmlentities() s'en occupe cote php
function checktext(objet){
  if (typeof(objet) === 'undefined'){objet = this;}
  objet.erreur(objet.estdefaut()?'':0);
}

// checkphone vire tout ce qui n'est ni chiffre ni espace ou signe +; comme un 'phone peut contenir un indicatif, on ne peut limiter le nombre de caracteres
function checkphone(objet){
  if (typeof(objet) === 'undefined'){objet = this;}
  if (objet.estdefaut()){return;}

  var tp = objet.value,
    tl = tp.length;
  tp = tp.replace(/[^\d\+ ]/g,"");

  objet.erreur((tp.length === 0)?2:(tp.length !== tl)?1:0);
  objet.value = tp;
}

// checkage reconstitue le format que nous voulons pour les ages des enfants - et effectue une comparaison avec le nombre d'enfants declares, pour eviter les incoherences. Cette methode est utilisee plusieurs fois dans le formulaire entier
function checkage(objet){
  if (typeof(objet) === 'undefined'){objet=this;}
  if (objet.estdefaut()){return;}

  var rv = objet.nbenf(),
    dbs = new RegExp(/,,/g),
    dfs = new RegExp(/^,|,$/g),
    bpat = new RegExp(/^(([1-9]|1[0-8])[,]){0,15}([1-9]|1[0-8])$/),
    ta = objet.value,
    pat = new RegExp('^(([1-9]|1[0-8])[,]){'+(rv-1)+'}([1-9]|1[0-8])$');

  if (isNaN(rv)){rv = -1;}
  
  ta=ta.replace((/[^\d]/g),",");

  while (dbs.test(ta) || dfs.test(ta)){ta = ta.replace(dbs,",").replace(dfs,"");}
  
  if (!bpat.test(ta)){
    objet.value = objet.defaut;
    objet.erreur(2);
    alerte("Ages entre 1 et 18 ans (nourrissons, mettez 1");
    return;}

  objet.value = ta;

  if (pat.test(ta)){
    objet.erreur(0);
    return;}
  objet.erreur(1);
  alerte("Pas autant d'ages que d'enfants: "+rv);
  
}

// checkrevenu n'existe reellement que pour verifier le min/max de l'objet. Cette methode pourrait en fait etre appliquee a tous les inputs de type entier...
function checkrevenu(objet){
  if (typeof(objet) === 'undefined'){objet = this;}
  if (objet.estdefaut()){return;}
  checknum(objet);
  if(parseInt(objet.value,10) < objet.mini){
    objet.value = objet.defaut;
    objet.erreur(2);
    return;
  }
  if(parseInt(objet.value,10) < objet.med){
    objet.erreur(1);
    alerte("Revenu annuel faible; si vous avez un co-emprunteur, renseignez ses champs.");
    return;
  }
  objet.erreur(0);
}

function checkselect(objet){
  if (typeof(objet) === 'undefined'){objet=this;}
  objet.erreur(objet.estdefaut()?'':0);
}

// section de declaration de methodes communes a presque tous les objets

// objerreur est une propriete pour tous les inputs; elle est rajoutee comme methode des instances d'objets input. Note: pourrait etre remplacee en creant une sous-classe d'inputs pour le form concerne, mais tous les navigateurs ne le supporteront pas

function objerreur(er){
  var cls;
  er = parseInt(er,10);
  switch (er){
    case 0 : cls = 'bdOK';break;
    case 1 : cls = 'bdWarning';break;
    case 2 : cls = 'bdError';break;
    default : cls = this.requis?'bdRequired':'defaut';break;
  }
  this.errlevel = er;
  this.className = cls;
  if ((er>0)&&(scrollmoi)){window.location = '#'+detectParent(this,'fieldset',1).getElementsByTagName('legend')[0].getElementsByTagName('a')[0].getAttribute('id');}
}

// propriete booleenne associee a un objet qui renvoie si l'objet est actuellement a sa valeur par defaut (ou vide)
function objestdefaut(){
  if ((this.value === "")|| (this.value === this.defaut)){
    this.value=this.defaut;
    this.erreur();
    return true;}
  return false;
}

// la fonction check()est une 'coquille vide' destinee a attacher objet.checkme a un objet.evenement;elle sert aussi a gerer l'objet 'event' d'IE, incapable d'utiliser 'this' correctement
function check(){
  var objet = ((document.addEventListener)||(event.srcElement === null))?this:event.srcElement;
  objet.checkme();
}

// checkonsubmit fait un audit de toutes les erreurs contenues dans le formulaire; selon les niveaux d'erreur, la soumission du formulaire sera refusee avec l'indication des endroits a corriger, ou demandera confirmation que les corrections automatiques sont bonnes, ou passera simplement OK pour la soumission
function checkonsubmit() {
  var wrns = "",
    errs = "",
    reqs = "",
    ret = false,
    scrollmoi = false,
    i,elem;

  for (i = this.length-1; i>= 0; i=i-1) {
    elem = this.elements[i];
    if (elem.estdefaut() && elem.requis){
      reqs = " "+elem.libelle+" - "+reqs;
      elem.erreur(2); }

    switch (elem.errlevel) {
      case 1 : wrns = " "+elem.libelle+" "+elem.value+" - "+wrns;
        break;
      case 2 : if (!elem.requis) {errs = " "+elem.libelle+" - "+errs; }
        break;
      default: continue;
    }
  }

  scrollmoi = true;

  if ((errs+reqs+wrns) === 0) {return true;}

  if (errs !== "") {
    alerte("Veuillez corriger les erreurs suivantes: ",errs);
    ret = true;
  }
  if (reqs !== "") {
    alerte("Les champs suivants doivent être renseignés: ",reqs);
    ret = true;
  }
  if (wrns !== "") {alerte("Vérifiez les champs suivants: ",wrns);}

  if (ret){ return false;}
  wrns = wrns.replace(/<li>/gi,"\n\t");
  return confirm(wrns.replace(/(<([^>]+)>)/gi,"")+"\nAcceptez-vous ces corrections?");
}

function checkonreset(){
  var elems = EventIE?window.event.srcElement.elements:this.elements,i;
  for (i = elems.length-1; i>= 0; i=i-1) {
    switch (elems[i].type){
      case 'text':
      case 'textarea':
      case 'checkbox':
      case 'select-one':elems[i].erreur();break;
      default:break;
    }
  }
}

function retIntercept(e){
  var Ent = (parseInt(EventIE?window.event.keyCode:e.which,10) === 13)?true:false;
  if(Ent){
    this.blur();
    Ent = !confirm('Touche [Return] détectée: soumettre le formulaire?');
    this.focus();
  }
  return !Ent;}

// initevent initialise les ecouteurs d'evenement de tous les objets du formulaire passe en parametre. Elle est appelee une fois au moment du chargement du formulaire, mais comme ledit chargement depend des evenements supportes par le navigateur, elle est repetee 4-5 fois dans le code 
function initevent(objet){
  var i,elem;
  for (i = objet.length-1;i >= 0;i=i-1){
  elem = objet.elements[i];
  switch (elem.type){
    case 'text':
      elem.onkeypress=retIntercept;
      addEvent(elem,'blur',check);
      addEvent(elem,'focus',rmvdef);
      break;
    case 'textarea':
      addEvent(elem,'blur',check);
      addEvent(elem,'focus',rmvdef);
      break;
    case 'checkbox':
      elem.onkeypress=retIntercept;
      addEvent(elem,'change',check);
      break;
    case 'select-one':
      addEvent(elem,'change',check);
      break;
    case 'reset':
    case 'submit': break;
    default: continue;}
  elem.rmvdef=rmvdef;
  elem.erreur();
  elem.checkme();
  }
}

function loyerverif(){
  checknum(this);
  if(this.errlevel <= 0){
    checkloyer(this);}
}

// initvar initialise les proprietes et methodes des objets du formulaire passe en parametre. Fonction lourde en code mais simple a lire
function initvar(objet){
  var libelles = document.getElementsByTagName('label'),i,curr,oelm,d,oi;
  for (i = libelles.length-1;i >= 0;i=i-1){
    curr = libelles[i].htmlFor;
    if(curr !== ''){if(document.getElementById(curr)){document.getElementById(curr).libelle = libelles[i].childNodes[0].nodeValue;}}
  }
  libelles = '';

  oelm = objet.elements;

// gestion des champs requis - ajouter la propriete requis=true a un champ du formulaire s'occupe du CSS et des fonctions de verification. Doit etre reflete dans FoncForm.php!
  oelm.NomEmpr.requis =
  oelm.PrenomEmpr.requis =
  oelm.DateNaissEmpr.requis =
  oelm.Adresse.requis =
  oelm.CodePostal.requis =
  oelm.Ville.requis =
  oelm.Telephone.requis =
  oelm.NombreEnfantEmpr.requis =
  oelm.TypeLogement.requis =
  oelm.SalaireEmprAnnuel.requis = true;

// gestion de la casse des champs texte
  oelm.NomEmpr.casse = 2;
  if(oelm.NomCoEmpr){oelm.NomCoEmpr.casse = 2;}
  oelm.PrenomEmpr.casse =
  oelm.Ville.casse = 1;
  if(oelm.PrenCoEmpr){oelm.PrenCoEmpr.casse = 1;}

  d = new Date();

  oelm.DateNaissEmpr.mini=parseInt(d.getFullYear(),10) - 115;
  oelm.DateNaissEmpr.maxi=parseInt(d.getFullYear(),10) - 15;
  if(oelm.DateNaissCoEmpr){oelm.DateNaissCoEmpr.mini = parseInt(d.getFullYear(),10) - 115;}
  if(oelm.DateNaissCoEmpr){oelm.DateNaissCoEmpr.maxi = parseInt(d.getFullYear(),10) - 15;}

  if(oelm.DateRepriseCongeParental){
    oelm.DateRepriseCongeParental.mini = d.getFullYear();
    oelm.DateRepriseCongeParental.maxi = d.getFullYear()+ 3;}

// gestion des champs numeriques avec min/med/max

  if(oelm.PensionAlimentaireRecuMensuel){oelm.PensionAlimentaireRecuMensuel.mini = 0;
    oelm.PensionAlimentaireRecuMensuel.maxi = 5000;}
  if(oelm.PensionAlimentaireVerseMensuel){oelm.PensionAlimentaireVerseMensuel.mini = 0;
    oelm.PensionAlimentaireVerseMensuel.maxi = 5000;}
  oelm.NombreEnfantEmpr.mini =
  oelm.MensualiteImmo.mini = 
  oelm.MensualiteAutre.mini = 0;
  oelm.NombreEnfantEmpr.maxi = 15;
  oelm.SalaireEmprAnnuel.mini = 5000;
  oelm.SalaireEmprAnnuel.med = 12000;
  if(oelm.SalaireCoEmprAnnuel){oelm.SalaireCoEmprAnnuel.med = 5000;}
  if(oelm.RevenuFoncierAnnuel){oelm.RevenuFoncierAnnuel.med = 3000;}
  oelm.MensualiteImmo.maxi =
  oelm.MensualiteAutre.maxi = 10000;

//gestion des methodes de retour du nombre max d'enfants pour 3 champs
  if(oelm.AgeEnfantEmpr){
    oelm.AgeEnfantEmpr.nbenf=function(){return parseInt(oelm.NombreEnfantEmpr.value,10);};
    oelm.AgeEnfantPensionAlimentaireRecu.nbenf=function(){return parseInt(oelm.NombreEnfantPensionAlimentaireRecu.value,10);};
    oelm.AgeEnfantPensionAlimentaireVerse.nbenf=function(){return parseInt(oelm.NombreEnfantPensionAlimentaireVerse.value,10);};
    oelm.AgeEnfantEmpr.checkme =
    oelm.AgeEnfantPensionAlimentaireRecu.checkme =
    oelm.AgeEnfantPensionAlimentaireVerse.checkme = checkage;}

  if(oelm.NomCoEmpr){oelm.NomCoEmpr.checkme = checkname;}

  oelm.NomEmpr.checkme =
  oelm.PrenomEmpr.checkme =
  oelm.Ville.checkme = checkname;
  if(oelm.ProfEmpr){oelm.ProfEmpr.checkme = checkname;}
  if(oelm.PrenCoEmpr){oelm.PrenCoEmpr.checkme = checkname;}
  if(oelm.ProfCoEmpr){oelm.ProfCoEmpr.checkme = checkname;}
  if(oelm.PreciseAutreRevenu){oelm.PreciseAutreRevenu.checkme = checkname;}
  if(oelm.VotreProjet){oelm.VotreProjet.checkme = checkname;}

  oelm.CodePostal.checkme = checkpost;

  oelm.SalaireEmprAnnuel.checkme = checkrevenu;

  oelm.DateNaissEmpr.checkme = checkdate;
  if(oelm.DateNaissCoEmpr){oelm.DateNaissCoEmpr.checkme = checkdate;}
  if(oelm.DateRepriseCongeParental){oelm.DateRepriseCongeParental.checkme = checkdate;}

  oelm.Adresse.checkme = checktext;
  if(oelm.Commentaire){oelm.Commentaire.checkme = checktext;}

  oelm.TypeLogement.checkme = checkloyer;

  oelm.Telephone.checkme = oelm.Portable.checkme = checkphone;

  oelm.Email.checkme = checkmail;

  oelm.Loyer.checkme = loyerverif;
  if(oelm.APLMensuel){oelm.APLMensuel.checkme = loyerverif;}
  oelm.SoldePretMobilier.checkme = loyerverif;

  oelm.NombreEnfantEmpr.checkme = function(){
    checknum(this);
    var chk=parseInt(this.value,10);

    hidenseek('enfant',(chk > 0)?'':'none');
    if (chk > 0){return;}
    if(oelm.AgeEnfantEmpr){oelm.AgeEnfantEmpr.value = "";}
    if(oelm.CafMensuelleEnfant){oelm.CafMensuelleEnfant.value = "";}
    if(oelm.PensionAlimentaireRecuMensuel){oelm.PensionAlimentaireRecuMensuel.value = "";}
    if(oelm.NombreEnfantPensionAlimentaireRecu){oelm.NombreEnfantPensionAlimentaireRecu.value = "";}
    if(oelm.AgeEnfantPensionAlimentaireRecu){oelm.AgeEnfantPensionAlimentaireRecu.value = "";}
  };

  if(oelm.PensionAlimentaireRecuMensuel){oelm.PensionAlimentaireRecuMensuel.checkme=function(){
    checknum(this);
    var chk=parseInt(this.value,10);

    hidenseek('pensionr',(chk > 0)?'':'none');
    if (chk > 0){return;}
    oelm.NombreEnfantPensionAlimentaireRecu.value = "";
    oelm.AgeEnfantPensionAlimentaireRecu.value = "";
  };}

  if(oelm.NombreEnfantPensionAlimentaireRecu){oelm.NombreEnfantPensionAlimentaireRecu.checkme=function(){
    checknum(this);
    var nbenf=oelm.AgeEnfantEmpr.nbenf();
    if (parseInt(this.value,10)> nbenf){
      alerte("Plus d'enfants pensionnes ("+this.value+") que d'enfants a charge ("+nbenf+")!");
      this.value = nbenf;}
  };}

  if(oelm.PensionAlimentaireVerseMensuel){oelm.PensionAlimentaireVerseMensuel.checkme = function(){
    checknum(this);
    var chk = parseInt(this.value,10);

    hidenseek('pensionv',(chk > 0)?'':'none');
    if (chk > 0){return;}
    oelm.NombreEnfantPensionAlimentaireVerse.value = "";
    oelm.AgeEnfantPensionAlimentaireVerse.value = "";
  };}

  if(oelm.CongeParental){oelm.CongeParental.checkme = function(){
    var chk = parseInt(this.value,10);
    hidenseek('congeparent',((chk === 1)||(chk === 3))?'':'none');
  };}

  if(oelm.Apport){oelm.Apport.checkme = function(){hidenseek('apportprojet',this.checked?'':'none');};}

  if(oelm.RelationCoEmpr){oelm.RelationCoEmpr.checkme=function(){
    var chk=parseInt(this.value,10);
    hidenseek('coempr',(chk === 0)?'none':'');};}

  if(oelm.DomTomCorse){oelm.DomTomCorse.checkme = function(){};}
  if(oelm.FICP){oelm.FICP.checkme = function(){};}
  if(oelm.IgnoreImmo){oelm.IgnoreImmo.checkme = function(){};}

  for(i=oelm.length-1;i >=0 ;i=i-1){// recupere les valeurs affichees a la base et les stocke ailleurs pour restauration
    oi = oelm[i];
    oi.errlevel = '';
    if(oi.type === 'textarea'){oi.defaut = oi.childNodes[0].nodeValue;}
    else if(oi.type === 'select-one'){oi.defaut = findDefOptVal(oi);}
    else {oi.defaut = oi.getAttribute('value');}
    // certains navigateurs conservent la 'value' d'un element d'un chargement de page a un autre;si l'element n'est pas un SELECT, ceci prend directement la valeur inscrite dans le html - soit pour l'attribut 'value' (les INPUT), soit pour les valeurs par défaut des enfants (SELECT), soit les noeuds texte contenus (TEXTAREA)
    oi.erreur = objerreur;
    oi.estdefaut = objestdefaut;
    if (!oi.checkme){
      oi.checkme = checknum;
    }
  }
}

function createlegende(){
  addElem(document.body,"","div","legende","onglet");
  var leg = document.getElementById("legende"),zeP;
  addElem(leg,'','p','','');
  zeP = leg.childNodes[0];
  addElem(zeP,'Légende: ','strong','','');
  zeP.appendChild(document.createTextNode('les champs sont '));
  addElem(zeP,'requis','span','','bdRequired');
  zeP.appendChild(document.createTextNode(', '));
  addElem(zeP,'erroné','span','','bdError');
  zeP.appendChild(document.createTextNode(' ou '));
  addElem(zeP,'incertain','span','','bdWarning');
  zeP.appendChild(document.createTextNode('; un champ encore vide contient une '));
  addElem(zeP,'aide de saisie','span','','defaut');
  zeP.appendChild(document.createTextNode('.'));
}

function createsimul(){
  var calcu = document.getElementById('calcul'),calculist,i;
  addElem(calcu,'Simulateur','h4','','');
  addElem(calcu,'','ul','listesimul','');
  calculist = document.getElementById('listesimul');
  for(i=0;i<4;i=i+1){addElem(calculist,'','li','','');}

  addElem(calculist.childNodes[0],'Total dettes','label','lbl_calculsomme','');
  document.getElementById('lbl_calculsomme').setAttribute('for','calculsomme');
  addElem(calculist.childNodes[0],'','input','calculsomme','');
  calculist.childNodes[0].setAttribute('title','Montant actuel des dettes totales');
  document.getElementById('calculsomme').setAttribute('disabled','disabled');

  addElem(calculist.childNodes[1],'Ratio (%)','label','lbl_ratio','');
  document.getElementById('lbl_ratio').setAttribute('for','ratioendett');
  addElem(calculist.childNodes[1],'','input','ratioendett','');
  calculist.childNodes[1].setAttribute('title','Ratio d\'endettement actuel');
  document.getElementById('ratioendett').setAttribute('disabled','disabled');

  addElem(calculist.childNodes[2],'Mens. Min','label','lbl_capmin','');
  document.getElementById('lbl_capmin').setAttribute('for','capmin');
  addElem(calculist.childNodes[2],'','input','capmin','');
  calculist.childNodes[2].setAttribute('title','Nouvelle mensualité: minimale');
  document.getElementById('capmin').setAttribute('disabled','disabled');

  addElem(calculist.childNodes[3],'Mens. Max','label','lbl_capmax','');
  document.getElementById('lbl_capmax').setAttribute('for','capmax');
  addElem(calculist.childNodes[3],'','input','capmax','');
  calculist.childNodes[3].setAttribute('title','Nouvelle mensualité: maximale');
  document.getElementById('capmax').setAttribute('disabled','disabled');
}

function array_sum(o){
  var s = 0,i;
  for(i = o.length; i >= 0; i=i-1){
    s += (isNaN(o[i])?0:o[i]);}
  return s;
}

// contenu des calculs interactifs
function majtab(){
  var oelm = document.getElementById("formulaire").elements,
    sommeRachat = 0,
    sommeMensualite = 0,
    Rachat = [parseInt(oelm.SoldePretMobilier.value,10),
    parseInt(oelm.SoldePretConsommation.value,10),
    parseInt((oelm.MontantProjet)?(oelm.MontantProjet.value):0,10),
    parseInt(oelm.SoldeDecouvert.value,10),
    parseInt((oelm.SoldeAutreDette)?(oelm.SoldeAutreDette.value):0,10),
    (parseInt((oelm.MontantApport)?(oelm.MontantApport.value):0,10) * (-1))],
    i,Revenus,Charges,Capacite,CapaciteMin,CapaciteMax,Mensualite,Ratio;

  for (i = 0; i <= Rachat.length; i=i+1){
    sommeRachat += (isNaN(Rachat[i]))?0:Rachat[i];}

  document.getElementById("calculsomme").value = sommeRachat;

  Revenus = [parseInt(oelm.SalaireEmprAnnuel.value,10)/12,
    parseInt((oelm.SalaireCoEmprAnnuel)?(oelm.SalaireCoEmprAnnuel.value):0,10)/12,
    parseInt((oelm.RevenuFoncierAnnuel)?(oelm.RevenuFoncierAnnuel.value):0,10)/12,
    parseInt((oelm.PensionAlimentaireRecuMensuel)?(oelm.PensionAlimentaireRecuMensuel.value):0,10),
    parseInt((oelm.APLMensuel)?(oelm.APLMensuel.value):0,10)];

  Charges = [parseInt((oelm.PensionAlimentaireVerseMensuel)?(oelm.PensionAlimentaireVerseMensuel.value):0,10),
    parseInt(oelm.Loyer.value,10)];

  Capacite = (isNaN(Revenus[0])?0:Revenus[0]) + (isNaN(Revenus[1])?0:Revenus[1]) + (isNaN(Revenus[3])?0:Revenus[3]) + (isNaN(Revenus[4])?0:Revenus[4]) - (isNaN(Charges[1])?0:Charges[1]);
  CapaciteMin = Math.round((Capacite + (isNaN(Revenus[2])?0:Revenus[2]*0.75) + (isNaN(Revenus[3])?0:Revenus[3])) *0.3 - (isNaN(Charges[0])?0:Charges[0]));
  CapaciteMax = Math.round((Capacite + (isNaN(Revenus[2])?0:Revenus[2]*0.85) - (isNaN(Charges[0])?0:Charges[0])) * 0.54 );

  Mensualite = [parseInt(oelm.MensualiteImmo.value,10),
    parseInt(oelm.MensualiteAutre.value,10)];

  for (i = 0; i<= Mensualite.length; i=i+1){
    sommeMensualite += (isNaN(Mensualite[i]))?0:Mensualite[i];}

  Ratio = Math.round((sommeMensualite) / (array_sum(Revenus)-array_sum(Charges)) * 100);

  document.getElementById("capmin").value = CapaciteMin;
  document.getElementById("capmax").value = CapaciteMax;
  document.getElementById("ratioendett").value = (isNaN(Ratio))?0:Ratio;
}

// sert a initialiser le formulaire
function initform(){
  var formul = document.getElementById("formulaire");
  if ((arguments.callee.done)||(!formul)){return;}

  arguments.callee.done=true;
  addElem(document.body,'','div','alerteCourante');
  addElem(document.body,'','div','calcul','');

  if (document.getElementById('servErreur')) {
    alerte("Suite à une erreur imprévue, l'assistance de saisie est désactivée. Vos données ne sont pas encore enregistrées, corrigez manuellement les valeurs indiquées.");
    return;}

  createlegende();
  createsimul();
  initvar(formul);
  ajoutBubulle(); // repetition pour les elements crees apres premiere execution
  formul.onsubmit = checkonsubmit;
  addEvent(formul,'reset',checkonreset);
  initevent(formul);

  majtab();

  addEvent(document.getElementById("ct"),'keyup',majtab);
}

// fin de la partie declaratrice de fonctions. La suite installe le trigger d'initialisation du formulaire
if(EventIE){// feu sous IE 5-7
  script.attachEvent('onreadystatechange',function() {
    if (event.srcElement.readyState === "complete") {
      initform();
    }
  });
}

if(EventW3C){// feu sous Firefox, Opera 9.2 et Safari 3
  addEvent(document,"DOMContentLoaded",initform);}

addEvent(window,"load",initform);// pour le reste...