// 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 "CharUtil.h"
#include <sstream> // for istringstream 
using namespace std;
#include <limits>

// transformation d'un string ou d'une chaine de character en entier 
int ChangeEntier(string st)
   { using namespace std;
     char * chh = (char*)st.c_str();
     #ifndef ENLINUX_STREAM
         istringstream flux (chh);
     #else 
         istrstream flux (chh);
     #endif    
  
     int i;
     flux >> i;
     return i;
    }; 
int ChangeEntier(char * st)
   {using namespace std;
     #ifndef ENLINUX_STREAM
         istringstream flux (st);
     #else 
         istrstream flux (st);
     #endif    
     int i;
     flux >> i;
     return i;
    }; 

// test d'un nombre numérique: ref: http://rosettacode.org/wiki/Determine_if_a_string_is_numeric
bool isNumeric( const char* pszInput, int nNumberBase )
   {
    istringstream iss( pszInput );
    
    if ( nNumberBase == 10 )
    {
     double dTestSink;
     iss >> dTestSink;
    }
    else if ( nNumberBase == 8 || nNumberBase == 16 )
    {
     int nTestSink;
     iss >> ( ( nNumberBase == 8 ) ? oct : hex ) >> nTestSink;
    }
    else
     return false;
    
    // was any input successfully consumed/converted?
    if ( ! iss )
     return false;
    
    // was all the input successfully consumed/converted?
    return ( iss.rdbuf()->in_avail() == 0 );
   };

 // transformation d'un string ou d'une chaine de character en relle
double ChangeReel(string st)
   { using namespace std;
  
     #ifndef ENLINUX_STREAM
         istringstream flux ((char*) st.c_str());
     #else 
         istrstream flux ((char*) st.c_str());
     #endif    
     double i;
     flux >> i;
     return i;
    }; 

double ChangeReel(char * st)
   { using namespace std;
     #ifndef ENLINUX_STREAM
         istringstream flux (st);
     #else 
         istrstream flux (st);
     #endif    
     double i;
     flux >> i;
     return i;
    }; 
 // recherche "nom" dans le tableau "tabMot", si nom existe ramene true, sinon false
 bool ExisteString (Tableau<string>& tabMot,string nom)
   { for (int i=1;i<= tabMot.Taille();i++)
       if (tabMot(i) == nom)
          return true;
     return false;     
    };  
 // transformation d'un entier en chaine de caractere correspondant
 string ChangeEntierSTring(int a)
   {  int b = a ;
      string sor = "";
      do 
       { // on recherche la derniere decimale
         int reste = b % 10 ;
         // on ajoute a la chaine
         sor =  ChangeEntierChar(reste) + sor;
         // on calcul le chiffre des dizaines
         b = b/10;
        } while (b != 0) ;  
      return sor;
    } ; 
 // transformation d'un réel en chaine de caractère correspondant  
   string ChangeReelSTring(double a)
   {using namespace std;
    char tab[50]; // 50 caractères pour écrire le réel !!
    char* st = tab; 
     #ifndef ENLINUX_STREAM
         ostringstream flux (st,50);
     #else 
         ostrstream flux (st,50);
     #endif    
     flux << a << ends;
     return st;
    }; 

 // transformation d'un entier de 0 a 10 en 1 caractere correspondant
 // il existe une fonction _itoa qui fait le meme travail qui se trouve dans extras.h
 char ChangeEntierChar(int a)
{	char result= ' ';
	 switch (a)
	    {case 0 :
       result='0';break;
      case 1 :
       result='1';break;
      case 2 :
          result='2';break;
      case 3 :
       result='3';break;
      case 4 :
       result='4';break;
      case 5 :
       result='5';break;
      case 6 :
       result='6';break;
      case 7 :
       result='7';break;
      case 8 :
       result='8';break;
      case 9 :
       result='9';break;
      default :
       cout << "\nErreur : l'entier n'est pas compris entre 0 et 9  !\n";
       cout << "ChangeEntierChar(int a) \n";
       Sortie(1);
     };
	 return result;
};

 // transformation d'un string en minuscules
 string Minuscules(const string& st)
   {   using namespace std; 
       unsigned long int lon=  st.length ();
       string reponse;
       for (unsigned long int i=0;i<lon;i++)
          reponse += (char) tolower(st[i]);
       return reponse;
   };
// -------- utilitaire pour lire une chaine de caractères:
// si retour chariot, retourne la valeur par défaut passée en paramètre
// sinon retourne le string lue au clavier
// gestion d'erreur si lecture non correcte
     // si avec_ecriture = true: on écrit "--> valeur par defaut : n " val_defaut
string lect_return_defaut(bool avec_ecriture,string val_defaut)
 { string rep;
   bool entree_non_valide = true;
   while (entree_non_valide)
     { // on s'intéresse d'abord au retour chariot
       int c = std::cin.peek();  // peek character (sans changer le flux !!)
       if (( c == EOF )||(c=='\n'))
          {rep = val_defaut;
           if (avec_ecriture)
             cout << "--> valeur par defaut : "<< val_defaut << flush ;
           c = getchar(); // on lit quand même le caractère
           entree_non_valide = false;
          }
       else // sinon on peut lire
         {std::getline (std::cin,rep);};
       // gestion d'erreur éventuelle
       if ( std::cin.fail()  || std::cin.eof())
          {std::cout << "\n Saisie incorrecte, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
          }
         else // sinon c'est ok
          {entree_non_valide = false;};
     };
  // retour de l'info
  return rep;
 };

 // lecture d'une chaine de caractère via getline: pas de validation
 // tant qu'il n'y a rien de lue
 // gestion d'erreur si lecture non correcte
 string lect_chaine()
 { string rep;
   bool entree_non_valide = true;
   while (entree_non_valide)
     { // on s'intéresse d'abord au retour chariot
       int c = std::cin.peek();  // peek character (sans changer le flux !!)
       if (( c == EOF )||(c=='\n'))
          {std::cout << "\n Saisie incorrecte, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
           entree_non_valide = false;
          }
       else // sinon on peut lire
         {std::getline (std::cin,rep);};
       // gestion d'erreur éventuelle
       if ( std::cin.fail()  || std::cin.eof())
          {std::cout << "\n Saisie incorrecte, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
          }
         else // sinon c'est ok
          {entree_non_valide = false;};
     };
  // retour de l'info
  return rep;
 };


 // lecture d'un scalaire réel avec getline
 // gestion d'erreur si lecture non correcte
 double lect_double()
 { string rep;
   bool entree_non_valide = true;
   while (entree_non_valide)
     { // on s'intéresse d'abord au retour chariot
       int c = std::cin.peek();  // peek character (sans changer le flux !!)
       if (( c == EOF )||(c=='\n'))
          {std::cout << "\n Saisie incorrecte, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
           entree_non_valide = false;
          }
       else // sinon on peut lire
         {std::getline (std::cin,rep);};
       // gestion d'erreur éventuelle
       if ( std::cin.fail()  || std::cin.eof())
          {std::cout << "\n Saisie incorrecte, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
          }
         else // sinon c'est ok
          {entree_non_valide = false;};
     };
  // on traduit en réel
  double result = ChangeReel(rep);
  // retour de l'info
  return result;
 };


//
//rep = lect_return_defaut(false,"f");
//rep = lect_return_defaut(false,"o");
//rep = lect_return_defaut(true,"o");
//= lect_chaine();
//rep = lect_chaine();
//(int) lect_double();
//#include "CharUtil.h"


// cas d'une valeur o/n , sinon pas acceptable
// si avec_ecriture = true: on écrit "--> valeur lue : "  valeur lue
string lect_o_n(bool avec_ecriture)
 { string rep;
   bool entree_non_valide = true;
   while (entree_non_valide)
     { // on s'intéresse d'abord au retour chariot
       int c = std::cin.peek();  // peek character (sans changer le flux !!)
       if (( c == EOF )||(c=='\n'))
          {// ce n'est pas acceptable
           std::cout << "\n Saisie incorrecte1, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
           entree_non_valide = false;
          }
       else // sinon on peut lire
         {std::getline (std::cin,rep);};
       // gestion d'erreur éventuelle
       if ( std::cin.fail()  || std::cin.eof())
          {std::cout << "\n Saisie incorrecte2, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
          }
       else // sinon c'est ok
          { rep = Minuscules(rep);
            if (!((rep == "o") || (rep == "n")))
             {std::cout << "\n Saisie incorrecte3, recommencez : ";
              std::cin.clear(); // effacer les bits d'erreurs
              }
            else // sinon ouf, c'est ok
             {entree_non_valide = false;
              if (avec_ecriture)
                cout << "--> valeur lue : "<< rep << flush ;
             };
          };
     };
  // retour de l'info
  return rep;
 };

 // cas d'une valeur 1/0 , sinon pas acceptable
 // si avec_ecriture = true: on écrit "--> valeur lue : "  valeur lue
 string lect_1_0(bool avec_ecriture)
 { string rep;
   bool entree_non_valide = true;
   while (entree_non_valide)
     { // on s'intéresse d'abord au retour chariot
       int c = std::cin.peek();  // peek character (sans changer le flux !!)
       if (( c == EOF )||(c=='\n'))
          {// ce n'est pas acceptable
           std::cout << "\n Saisie incorrecte1, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin           
          }
       else // sinon on peut lire
         {std::getline (std::cin,rep);};
       // gestion d'erreur éventuelle
       if ( std::cin.fail()  || std::cin.eof())
          {std::cout << "\n Saisie incorrecte2, recommencez : ";
           std::cin.clear(); // effacer les bits d'erreurs
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
          }
       else // sinon c'est ok
          { rep = Minuscules(rep);
            if (!((rep == "1") || (rep == "0")))
             {std::cout << "\n Saisie incorrecte3, recommencez : ";
              std::cin.clear(); // effacer les bits d'erreurs
              }
            else // sinon ouf, c'est ok
             {entree_non_valide = false;
              if (avec_ecriture)
                cout << "--> valeur lue : "<< rep << flush ;
             };
          };
     };
  // retour de l'info
  return rep;
 };

 // lecture du prochain caractère non espace et non vide dans le flot sans modifier le flot
 // en remplacement de la méthode peek qui ne marche pas avec code warrior
 // si pb ou aucun caractère, retour du caractère "espacement"
 char Picococar(istream& entr)
  { char car; // = flot.peek();
    entr >> car;
    // si pb cela signifie qu'en fait la ligne est terminée donc on s'arrête
    if (entr.rdstate() != 0) {return ' ';}
    // sinon on lit jusqu'à un caratère non nul
    while ( (car==' ')  && (entr.rdstate() == 0 ))
      // cas où le prochain caractère est un espace 
      { entr >> car; 
       }
    // si c'est une sortie car pb on retourne car c'est la fin de ligne   
    if (entr.rdstate() != 0) return ' ';
    // sinon on remet le caractère dans le flot
    entr.putback(car);
    return car; 
   };
 char Picococar(istrstream& entr)      
  { char car; // = flot.peek();
    entr >> car;
    // si pb cela signifie qu'en fait la ligne est terminée donc on s'arrête
    if (entr.rdstate() != 0) {return ' ';}
    // sinon on lit jusqu'à un caratère non nul
    while ( (car==' ')  && (entr.rdstate() == 0 ))
      // cas où le prochain caractère est un espace 
      { entr >> car; 
       }
    // si c'est une sortie car pb on retourne car c'est la fin de ligne   
    if (entr.rdstate() != 0) return ' ';
    // sinon on remet le caractère dans le flot
    entr.putback(car);
    return car; 
   };