
// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.

# include <iostream>
using namespace std;  //introduces namespace std
#include <stdlib.h>
#include "Sortie.h"
#include "UtilLecture.h"
#include "Sortie.h"

#include <fstream> 
#include <cstdlib>
#include <iomanip>
#include <algorithm>
#include "ParaGlob.h"
#include <dirent.h> // pour la gestion de l'ouverture de directory
#include <unistd.h>  // idem 
#include "CharUtil.h"

// ouverture du fichier base_info après le .info  dans le cas d'un restart par exemple
// s'il est déjà ouvert on ne fait rien
// a priori le fichier est ouvert en lecture  : lecture
// mais il peut également être en écriture : ecriture
void UtilLecture::Ouverture_base_info(string type_entree)
  { char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, pteurnom);
    // on définit des noms explicites
    std::string nom_BI(pteurnom);
    std::string nom_PI(pteurnom);
  #ifdef UTILISATION_MPI
    // cas d'un  calcul //,
    // on prend en compte le numéro du CPU
    int num_cpu = ParaGlob::Monde()->rank();
    nom_BI += ChangeEntierSTring(num_cpu);
    nom_PI += ChangeEntierSTring(num_cpu);
  #endif
    nom_BI += ".BI";
    nom_PI += ".PI";
    
    if (type_entree == "lecture")
      // cas d'une lecture
      // on regarde si on a déjà une ouverture en écriture si oui on ferme
    { if (sort_BI != NULL)
          Fermeture_base_info();
      // maintenant on regarde si la lecture est déjà en cours
     #ifdef UTILISATION_MPI
       // cas d'un  calcul //, et que l'on a une lecture en cours
       // on regarde si on a changé de CPU
       // si oui, on ferme tout
       if (ent_BI != NULL)
        {if (num_cpu_en_cours_BI != num_cpu)
           {Fermeture_base_info();
            // on met à jour le numéro en cours
            num_cpu_en_cours_BI = num_cpu;
           };
        };
     #endif

      // si pas de fichier ouvert, on ouvre
      if (ent_BI == NULL)
       { //ent_BI = new fstream(strcat(fileName,".BI"), ios::out | ios::in);
        ent_BI = new fstream(nom_BI.c_str(), ios::out | ios::in);
        if(!(ent_BI->is_open()))
         //  le fichier ne peut être ouvert, message d'erreur
         {  cout << "\n erreur en ouverture pour la lecture du fichier " << nom_BI << "\n"
                 << " UtilLecture::Ouverture_base_info() " << endl;
            Sortie(1);
         };
        // cas du fichier de pointeur, traitement presque analogue  
//        strcpy(fileName, pteurnom);
//        ent_PI = new fstream(strcat(fileName,".PI"), ios::out | ios::in);
        ent_PI = new fstream(nom_PI.c_str(), ios::out | ios::in);
        if(!(ent_PI->is_open()))
         //  le fichier ne peut être ouvert, message d'erreur
         {  cout << "\n erreur en ouverture pour la lecture du fichier " << nom_PI << "\n"
                 << " le fichier de pointeur ne peut etre lu, on essaie de faire uniquement avec le .BI " 
                 << endl;
            ent_PI = NULL;
         };
        bool positionPI = false; // pour de la gestion de cas 
        if (ent_PI!=NULL) // si le fichier n'est pas vide
         { // et on récupère les pointeurs d'incrément
           string toto;int nb_position;
           // on lit la première ligne 
           (*ent_PI) >> toto >> nb_position;
           // dans le cas ou il n'y a pas d'erreur
           // on effectue la lecture des positions si seulement
           // le nombre de position actuellement en service est différent
           if (ent_PI->rdstate() == 0)
           {// si le nombre de position actuelle est non valide, on lit
            if (liste_posi_BI.size() != nb_position)
             {  // on efface les positions actuelles
                liste_posi_BI.clear();
                // lecture des positions
                for (int i=1;i<= nb_position;i++)
                 { Position_BI truc;
                   (*ent_PI) >> truc;
                   liste_posi_BI.push_back(truc);
                 };
             };
             positionPI = true;  
           }
         }
        // si les positions n'ont pas été validé, on essaie de les recréer      
        if (!positionPI)
         // le fichier de pointeur n'est pas exploitable
         // on redéfinit par lecture le tableau de pointeur à partir du .BI
         {  cout << "\n attention, le fichier de pointeur .PI n'est pas exploitable "
                 << " \n on va donc essayer de retrouver les positions des increments "
                 << " dans .BI mais ce sera plus long !! " << endl;
            if (ent_PI != NULL) {ent_PI->close();ent_PI = NULL;};     
            // on efface les positions actuelles
            liste_posi_BI.clear();
            // on se positionne au premier incrément et si c'est ok on continue
            int incre = 0; streampos debut_increment(0);
            if (Positionnement_base_info(incre))
             { // enregistrement et bouclage
               Position_BI truc(debut_increment,incre);
               liste_posi_BI.push_back(truc);
               while (Increment_suivant_base_info(debut_increment,incre))
                { // dans la fonction il y a l'enregistrement dans la liste
                  // d'où on ne fait rien ici
                };
               // maintenant on se repositionne au début du fichier pour le BI
               ent_BI->clear();
               ent_BI->seekg(ios::beg);
               dernier_increment_lu = 0; 
               // on sauvegarde les positions pour une prochaine utilisation
//               strcpy(fileName, pteurnom);
//               sort_PI = new fstream(strcat(fileName,".PI"), ios::out | ios::in);
               sort_PI = new fstream(nom_PI.c_str(), ios::out | ios::in);
               if(!(sort_PI->is_open()))
               //  le fichier ne peut être ouvert, il n'existe pas donc on l'ouvre 
                { //sort_PI = new fstream(fileName, ios::out  | ios::ate);
                  sort_PI = new fstream(nom_PI.c_str(), ios::out | ios::in);
                  if(!(sort_PI->is_open())) 
                  //  le fichier ne peut être ouvert, message d'erreur
                  {  cout << "\n erreur en ouverture pour la lecture du fichier " << nom_PI << "\n"
                          << " UtilLecture::Ouverture_base_info() " << endl;
                     Sortie(1);
                  };
                };
               list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
               (*sort_PI) << "liste_des_positions_et_de_pointeur_dans_base_info,_taille_: " 
                          << liste_posi_BI.size() << "\n";
               for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++)
                  (*sort_PI) << (*iter) << "\n";
               (*sort_PI) << endl;
               sort_PI->close();sort_PI=NULL; 
             };
          }
       }

      }
    else if (type_entree == "ecriture")
      // cas d'une ecriture
      // on regarde si on a déjà une ouverture en lecture si oui on ferme
    { if (ent_BI != NULL)
          Fermeture_base_info();
          
    #ifdef UTILISATION_MPI
      // cas d'un  calcul //, et que l'on a une écriture en cours
      // on regarde si on a changé de CPU
      // si oui, on ferme tout
      if (sort_BI != NULL)
       {if (num_cpu_en_cours_BI != num_cpu)
          {Fermeture_base_info();
           // on met à jour le numéro en cours
           num_cpu_en_cours_BI = num_cpu;
          };
       };
    #endif
          
      // maintenant on regarde si la lecture est déjà en cours si oui on ne fait rien
      // sinon on ouvre et on se place à la fin
      if (sort_BI == NULL)
      { sort_BI = new fstream(nom_BI.c_str(), ios::out | ios::in | ios::ate);
        if(!(sort_BI->is_open()))
         //  le fichier ne peut être ouvert, il n'existe pas donc on l'ouvre 
         { sort_BI = new fstream(nom_BI.c_str(), ios::out  | ios::ate);
           if(!(sort_BI->is_open())) 
            //  le fichier ne peut être ouvert, message d'erreur
            {  cout << "\n erreur en ouverture pour la lecture du fichier " << nom_BI << "\n"
                 << " UtilLecture::Ouverture_base_info() " << endl;
               Sortie(1);
            }      
          }
        // même traitement pour le fichier de pointeur d'incrément 
        // qui est cependant systématiquement mis à 0, on écrit du début       
        sort_PI = new fstream(nom_PI.c_str(), ios::out | ios::in);
        if(!(sort_PI->is_open()))
         //  le fichier ne peut être ouvert, il n'existe pas donc on l'ouvre 
         { sort_PI = new fstream(nom_PI.c_str(), ios::out  | ios::ate);
           if(!(sort_PI->is_open())) 
            //  le fichier ne peut être ouvert, message d'erreur
            {  cout << "\n erreur en ouverture pour la lecture du fichier " << nom_PI << "\n"
                 << " UtilLecture::Ouverture_base_info() " << endl;
               Sortie(1);
            }      
          }      
       }
      }
    
    // essai
 /*   // essai
    fstream * toto;
    toto =  new fstream("toto", ios::out | ios::in ); 
	toto->clear();
    (*toto) << "truc \n";(*toto) << "tric";
    // positionnement au début du fichier
    toto->seekp(0,ios::beg);
    string titi;
    (*toto) >> titi;
    // récup de l'adresse
    streampos adresse = toto->tellp();
    // ouverture d'un stream en écriture er positionnement 
    fstream * toutou;
    toto->seekp(0,ios::beg);
    toto->close ();
    toutou =  new fstream("toto",ios::out | ios::in | ios::ate); 
    toutou->seekp(adresse);
 //   (*toutou) >> titi;
    (*toutou) << "\nfin\n";
    toutou->close(); */
   };

// fermeture du fichier base_info 
void UtilLecture::Fermeture_base_info()
  { if (ent_BI != NULL)
      {// cas du fichier ouvert en lecture
       delete ent_BI;
       ent_BI = NULL;
       if(ent_PI != NULL) delete ent_PI;
       ent_PI = NULL;
       }
    if (sort_BI != NULL)
      {// cas du fichier ouvert en écriture
       delete sort_BI;
       sort_BI = NULL;
       // on sauvegarde le tableau de pointeur d'incrément
       sort_PI->seekp( ios::beg);
       list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
       (*sort_PI) << "liste_des_positions_et_de_pointeur_dans_base_info,_taille_: " 
                  << liste_posi_BI.size() << "\n";
       for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++)
          (*sort_PI) << (*iter) << "\n";
       (*sort_PI) << endl;
       // puisque le fichier base_info est fermé, on suprime la liste de pointeur
       // elle sera remise à jour lors de l'ouverture du .BI
       list<Position_BI>::iterator iter_debut = liste_posi_BI.begin();
       liste_posi_BI.erase(iter_debut,iter_fin);
       // fermeture du fichier
       delete sort_PI;
       sort_PI = NULL;
       }
   
   };
        
//fichier base_info dans lequel sont lus les enregistrements
ifstream * UtilLecture::Ent_BI() 
  { if (ent_BI == NULL)
     { // cas ou le fichier n'est pas ouvert on l'ouvre
       Ouverture_base_info("lecture");
      }

      
      
    return (ifstream*) ent_BI; 
   };     
// et pour l'écriture
ofstream * UtilLecture::Sort_BI() 
   { if (sort_BI == NULL)
     { // cas ou le fichier n'est pas ouvert on l'ouvre
       Ouverture_base_info("ecriture");
      }
     return (ofstream*) sort_BI;
     } ;
     
// positionnement dans le fichier d'entrès au niveau d'un numéro d'incrément
// si l'on ne trouve pas le numéro on renvoi un indicateur à false
bool UtilLecture::Positionnement_base_info(int inc_voulu)
  {  streampos debut_increment(0);
     // tout d'abord on vérifie que le fichier base_info est disponible en lecture
     // sinon on l'ouvre en lecture
     if (ent_BI == NULL)
       Ouverture_base_info("lecture");
      
// --- on ne fait pas une recherche en boucle, comme commencé dans les lignes commentées qui suivent
// car on considère que la liste BI doit exister et contenir les info ha doc
//     // on regarde si l'on est au début du fichier sinon dans le cas d'une recherche
//     // infructueuse à la fin il faudra aussi faire une recherche au début
//     bool debut = true;
//     if (std::ios::beg != ( ent_BI->tellg())) debut = false;

     // on regarde si l'incrément demandé n'a pas déjà été enregistré
     Position_BI pos_ent(ios::beg,inc_voulu);
     list <Position_BI>::iterator iposi 
               = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
     if (iposi != liste_posi_BI.end())
        // dans le cas ou l'incrément existe, on se positionne à l'adresse mémorisée
        {ent_BI->clear(); // on remet à 0 les bits de contrôle car si lors d'une précédente lecture
                          // on est par exemple arrivée à la fin du fichier, la fonction seekg ne fonctionnera
                          // pas !! car le bit de eof est activé 
         ent_BI->seekg((*iposi).position, ios::beg);
        };

     // maintenant on lit 
     string toto; int titi; int inc; bool inc_trouve = false;
     // def d'un tableau d'entrée en flot d'entrée pour faire de la lecture non formaté
     char * tableau; int longueur =  250;
     tableau = new char [longueur] ; // def du tableau intermediaire
     istrstream * intar;
     // on définit une position intermédiaire dans le fichier pour bien se positionner 
     // pour l'écriture ensuite éventuelle des incréments
     streampos position_inter=0;        
     // lecture tant que l'on n'a pas atteint la fin du fichier
     do
       { // tout d'abord on mémorise l'ancienne position et on récupère la nouvelle
         debut_increment = position_inter;
         position_inter = ent_BI->tellg();
         // si la ligne est la bonne debut_increment sera positionné sur le début
         // de la ligne qui contiend des ====
              
         ent_BI->getline(tableau,longueur,'\n'); // lecture d'une ligne dans le fichier
         if (strstr(tableau,"INCREMENT_DE_CHARGE_:")!=NULL)
           { // on repositionne le flot au debut du tableau de carractere  
             // ouverture du flot a la longueur sans blanc
             intar = new istrstream(tableau,short(strlen (tableau))) ;
             (*intar) >> toto >> inc;
             if (inc == inc_voulu)
               // ok on a l'incrément voulu
               // fin de la préparation de la lecture pour l'incrément 
               {(*intar)  >> toto >> titi
                          >> toto ; 
                 inc_trouve = true;
                }
              delete intar;  
             }
          // test pour vérifier l'intégrité du flot
          if (ent_BI->rdstate() != 0)
            // si l'on est arrivé  à la fin du fichier il n'y a rien à faire
            // sinon on remet à flot le flot (cas par exemple d'entier au lieu de caractère)!
            if (!(ent_BI->eof()))
                ent_BI->clear();
         }                 
         while ((!(ent_BI->eof()))&& (!inc_trouve));
       delete[] tableau;
      
	   if (!inc_trouve)
	       return false;
	   else 
	     { // on passe la ligne des ===
	       (*ent_BI) >> toto; 
	       // on met à jour la variable dernier_increment_lu
	       dernier_increment_lu = inc_voulu;
        return true;
      };
};
    
// positionnement dans le fichier d'entrès au niveau du numéro d'incrément suivant
// si l'on ne trouve pas de numéro on renvoi un indicateur à false
// la méthode renvoie également la position du début de l'incrément
// et le numéro trouvé d'incrément
bool UtilLecture::Increment_suivant_base_info(streampos& debut_increment,int& inc_lu)
  {  // tout d'abord on vérifie que le fichier base_info est disponible en lecture
     // sinon on l'ouvre en lecture
     if (ent_BI == NULL)
       Ouverture_base_info("lecture");
     // on regarde si dans la liste des incréments enregistrés, la position du suivant 
     // s'il existe
     Position_BI pos_int(ios::beg,dernier_increment_lu);
     list <Position_BI>::iterator iposi 
               = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_int);
     // iposi représente la position du dernier incrément enregistré          
     if (iposi != liste_posi_BI.end())
      // cas ou l'incrément existe, on prend le suivant
      {list <Position_BI>::iterator iposa = iposi; // sauvegarde
       iposi++;
       // on vérifie qu'il existe et dans ce cas on se positionne correctement
       if (iposi != liste_posi_BI.end())
          ent_BI->seekg((*iposi).position, ios::beg);
       else
          // sinon on se met à la dernière position
          ent_BI->seekg((*iposa).position, ios::beg);
       }
     else
       // si c'était le dernier enregistré on se met à la dernière position
       // au cas ou le fichier de pointeur n'est pas complet
       ent_BI->seekg(pos_int.position, ios::beg);
     // maintenant on lit 
     string toto;   bool inc_trouve = false;
     // def d'un tableau d'entrée en flot d'entrée pour faire de la lecture non formaté
     char * tableau; int longueur =  250;
     tableau = new char [longueur] ; // def du tableau intermediaire
     istrstream * intar;
     // on définit une position intermédiaire dans le fichier pour bien se positionner 
     // pour l'écriture ensuite éventuelle des incréments
     streampos position_inter=0;        
     // lecture tant que l'on n'a pas atteint la fin du fichier
     do
       { // tout d'abord on mémorise l'ancienne position et on récupère la nouvelle
         debut_increment = position_inter;
         position_inter = ent_BI->tellg();
         // si la ligne est la bonne debut_increment sera positionné sur le début
         // de la ligne qui contiend des ====
              
         ent_BI->getline(tableau,longueur,'\n'); // lecture d'une ligne dans le fichier
         if (strstr(tableau,"INCREMENT_DE_CHARGE_:")!=NULL)
           { // on repositionne le flot au debut du tableau de carractere  
             // ouverture du flot a la longueur sans blanc
             intar = new istrstream(tableau,short(strlen (tableau))) ;
             (*intar) >> toto >> inc_lu;
             // le nouvel incrément n'est valide que s'il est différent de l'ancien
             if (inc_lu != dernier_increment_lu)
               inc_trouve = true;
             delete intar;  
             }
          // test pour vérifier l'intégrité du flot
          if (ent_BI->rdstate() != 0)
            // si l'on est arrivé  à la fin du fichier il n'y a rien à faire
            // sinon on remet à flot le flot (cas par exemple d'entier au lieu de caractère)!
            if (!(ent_BI->eof()))
                ent_BI->clear();
         }                 
         while ((!(ent_BI->eof()))&& (!inc_trouve));
     delete[] tableau;
     // dans le cas où on n'a pas trouvé de bon incrément       
	 if (!inc_trouve)
	       { inc_lu = -1;
	         return false;
	        } 
	 else 
	     { // on passe la ligne des ===
	       (*ent_BI) >> toto;
	       // on enregistre la position dans la liste de position
        // on regarde si l'incrément demandé n'a pas déjà été enregistré
        Position_BI pos_ent(debut_increment,inc_lu);
        list <Position_BI>::iterator iposi_end = liste_posi_BI.end();
        list <Position_BI>::iterator iposi
            = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
        if (iposi == liste_posi_BI.end())
          {// le nouvel incrément n'existait pas mais
           // éventuellement le nouvel incrément peut-être intercalé entre des anciens
           // -- on ré-ordonne la liste, qui normalement ne doit avoir que des singletons
           liste_posi_BI.sort();
           iposi_end = liste_posi_BI.end(); // au cas où
           // -- on regarde si effectivement on est intercalé
           if ((* liste_posi_BI.begin() < (*iposi)  ) && ((*iposi) < (*iposi_end )))
            {// on recherche l'encadrement ad hoc
             list <Position_BI>::iterator ipopo;
             for (ipopo = liste_posi_BI.begin(); ipopo != iposi_end; ipopo++)
               if ((* ipopo) > (*iposi))
                 break;
             if (ipopo != liste_posi_BI.end())
              {// dans le cas où la position existe déjà on efface le reste de la liste
               // qui est maintenant inutile
               liste_posi_BI.erase(ipopo,liste_posi_BI.end());
              };
            };
           liste_posi_BI.push_back(pos_ent);
//           // on ré-ordonne la liste, qui normalement ne doit avoir que des singletons
//           liste_posi_BI.sort(); // normalement ne sert à rien
          };
        // on met à jour la variable dernier_increment_lu
        dernier_increment_lu = inc_lu;  
        // retour  
        return true;
      };
           
};
    
// enregistrement de la position 
// normalement correspond à un début d'incrément
void UtilLecture::Enregistrement_position_increment_base_info(int incr)
 { // récup de la position
   streampos position_inter=0;        
   position_inter = sort_BI->tellp();
   // on enregistre la position dans la liste de position
   // on regarde si l'incrément demandé n'a pas déjà été enregistré
   Position_BI pos_ent(position_inter,incr);
   list <Position_BI>::iterator iposi 
               = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
   if (iposi != liste_posi_BI.end())            
     {// dans le cas où la position existe déjà on efface le reste de la liste
      // qui est maintenant inutile
      liste_posi_BI.erase(iposi,liste_posi_BI.end());
      };
   // on écrit la nouvelle position
   liste_posi_BI.push_back(pos_ent);
  };

// renvoi tous les incréments actuellements enregistré
list <int>  UtilLecture::Liste_increment()
  {  // création de la liste de retour
     list<int> list_incr;
     // on parcourt la liste des positions d'incréments
     // et on remplit la liste des numéros d'incréments
     list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
     for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++)
          list_incr.push_back((*iter).num_incr);
     // retour
     return list_incr;
    };        

  // -------------- cas des temps de calcul ----------------
     // ouverture du fichier spécifique des temps cpu
void UtilLecture::Ouverture_fichier_temps_cpu()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort__temps_cpu != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    
    // on définit des noms explicites
    std::string nom_CPU(ptnomCVisu);
  #ifdef UTILISATION_MPI
    // cas d'un  calcul //,
    // on prend en compte le numéro du CPU
    int num_cpu = ParaGlob::Monde()->rank();
    nom_CPU += ChangeEntierSTring(num_cpu);
  #endif
    nom_CPU += "_temps.cpu";
    
    sort__temps_cpu = new ofstream(nom_CPU.c_str());
    if(!(sort__temps_cpu->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_CPU << "\n"
             << " UtilLecture::Ouverture_fichier_temps_cpu() " << endl;
        Sortie(1);
     };
 };
     // fermeture du fichier des temps cpu
void UtilLecture::Fermeture_fichier_temps_cpu()
  { if (sort__temps_cpu != NULL)
      { delete(sort__temps_cpu);
        sort__temps_cpu = NULL;
      };
  };

  // -------------- cas de la visualisation ----------------
    //        +++ vrml ++++_____________________________________  
// ouverture du fichier principal vrml
void UtilLecture::Ouverture_fichier_principal_vrml()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_princ_vrml != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_princ_vrml = new ofstream(strcat(fileName,"_princ.wrl"));
    if(!(sort_princ_vrml->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_principal_vrml() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier principal vrml
void UtilLecture::Fermeture_fichier_principal_vrml()
  { if (sort_princ_vrml != NULL) 
      { delete(sort_princ_vrml);
        sort_princ_vrml = NULL;
        }
    };    
// ouverture du fichier de légendes vrml
void UtilLecture::Ouverture_fichier_legende_vrml()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_legende_vrml != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_legende_vrml = new ofstream(strcat(fileName,"_legende.wrl"));
    if(!(sort_legende_vrml->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_legende_vrml() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier légendes vrml
void UtilLecture::Fermeture_fichier_legende_vrml()
  { if (sort_legende_vrml != NULL) 
      { delete(sort_legende_vrml);
        sort_legende_vrml = NULL;
        }
    };    
    //        +++ maple ++++ ____________________________________________
// ouverture du fichier maple
void UtilLecture::Ouverture_fichier_principal_maple()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_princ_maple != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_princ_maple = new ofstream(strcat(fileName,"_princ.maple"));
    if(!(sort_princ_maple->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_principal_maple() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier principal maple
void UtilLecture::Fermeture_fichier_principal_maple()
  { if (sort_princ_maple != NULL) 
      { delete(sort_princ_maple);
        sort_princ_maple = NULL;
        }
    };    
    //        +++ geomview ++++_____________________________________  
// ouverture du fichier principal geomview
void UtilLecture::Ouverture_fichier_principal_geomview()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_princ_geomview != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_princ_geomview = new ofstream(strcat(fileName,"_princ.oogl"));
    if(!(sort_princ_geomview->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_principal_geomview() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier principal geomview
void UtilLecture::Fermeture_fichier_principal_geomview()
  { if (sort_princ_geomview != NULL) 
      { delete(sort_princ_geomview);
        sort_princ_geomview = NULL;
        }
    };    
// ouverture du fichier de légendes geomview
void UtilLecture::Ouverture_fichier_legende_geomview()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_legende_geomview != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_legende_geomview = new ofstream(strcat(fileName,"_legende.oogl"));
    if(!(sort_legende_geomview->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_legende_geomview() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier légendes geomview
void UtilLecture::Fermeture_fichier_legende_geomview()
  { if (sort_legende_geomview != NULL) 
      { delete(sort_legende_geomview);
        sort_legende_geomview = NULL;
        }
    }; 
       
    //        +++ Gid ++++_____________________________________  
// ouverture du fichier maillage initial Gid
void UtilLecture::Ouverture_fichier_initial_Gid()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_initial_Gid != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_initial_Gid = new ofstream(strcat(fileName,"_Gid.msh"));
    if(!(sort_initial_Gid->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_initial_Gid() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier maillage initial Gid
void UtilLecture::Fermeture_fichier_initial_Gid()
  { if (sort_initial_Gid != NULL) 
      { delete(sort_initial_Gid);
        sort_initial_Gid = NULL;
        }
    };    
          
// ouverture du fichier maillage initial Gid
void UtilLecture::Ouverture_fichier_resultat_Gid()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_resultat_Gid != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_resultat_Gid = new ofstream(strcat(fileName,"_Gid.res"));
    if(!(sort_resultat_Gid->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_resultat_Gid() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier maillage initial Gid
void UtilLecture::Fermeture_fichier_resultat_Gid()
  { if (sort_resultat_Gid != NULL) 
      { delete(sort_resultat_Gid);
        sort_resultat_Gid = NULL;
        }
    };    
          
       
    //        +++ Gmsh ++++_____________________________________  
// ouverture du fichier maillage initial Gmsh
void UtilLecture::Ouverture_fichier_initial_Gmsh()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_initial_Gmsh != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_initial_Gmsh = new ofstream(strcat(fileName,"_Gmsh.msh"));
    if(!(sort_initial_Gmsh->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_initial_Gmsh() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier maillage initial Gmsh
void UtilLecture::Fermeture_fichier_initial_Gmsh()
  { if (sort_initial_Gmsh != NULL) 
      { delete(sort_initial_Gmsh);
        sort_initial_Gmsh = NULL;
        }
    };    
// création du répertoire contenant tous les fichiers résultats
void UtilLecture::CreationRepertoireResultat()
 {  // création du nom
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
//    system(strcat(fileName,"_Gmsh"));  // fonctionne mais on ne peut pas savoir
//     si le répertoire existe déjà, on utilise donc opendir (mais qui n'est pas 
//     présent partout !!
    DIR * ouvre_dir = opendir(strcat(fileName,"_Gmsh"));
    if(ouvre_dir == NULL)
     { // la première fois cela veut dire que le répertoire n'existe pas on le crée avec
       // un ordre système
      // int toto = mkdir(fileName, 775);
       char ordre[132];
       char* pordre  = ordre;
       strcpy(pordre, "mkdir ");strcat(pordre,fileName);
       system(pordre); 
       // et on retente une ouverture
       ouvre_dir = opendir(fileName);		
     };
    // maintenant s'il y a pb, c'est vraiment un pb
    if(ouvre_dir == NULL)
      //  le répertoire ne peut être créé, message d'erreur
     {  cout << "\n erreur en creation du repertoire  " << fileName << "\n"
             << " UtilLecture::CreationRepertoireResultat(.. " << endl;
        Sortie(1);
      }    
	};
          
// ouverture d'un fichier résultat Gmsh, comprenant un nom particulier
void UtilLecture::Ouverture_fichier_resultat_Gmsh(const string& nom)
 {   // on commence par voir si le fichier existe déjà
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier existe déjà on ne fait rien          
     if (ili == sort_resultat_Gmsh.end())
   	   {// --- cas où le fichier n'existe pas 
        // on construit le nom de fichier
        char nomm[132];
        char*fileName  = nomm;
        strcpy(fileName, ptnomCVisu);
        strcat(fileName,"_Gmsh/"); // là il contient la racine du répertoire
        strcat(fileName,ptnomCVisu); // on rajoute le début du nom du fichier
        strcat(fileName,"_"); // on rajoute un séparateur
        strcat(fileName,nom.c_str()); // on rajoute le nom passé en paramètre
        strcat(fileName,"_Gmsh.pos"); // ajout de la fin
        noms_base_fichiers_gmsh.push_back(nom);
        sort_resultat_Gmsh[nom] = new ofstream(fileName);
        if (ParaGlob::NiveauImpression()> 7)
          cout << "\n ouverture du fichier "<< fileName << endl;
        if(!(sort_resultat_Gmsh[nom]->is_open()))
          //  le fichier ne peut être ouvert, message d'erreur
          {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
                  << " UtilLecture::Ouverture_fichier_resultat_Gmsh(list <string>) " << endl;
             Sortie(1);
          };
   	   };
  };
  
// ouverture d'un ensemble de fichiers: ces fichiers seront ensuite accessibles
void UtilLecture::Ouverture_fichier_resultat_Gmsh(const list <string>& t_nom)
{ // on va itérer sur les noms
  list <string>::const_iterator iti,itifin=t_nom.end();
  for (iti=t_nom.begin();iti != itifin; iti++)
   { const string & nom = (*iti); // pour simplifier
     // on commence par voir si le fichier existe déjà
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier existe déjà on ne fait rien          
     if (ili == sort_resultat_Gmsh.end())
   	   {// --- cas où le fichier n'existe pas 
        // on construit le nom de fichier
        char nomm[132];
        char*fileName  = nomm;
        strcpy(fileName, ptnomCVisu);
        strcat(fileName,"_Gmsh/"); // là il contient la racine du répertoire
        strcat(fileName,ptnomCVisu); // on rajoute le début du nom du fichier
        strcat(fileName,"_"); // on rajoute un séparateur
        strcat(fileName,nom.c_str()); // on rajoute le nom passé en paramètre
        strcat(fileName,"_Gmsh.pos"); // ajout de la fin
        noms_base_fichiers_gmsh.push_back(nom);
        sort_resultat_Gmsh[nom] = new ofstream(fileName);
        if (ParaGlob::NiveauImpression()> 7)
          cout << "\n ouverture du fichier "<< fileName << endl;
        if(!(sort_resultat_Gmsh[nom]->is_open()))
          //  le fichier ne peut être ouvert, message d'erreur
          {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
                  << " UtilLecture::Ouverture_fichier_resultat_Gmsh(list <string>) " << endl;
             Sortie(1);
          };
   	   };
   }; 
};
  
// fermeture du fichier résultat Gmsh  
void UtilLecture::Fermeture_fichier_resultat_Gmsh(const string& nom)
  {  // on commence par voir si le fichier existe 
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier n'existe pas on ne fait rien
     // mais on sort un message          
     if (ili == sort_resultat_Gmsh.end())
  	  { cout << "\n erreur en fermeture du fichier relatif au nom " << nom 
  	         << " ce fichier n'existe pas ??? , on continue mais ...."
  	         << "\n UtilLecture::Fermeture_fichier_resultat_Gmsh(string nom)";
  	  }
  	 else// sinon fct normal 
      { delete(ili->second);
  	     sort_resultat_Gmsh.erase(ili);
        // suppression du nom de la liste
        noms_base_fichiers_gmsh.remove(nom);
      };
  }; 
     
// fermeture de tous les fichiers résultat
void UtilLecture::Fermeture_TousLesFichiersResultats_Gmsh()
  {  map < string, ofstream * , std::less <string> >::iterator ili,ilifin 
                     = sort_resultat_Gmsh.end();
     for (ili=sort_resultat_Gmsh.begin();ili != ilifin;ili++)
        { delete(ili->second);
         };
     sort_resultat_Gmsh.erase(sort_resultat_Gmsh.begin(),sort_resultat_Gmsh.end());
     noms_base_fichiers_gmsh.clear();
  };
  
// récupération d'un fichier résultats Gmsh
ofstream & UtilLecture::Sort_resultat_Gmsh(const string& nom)
  {  
   #ifdef MISE_AU_POINT
     // on commence par voir si le fichier existe 
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier n'existe pas on  sort un message          
     if (ili == sort_resultat_Gmsh.end())
  	  { cout << "\n erreur en recuperation du fichier relatif au nom " << nom 
  	         << " ce fichier n'existe pas ??? "
  	         << "\n UtilLecture::Sort_resultat_Gmsh(string nom)";
  	    Sortie(1);
  	    return *(sort_resultat_Gmsh[nom]); // pour faire taire le compilo     
  	  }
  	 else// sinon fct normal 
   #endif
      { return *(sort_resultat_Gmsh[nom]);
      };
  }; 
          
// ouverture du fichier CommandeVisu s'il est déjà ouvert on ne fait rien
// a priori le fichier est ouvert en lecture  : lecture
// mais il peut également être en écriture : ecriture
void UtilLecture::Ouverture_CommandeVisu(string type_entree)
  { char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    if (type_entree == "lecture")
      // cas d'une lecture
      // on regarde si on a déjà une ouverture en écriture si oui on ferme
    { if (sort_CommandeVisu != NULL)
          Fermeture_CommandeVisu();
      // maintenant on regarde si la lecture est déjà en cours si oui on ne fait rien
      // si le flot est correcte, sinon on ouvre
      if (ent_CommandeVisu == NULL)
      { ent_CommandeVisu = new fstream(strcat(fileName,".CVisu"), ios::out | ios::in);
        if(!(ent_CommandeVisu->is_open()))
         //  le fichier ne peut être ouvert, message d'erreur
         {  cout << "\n erreur en ouverture pour la lecture du fichier " << fileName << "\n"
                 << " UtilLecture::Ouverture_CommandeVisu() " << endl;
            throw (ErrNouvelleDonneeCVisu(0)); // erreur en ouverture fichier pour la lecture
            Sortie(1);
          }
       }
      else if ( ent_CommandeVisu->rdstate() != 0) // pb éventuelle on redémarre le flux     
       {Fermeture_CommandeVisu();       
        ent_CommandeVisu = new fstream(strcat(fileName,".CVisu"), ios::out | ios::in);
        if(!(ent_CommandeVisu->is_open()))
         //  le fichier ne peut être ouvert, message d'erreur
         {  cout << "\n erreur2 en ouverture pour la lecture du fichier " << fileName << "\n"
                 << " UtilLecture::Ouverture_CommandeVisu() " << endl;
            throw (ErrNouvelleDonneeCVisu(0)); // erreur en ouverture fichier pour la lecture
            Sortie(1);
          }
       }
      }
    else if (type_entree == "ecriture")
      // cas d'une ecriture
      // on regarde si on a déjà une ouverture en lecture si oui on ferme
    { if (ent_CommandeVisu != NULL)
          Fermeture_CommandeVisu();
      // maintenant on regarde si la lecture est déjà en cours si oui on ne fait rien
      // sinon on ouvre et on se place à la fin
      if (sort_CommandeVisu == NULL)
      { sort_CommandeVisu = new fstream(strcat(fileName,".CVisu"), ios::out | ios::in );
        if(!(sort_CommandeVisu->is_open()))
         //  le fichier ne peut être ouvert, il n'existe pas donc on l'ouvre 
         { sort_CommandeVisu = new fstream(fileName, ios::out  | ios::ate);
           if(!(sort_CommandeVisu->is_open())) 
            //  le fichier ne peut être ouvert, message d'erreur
            {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
                 << " UtilLecture::Ouverture_CommandeVisu() " << endl;
               throw (ErrNouvelleDonneeCVisu(10)); // erreur en ouverture fichier pour l'écriture
               Sortie(1);
            };      
         };
      };
    }; //-- fin du cas écriture
    
   };
          
// fermeture du fichier CommandeVisu 
void UtilLecture::Fermeture_CommandeVisu()
  { if (ent_CommandeVisu != NULL)
      {// cas du fichier ouvert en lecture
       delete ent_CommandeVisu;
       ent_CommandeVisu = NULL;
       }
    if (sort_CommandeVisu != NULL)
      {// cas du fichier ouvert en écriture
       delete sort_CommandeVisu;
       sort_CommandeVisu = NULL;
       }   
   };
   
// changement du nom de fichier .CVisu
// entraîne la fermeture du fichier en cours, en lecture et en écriture
// il n'y a pas de vérification à ce niveau d'existence éventuelle
// car on ne sait pas ce que l'on veut en faire
void UtilLecture::Changement_NomCVisu(string nouveauNomCvisu)
	{ // on commence par fermer le fichier en cours
	  Fermeture_CommandeVisu();
	  
	  // maintenant on regarde si la chaine passée en paramètre est non nulle
	  if (nouveauNomCvisu != "")
	    // on définit directement le nouveau nom
	  	{nomRacineCVisu = nouveauNomCvisu;}
	  else // sinon on passe en interactif
	  	{ cout << "\n entrez le nouveau nom:  ";
	      string nom;
	      nom= lect_chaine();
	      cout << " nom_lue: " << nom;
	      // dans le cas où ".CVisu" figure dans la racine, on supprime cette chaine
          int posi = nomRacine.find(".CVisu");
          if (posi != string::npos)
             { string nom_inter = nomRacine.substr(0,posi);
			   nom = nom_inter;
              };
          nomRacineCVisu = nom;
	  	};	
      // on met à jour le pointeur      
      ptnomCVisu = (char*)nomRacineCVisu.c_str(); 
	};
            
// lecture d'une nouvelle ligne de donnee utilisable pour l'entree de donnee
// dans le fichier de commande de visualisation (idem NouvelleDonnee mais en plus simple
// car il n'y a pas de fichier inclus) 
void UtilLecture::NouvelleDonneeCVisu()
   { // on lit jusqu'à la fin de fichier(boucle infini)
//     int boucle=0;
     try  
        { 
               Nouvel_enregCvisu (); // lecture d'un enreg ds le fichier courant
               // on repositionne le flot au debut du tableau de carractere  
               // ouverture du flot a la longueur sans blanc
               delete entCVisu;  
               #ifndef ENLINUX_STREAM
                   entCVisu = new istringstream(tablcarCVisu,strlen (tablcarCVisu)) ; 
               #else 
                   entCVisu = new istrstream(tablcarCVisu,(long)strlen (tablcarCVisu)) ;
               #endif    
              
          }    
     // sortie anormale du programme  
     catch (ErrNouvelEnregCVisu erreur)
         {  if ( erreur.lecture == 1) // on a atteind une fin de fichier
                    throw (ErrNouvelleDonneeCVisu(1)); 
            else
                   throw (ErrNouvelleDonneeCVisu(-1)); // erreur inconnue
         }    
  };
  
// recherche dans le fichier de commande la chaine de caractère passée en paramètre
// retour false: si on ne trouve pas la chaine
// retour true: si on la trouve, et dans ce cas le pointeur courant du fichier est 
//              positionné sur la ligne de la chaine
bool UtilLecture::PositionEtExisteCVisu(const string chaine)
 { // on ouvre le fichier en lecture si ce n'est pas fait
   try{
      Ouverture_CommandeVisu("lecture");
      // on commence par se positionner en début du fichier
      ent_CommandeVisu->seekg(ios::beg);   
      // on effectue la lecture jusqu'à trouver la chaine
      while (strstr(tablcarCVisu,chaine.c_str())==NULL)
          NouvelleDonneeCVisu();          
      // arrêt, on a trouvé la chaine et on est bien positionné
      return true; 
     }
   // sortie  de la lecture  hors du while
   catch (UtilLecture::ErrNouvelleDonneeCVisu erreur)
         {  if ( erreur.lecture != 1) 
              { // erreur en lecture
                cout << "\n **** ERREUR en lecture du fichier de  commande de visualisation "
                     << "\n on continue quand meme, mais il y aura peut-etre un probleme de coherence pour la suite";
                if (ParaGlob::NiveauImpression() >= 4)     
                  cout  << "\n UtilLecture::PositionEtExisteCVisu(..";
               }      
         }    
   catch (ErrSortieFinale)
        // cas d'une direction voulue vers la sortie
        // on relance l'interuption pour le niveau supérieur
      { ErrSortieFinale toto;
        throw (toto);
      }
   catch (...)// erreur inconnue
      {  cout << "\n **** ERREUR inconnuee en lecture du fichier de  commande de visualisation "
              << "\n on continue quand meme, mais il y aura peut-etre un probleme de coherence pour la suite";
         if (ParaGlob::NiveauImpression() >= 4)     
             cout  << "\n 2 UtilLecture::PositionEtExisteCVisu(..";
        }      
   // quelque soit la cause, on n'a pas trouvé la chaine
   return false;    
  };
   
//fichier CommandeVisu dans lequel sont lus les enregistrements
// en lecture directe
ifstream * UtilLecture::Ent_CommandeVisu() 
  { if (ent_CommandeVisu == NULL)
     { // cas ou le fichier n'est pas ouvert on l'ouvre
       Ouverture_CommandeVisu("lecture");
      }
    return (ifstream*) ent_CommandeVisu; 
   };     
         
 //------------ utilitaire de lecture d'un parametre précédé d'un mot clé, avec une restriction
 // sur les valeurs
 // lecture_effective: indique si oui ou non il y a eu lecture
 // val_defaut: si la grandeur n'est pas lue, elle est mise par défaut = val_defaut
 // nom_class_methode: le nom de la methode qui appel l'utilitaire -> sortie dans le  message si pb
 // min max : les bornes entre lesquelles doit se trouver le parametre lue sinon -> génération d'une erreur et arrêt
 //           si max < min alors la condition n'est pas prise en compte
 // mot_cle : mot_cle devant précéder le parametre
 // parametre: le parametre à lire
 // retourne le parametre lue ou la valeur par défaut
 bool UtilLecture::Lecture_un_parametre_int(int val_defaut,const string& nom_class_methode
								                   ,int min, int max, string& mot_cle, int& parametre ) const
   {  string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du parametre "<< mot_cle
                  << "\n on attendait la chaine " << mot_cle << " au lieu de: " << nom
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
         //sinon c'est ok
         *(entree) >> parametre;
			      if (max > min)
          {if ((parametre < min ) || (parametre > max )) 
           { cout << "\n erreur en lecture du parametre " << mot_cle
                  << "\n pour l'instant seuls les types " << min << " a " << max << " sont implantes, valeur lue:  " << parametre
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
			       };
         lecture_effective = true;
       }
      else // sinon on met la valeur par défaut
        { parametre  = val_defaut;};
		    // retour
		    return lecture_effective;
   };

 // idem pour un double										 
 bool UtilLecture::Lecture_un_parametre_double(double val_defaut,const string& nom_class_methode
									                     ,double min, double max,const string& mot_cle, double& parametre ) const
    { string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du parametre "<< mot_cle
                  << "\n on attendait la chaine " << mot_cle << " au lieu de: " << nom
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
         //sinon c'est ok
         *(entree) >> parametre;
			      if (max > min)
          {if ((parametre < min ) || (parametre > max )) 
           { cout << "\n erreur en lecture du parametre " << mot_cle
                  << "\n pour l'instant seuls les types " << min << " a " << max << " sont implantes, valeur lue:  " << parametre
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
			       };
         lecture_effective = true;
       }
      else // sinon on met la valeur par défaut
        { parametre  = val_defaut;};
		    // retour
		    return lecture_effective;
    };

// lecture et passage d'un mot clé: il y a simplement vérification que c'est le bon mot clé qui est lue
// ramène si oui ou non le mot clé à été lue
bool UtilLecture::Lecture_et_verif_mot_cle(const string& nom_class_methode,const string& mot_cle) const
   {  string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du mot cle "<< mot_cle
                  << "\n on a lue  " << nom
                  << nom_class_methode << "( ... ";
             Sortie(1);
           };
         //sinon c'est ok
         lecture_effective = true;
       }
      else // sinon problème
       { cout << "\n erreur en lecture du mot cle "<< mot_cle
              << "\n il n'existe pas sur la ligne  " << tablcar
              << nom_class_methode << "( ... ";
         Sortie(1);
       };
		    // retour
		    return lecture_effective;
   };

// idem pour un mot clé et un string: nom
bool UtilLecture::Lecture_mot_cle_et_string(const string& nom_class_methode,const string& mot_cle,string& nom_ret) const
   {  string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du mot cle "<< mot_cle
                  << "\n on a lue  " << nom
                  << nom_class_methode << "( ... ";
             Sortie(1);
           };
         //sinon c'est ok
         lecture_effective = true;
       }
      else // sinon problème
       { cout << "\n erreur en lecture du mot cle "<< mot_cle
              << "\n il n'existe pas sur la ligne  " << tablcar
              << nom_class_methode << "( ... ";
         Sortie(1);
       };
      // puis lecture du string
      *(entree) >> nom_ret;
		    // retour
		    return lecture_effective;
   };

// ------------------------------- méthodes protégées ---------------------------------
        
//fichier CommandeVisu dans lequel sont lus les enregistrements
//  en écriture
ofstream * UtilLecture::Sort_CommandeVisu() 
   { if (sort_CommandeVisu == NULL)
       { // cas ou le fichier n'est pas ouvert on l'ouvre
         Ouverture_CommandeVisu("ecriture");
        }
     return (ofstream*) sort_CommandeVisu;
   } ;
