
// 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 <fstream>
//#ifdef SYSTEM_MAC_OS_X
//  #include <stringfwd.h> // a priori ce n'est pas portable
//#el
#if defined  SYSTEM_MAC_OS_CARBON
  #include <stringfwd.h> // a priori ce n'est pas portable
#else  
  #include <string.h> // pour le flot en memoire centrale
#endif
#include <string>

//#include "Debug.h"
#ifndef ENLINUX_STREAM
  #include <ios>
#else  
  #include <iostream>
  #include <strstream>
#endif

#include "UtilLecture.h"
        using namespace std;
        // 
//         ----- routine de la classe UtilLecture -------
//  
// routine pour acquerir un nouvel enregistrement et
// passer les commentaires dans les fichiers d'entree d'herezh
// Un commentaire se trouve apres le symbole #
// une ligne est consideree comme non_commentaire si elle possede au moins un carractere non
// identique a l'espace avant le carractere #
// dans le cas ou il y a une erreur de lecture ou que la fin de fichier est ateinte
// le programme genere une exception de tye : errNouvelEnreg, =1 -> fin de fichier
// = -1 autre probleme de lecture 

void   UtilLecture::Nouvel_enreg()
  {                   
  
    char delim = '\n'; // fin de ligne utilise
    int nouvelleligne = 0; /* initialisation de l'indicateur pour sortie de 
               la boucle de recherche, quand = 1 on a trouve une ligne interessante */
               
    char* fin = NULL ; // position du carractere #
	   char* lienLigne = NULL; // position éventuelle d'un caractère \ de continuation de ligne unix
	   bool suiteLigne = false; // indique si oui ou non la ligne lue se continue
	   char* finReturn = NULL; // position éventuelle d'un caractère \r (cariage return)
 
    ifstream & fichier = *ptrfich; 
	   tabMultiLignes[0] = '\0'; // on met à 0 le tableau de stockage de plusieurs lignes  
  
    do  // on test jusqu'a une ligne interessante
     { suiteLigne=false;                
       fichier.getline(tableau,longueur,delim); // lecture d'une ligne dans le fichier
       // reta = -1 s'il y a eu un pb qui fait qu'aucune lecture viable n'a été faite
       (maille1->numLigne)++; // incrementation du numero de ligne

/*//   -- debug
if (fichier.eof() && (reta != -1) )
  cout << "\n ** debug UtilLecture::Nouvel_enreg() "
       << " fichier.rdstate()= "<< fichier.rdstate() << endl;
*/// --  fin  debug

       // ---- traitement d'un cas particulier que je ne vois pas comment traiter autrement
       int long_ligne = 0; // une longeur de ligne intermédiaire, ne sert que pour le test plus bas
       if ( (fichier.rdstate() != 6) && fichier.eof()) // on a atteind la fin de ligne,
            long_ligne = (int) strlen (tableau);  // mais on a lue quelque chose

      
       /* pour mémoire: 
             enum io_state
                    {  badbit   = 1<<0, // -> 1 dans rdstate()
                       eofbit   = 1<<1, // -> 2 
                       failbit  = 1<<2, // -> 4
                       goodbit  = 0     // -> O
                     };
          rdstate() == 6 cela signifie eofbit + failbit
       */
       // test de l'etat du flux d'entree
       if ((  fichier.rdstate() == 0 ) // cas normal
           || (long_ligne > 0 )  // cas où on a quand même lue quelque chose
          )                      // car reta != -1, mais que l'on a atteind la fin de ligne
        {
          int finLigne = (int) strlen (tableau); // longueur de la ligne (surabondant / à
                    // long_ligne mais on garde pour ne pas mélanger
          if ( finLigne > 0 ) 
           { // cas d'une ligne non vide
             fin = strchr(tableau,'#');  // position du debut de commentaire s'il existe
             finReturn = strchr(tableau,'\r');  // position d'un "cariage return" s'il existe
				         if (finReturn != NULL)
              { // on supprime le caractère pour pas que cela pose des pb par la suite 
					           *finReturn = '\0'; 
					         };
             lienLigne = strchr(tableau,'\\');  // position du caractère de continuation de ligne
				  
				         if ( (lienLigne != NULL) &&									// on n'intervient que s'il y a un caractère de continuation
				              ( ((fin != NULL) && (lienLigne < fin))  // si le caractère de continuation est après un #, on n'en tient pas compte
							             ||  (fin == NULL)                         // sinon on en tiens compte
                  )
						          )		
				          { // on supprime le caractère pour pas que cela pose des pb par la suite mais on sait avec lienLigne que
					           // la ligne continue
					           *lienLigne = '\0'; suiteLigne = true;
					           //cout << "\n on a trouvé un antislash !! ";
					           //Sortie(1);
					         }
				         else if ( (lienLigne != NULL) &&									// on n'intervient que s'il y a un caractère de continuation
				                   ((fin != NULL) && (lienLigne > fin))
                     )
				          { // on supprime le caractère pour pas que cela pose des pb par la suite mais on sait avec lienLigne que
					           // la ligne continue
					           *lienLigne = '\0'; suiteLigne = false;lienLigne=NULL;
					           //cout << "\n on a trouvé un antislash !! ";
					           //Sortie(1);
					         };
             char* ptr = tableau; // initialisation de la boucle do dans le if else suivant
             int debut = -1; // indiquera le premier caractère non nul
             // on cherche un carractere different de l'espace
             if ((fin != NULL)&&(fin != tableau) )  // cas ou il y a un #
               { 
                 do {                               // on cherche jusqu'a un
//                     if (*ptr != ' ')               // carractere non espacement
                     if ((*ptr != ' ') &&(*ptr != '\t')&&(*ptr != '\0'))   // carractere non espacement et non tabulation
                        nouvelleligne = 1 ;         //
                     ptr++; debut++;   
                    } while ((nouvelleligne == 0)&&(ptr <= fin-1));
                 if (nouvelleligne == 1)  // sortie de la ligne interessante
                    { // mise à nul du tableau tablcar
// nouvelle méthode: on se contente de mettre un caractère nul après la zone lue 
//essai----------------                      for (int ii =0; ii<= longueur; ii++) tablcar[ii] = '\0';
                      // recopie uniquement à partir du premier caractère non nul
                      int ii,ii2;
                      for (ii =debut,ii2=0; ii<= (int) (fin -  tableau) -1; ii++,ii2++) 
//                      for (ii =debut,ii2=0; ii<= ((int) fin - (int) tableau) -1; ii++,ii2++) 
                           tablcar[ii2] = tableau[ii];
									
							                 // on met un caractère de fin de chaine
							                 tablcar[ii2]='\0';		
									
                      // suppression des caractères nuls et des tabulations de fin de ligne 
                      for (int ii3 = ii2-1; ii3 >= 0; ii3--)
//                        if (tablcar[ii3] == ' ')  tablcar[ii3] = '\0'; else break;
                        if ((tablcar[ii3] == ' ') || (tablcar[ii3] == '\t'))
                          tablcar[ii3] = '\0';
                        else break;
                    };
               }
             else if (fin != tableau) // cas ou la ligne ne contiend pas de #
               { 
                 do {                               // on cherche jusqu'a un
//                     if (*ptr != ' ')               // carractere non espacement
                     if ((*ptr != ' ') &&(*ptr != '\t')&&(*ptr != '\0'))   // carractere non espacement et non tabulation
                        nouvelleligne = 1 ;         //
                     ptr++;debut++;   
                    } while ((nouvelleligne == 0)&&(ptr <= tableau + finLigne-1));
                 if (nouvelleligne == 1)  // sortie de la ligne interessante
                    { // mise à nul du tableau tablcar
// nouvelle méthode: on se contente de mettre un caractère nul après la zone lue 
//essai----------------                         for (int ii =0; ii<= longueur; ii++) tablcar[ii] = '\0';
                      // recopie uniquement à partir du premier caractère non nul
                      // jusqu'au caractère
                      int ii,ii2;
                      for (ii =debut,ii2=0; ii<= finLigne-1; ii++,ii2++) 
                           tablcar[ii2] = tableau[ii];
									
							               // on met un caractère de fin de chaine
							               tablcar[ii2]='\0';		
									
                      // suppression des caractères nuls de fin de ligne 
                      for (int ii3 = ii2-1; ii3 >= 0; ii3--)
                        if (tablcar[ii3] == ' ')  
                          tablcar[ii3] = '\0'; 
                        else 
                          break;   
                    };
               };
           };  // sinon cas d'une ligne vide, on passe a la suivante
        }
       else
        { // traitement des erreurs du flux d'entree
 //         if ( fichier.eofbit == 1 ) 
          #ifndef ENLINUX_STREAM
            if ( (fichier.rdstate() & ios_base::eofbit) == ios_base::eofbit) 
          #else  
            if ( (fichier.rdstate() & ios::eofbit) == ios::eofbit) 
          #endif

            {  ErrNouvelEnreg sortie(1) ; // fin du fichier atteind               
               throw (sortie); 
               nouvelleligne = 1;
             }  
          else
            {
               ErrNouvelEnreg sortie(-1) ; // probleme de lecture indetermine                
               throw (sortie);            // erreur de lecture
               nouvelleligne = 1;
             }  
        }; 
       // dans le cas où il y a un caractère de continuation on sauvegarde le résultat et on continue
		     if ((suiteLigne) || (tabMultiLignes[0] != '\0')) // cas ou on a lue un caractère de continuation
		      { //ou bien que l'on lit la dernière ligne d'une suite
		        strcat(tabMultiLignes,tablcar);
			     }; 
                         
     }while ((nouvelleligne == 0 ) || (suiteLigne));
	   // on boucle tant qu'il n'y a rien dans la ligne et qu'il n'y a pas de caractère de continuation
    // dans le cas ou le tableau tabMultiLignes a été utilisé on recopie le résultat dans tabcar
    if (tabMultiLignes[0] != '\0')
     strcpy(tablcar,tabMultiLignes);
	  		
//--pour la mise au point
//cout << "\n " << tablcar ;
//--fin mise au point		
     
  };   
       
// 
//         ----- routine de la classe UtilLecture -------
//  
// même routine que nouvel enreg, mais pour la lecture des commandes de visualisation
// On utilise grosso modo une struture simplifiée de nouvel_enreg car ici il n'y a pas de fichier
// Imbriqué
// Permet de passer les commentaires dans le fichier d'entree 
// Un commentaire se trouve apres le symbole #
// une ligne est consideree comme non_commentaire si elle possede au moins un carractere non
// identique a l'espace avant le carractere #
// dans le cas ou il y a une erreur de lecture ou que la fin de fichier est ateinte
// le programme genere une exception de tye : errNouvelEnreg, =1 -> fin de fichier
// = -1 autre probleme de lecture 

void   UtilLecture::Nouvel_enregCvisu ()                 
  {                   
  
    char delim = '\n'; // fin de ligne utilise
    int nouvelleligne = 0; // initialisation de l'indicateur pour sortie de la boucle 
                           //de recherche, quand = 1 on a trouve une ligne interessante                
    char* fin ; // position du carractere # 
    fstream & fichier = *ent_CommandeVisu;  
    int numLigne=0; // numéro de la ligne courante en lecture                          
  
    do  // on test jusqu'a une ligne interessante
     {                 
       fichier.getline(tableauCVisu,longueur,delim); // lecture d'une ligne dans le fichier
       numLigne++; // incrementation du numero de ligne

       if (  fichier.rdstate() == 0 )  // test de l'etat du flux d'entree     
        {  
           int finLigne = (int) strlen (tableauCVisu); // longueur de la ligne
           if ( finLigne > 0 ) 
            {   // cas d'une ligne non vide
              fin = strchr(tableauCVisu,'#');  // position du debut de commentaire s'il existe
              char* ptr = tableauCVisu; // initialisation de la boucle do dans le if else suivant
              int debut = -1; // indiquera le premier caractère non nul
              // on cherche un carractere different de l'espace
              if ((fin != NULL)&&(fin != tableauCVisu) )  // cas ou il y a un #
               { 
                 do {                               // on cherche jusqu'a un
                     if (*ptr != ' ')               // carractere non espacement
                        nouvelleligne = 1 ;         //
                     ptr++; debut++;   
                    } while ((nouvelleligne == 0)&&(ptr <= fin-1));
                 if (nouvelleligne == 1)  // sortie de la ligne interessante
                    { // mise à nul du tableauCVisu tablcarCVisu
// nouvelle méthode: on se contente de mettre un caractère nul après la zone lue 
//essai----------------                      for (int ii =0; ii<= longueur; ii++) tablcarCVisu[ii] = '\0';
                      // recopie uniquement à partir du premier caractère non nul
                      int ii,ii2;
                      for (ii =debut,ii2=0; ii<= (int) (fin - tableauCVisu) -1; ii++,ii2++) 
 //                     for (ii =debut,ii2=0; ii<= ((int) fin - (int) tableauCVisu) -1; ii++,ii2++) 
                           tablcarCVisu[ii2] = tableauCVisu[ii];
									
							 // on met un caractère de fin de chaine
							 tablcarCVisu[ii2]='\0';		
									
                      // suppression des caractères nuls de fin de ligne 
                      for (int ii3 = ii2-1; ii3 >= 0; ii3--)
                        if (tablcarCVisu[ii3] == ' ')  tablcarCVisu[ii3] = '\0'; else break;   
                     }; 
               }
              else if (fin != tableauCVisu) // cas ou la ligne ne contiend pas de #
               { 
                 do {                               // on cherche jusqu'a un
                     if (*ptr != ' ')               // carractere non espacement
                        nouvelleligne = 1 ;         //
                     ptr++;debut++;   
                    } while ((nouvelleligne == 0)&&(ptr <= tableauCVisu + finLigne-1));
                 if (nouvelleligne == 1)  // sortie de la ligne interessante
                    { // mise à nul du tableauCVisu tablcarCVisu
                      for (int ii =0; ii<= longueur; ii++) tablcarCVisu[ii] = '\0';
                      // recopie uniquement à partir du premier caractère non nul
                      // jusqu'au caractère
                      int ii,ii2;
                      for (ii =debut,ii2=0; ii<= finLigne-1; ii++,ii2++) 
                           tablcarCVisu[ii2] = tableauCVisu[ii];
                      // suppression des caractères nuls de fin de ligne 
                      for (int ii3 = ii2-1; ii3 >= 0; ii3--)
                        if (tablcarCVisu[ii3] == ' ')  
                          tablcarCVisu[ii3] = '\0'; 
                        else 
                          break;   
                    };
               };           
            };  // sinon cas d'une ligne vide, on passe a la suivante
        }
       else 
        { // traitement des erreurs du flux d'entree
 //         if ( fichier.eofbit == 1 ) 
          #ifndef ENLINUX_STREAM
            if ( (fichier.rdstate() & ios_base::eofbit) == ios_base::eofbit) 
          #else  
            if ( (fichier.rdstate() & ios::eofbit) == ios::eofbit) 
          #endif

            {  ErrNouvelEnregCVisu sortie(1) ; // fin du fichier atteind               
               throw (sortie); 
               nouvelleligne = 1;
             }  
          else
            {
               ErrNouvelEnregCVisu sortie(-1) ; // probleme de lecture indetermine                
               throw (sortie);            // erreur de lecture
               nouvelleligne = 1;
             }  
        }; 
       // dans le cas 
                         
     }while (nouvelleligne == 0 ) ;
     
  };   
       
#ifdef UTILISATION_MPI
 // ramène un nouvel enregistrement dans le buffer passé en paramètre
 // ramène true tant que l'on n'a pas atteind la fin de fichier
 // collectif: indique si on veut une utilisation collective ou pas
 // en sortie posi_suivant: qui indique l'offset du prochain charactère qu'on voudrait lire
 // important: le pointeur de fichier en sortie n'est pas posi_suivant, il suit en fait
 // la lecture d'un gros buffer interne, du coup si on veut une nouvelle lecture
 // en dehors de Nouvelle_enreg_MPI_BI, il faut au paravent se positionner sur posi_suivant
 bool UtilLecture::Nouvelle_enreg_MPI_BI(MPI_File * file,string & buf_ligne,bool collectif,MPI_Offset& posi_suivant)
  {
    bool pas_fin_fichier = true; // init
  #ifdef MISE_AU_POINT
   // petite vérification
   if (lecture_MPI_BI_en_cours == 0)
     { cout << "\n *** erreur la lecture d'un enregistrement dans le .BI "
            << " n'est pas autorisee, lecture_MPI_BI_en_cours == 0 "
            << "\n UtilLecture::Nouvelle_enreg_MPI_BI(..."<<endl;
       Sortie(1);
     };
  #endif
     
   MPI_Status status;
   int ierr_lecture = 0; // init
   // si aucune lecture en cours on récupère un premier buffer
   if (lecture_MPI_BI_en_cours == 1)
     {
       // on récupère la position du début du buffer
       int ierr = MPI_File_get_position(*file, &offset_Nouvelle_enreg_MPI);
       if (ierr)
        {cout << "\n *** erreur d'acces a MPI_File_get_position , stop Herezh "
              << "\n UtilLecture::Enregistrement_position_increment_base_info(..." << endl;
         Sortie(1);
        };
       if (collectif)
         ierr_lecture = MPI_File_read_shared(*file, buffer_MPI, taille_buffer_Nouvelle_enreg_MPI, MPI_CHAR, &status);
       else
         ierr_lecture = MPI_File_read(*file, buffer_MPI, taille_buffer_Nouvelle_enreg_MPI, MPI_CHAR, &status);
    #ifdef MISE_AU_POINT
      if (ierr_lecture)
       { cout << "\n *** erreur en lecture MPI dans le .BI "
              << " proc: " << num_cpu_en_cours_BI << " , code d'erreur = "<< ierr_lecture << endl;
         Sortie(1);
       };
    #endif
     
      // on récupère le nombre d'éléments lus
      MPI_Get_count(&status, MPI_CHAR,&taille_actuelle_buffer);
      // si le nombre est inférieur à celui demandé, on est arrivé à la fin du fichier
      if (taille_actuelle_buffer < taille_buffer_Nouvelle_enreg_MPI)
           {pas_fin_fichier = false;}
      else {pas_fin_fichier = true;};
      lecture_MPI_BI_en_cours = 2;
      dernier_posi_dans_buffer = 0; // init
     };

   // on récupère une ligne c-a-d qu'on parcours le buffer jusqu'à une fin de ligne
   bool ligne_pas_finie = true; // init
   int i=dernier_posi_dans_buffer; buf_ligne = "";// init
   while (ligne_pas_finie)
     { i++;
       // si on sort du buffer, il faut récupérer un autre buffer
       if (i>taille_actuelle_buffer)
        {
         // on récupère la position du début du buffer
         int ierr = MPI_File_get_position(*file, &offset_Nouvelle_enreg_MPI);
         if (ierr)
          {cout << "\n *** erreur d'acces a MPI_File_get_position , stop Herezh "
                << "\n UtilLecture::Enregistrement_position_increment_base_info(..." << endl;
           Sortie(1);
          };
         if (collectif)
           ierr_lecture = MPI_File_read_shared(*file, buffer_MPI, taille_buffer_Nouvelle_enreg_MPI, MPI_CHAR, &status);
         else
           ierr_lecture = MPI_File_read(*file, buffer_MPI, taille_buffer_Nouvelle_enreg_MPI, MPI_CHAR, &status);
         #ifdef MISE_AU_POINT
         if (ierr_lecture)
          {cout << "\n *** erreur d'acces a MPI_File_read , stop Herezh "
                << "\n UtilLecture::Nouvelle_enreg_MPI_BI(..." << endl;
           Sortie(1);
          };
         #endif

         // on récupère le nombre d'éléments lus
         ierr_lecture = MPI_Get_count(&status, MPI_CHAR,&taille_actuelle_buffer);
         #ifdef MISE_AU_POINT
         if (ierr_lecture)
          {cout << "\n *** erreur d'acces a MPI_Get_count , stop Herezh "
                << "\n UtilLecture::Nouvelle_enreg_MPI_BI(..." << endl;
           Sortie(1);
          };
         #endif
         // si le nombre est inférieur à celui demandé, on est arrivé à la fin du fichier
         if (taille_actuelle_buffer < taille_buffer_Nouvelle_enreg_MPI)
              {pas_fin_fichier = false;}
         else {pas_fin_fichier = true;};
         // si la taille du buffer = 0 on ne peut plus lire de caractère et de plus on est à la fin du fichier
         dernier_posi_dans_buffer = -1; // au cas où
         if (taille_actuelle_buffer == 0)
            break;
         // sinon on continue avec le nouveau buffer
         i =  1;
        };
       // si le prochain caractère est '\n', on valide la ligne
       buf_ligne += buffer_MPI[i];
       if (buffer_MPI[i] == '\n')
          {ligne_pas_finie = false;
          };
     };
    
   //si le buffer n'est pas vidé on positionne la prochaine lecture de caractère
   if (!ligne_pas_finie) // la lecture a été ok (on a lue une ligne avec un '\n' à la fin
     { dernier_posi_dans_buffer = i;
       posi_suivant = offset_Nouvelle_enreg_MPI + dernier_posi_dans_buffer + 1;
     }
   else
    { // si la ligne n'est pas finie il y a un pb !!
      cout << "\n **** erreur de lecture MPI dans le .BI pour le proc "<< num_cpu_en_cours_BI
           << " on a atteint la fin de fichier et la ligne courante n'est pas terminee "
           << " actuellement on a lue :" << buf_ligne;
      Sortie(1);
    };

     // retour de l'indicateur de fin de fichier
     return pas_fin_fichier;
     };
#endif

  
                            
                            
                            
                            
                            
                            
