// 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-2021 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 "LesCourbes1D.h"
#include "ParaGlob.h"
//#include <extras.h>
#include "CharUtil.h"

// --------------- variables statiques ---------
 MotCle LesCourbes1D::motCle; // liste des mots clés

LesCourbes1D::LesCourbes1D () :  // par defaut
    listeDeCourbe1D()   
    {  }; 
// DESTRUCTEUR :
LesCourbes1D::~LesCourbes1D ()
    { // effacement des grandeurs pointées par la liste de référence
      map < string, Courbe1D * , std::less <string> >::iterator i,ifin=listeDeCourbe1D.end();
      for (i=listeDeCourbe1D.begin() ; i != ifin; i++)
             if ((*i).second != NULL) delete (*i).second;
     };
        
 // lecture des courbes
 void LesCourbes1D::Lecture(UtilLecture & entreePrinc)
   { if (strstr(entreePrinc.tablcar,"les_courbes_1D")!=NULL)
      {try
        { if (ParaGlob::NiveauImpression() >= 4) cout << " debut de la lecture de courbes " << endl;
          // lecture des courbes temps qu'il n'y a pas de nouveau mot clé
          string nom_courbe,type_courbe; // variables de travail
          Courbe1D * courbe=NULL;
          entreePrinc.NouvelleDonnee();
          while (!motCle.SimotCle(entreePrinc.tablcar))
            { // lecture du nom de la courbe et de son type
              *(entreePrinc.entree) >> nom_courbe >> type_courbe;
              if (ParaGlob::NiveauImpression() >= 6) 
                 cout << " lecture de la courbe " << nom_courbe << endl;
              // création de la courbe    
              courbe = Courbe1D::New_Courbe1D(nom_courbe,Id_Nom_Courbe1D (type_courbe.c_str()));
              // lecture de la courbe
              courbe->LectDonnParticulieres_courbes (nom_courbe,&entreePrinc);
              if (ParaGlob::NiveauImpression() >= 6) 
                 cout << " fin de la lecture de la courbe " << nom_courbe << endl;
              // verification que l'on n'a pas deux noms de courbes identiques
              bool res = false;
              map < string, Courbe1D * , std::less <string> > ::iterator il = listeDeCourbe1D.find(nom_courbe);
              if (il != listeDeCourbe1D.end()) res=true;                                          
              if (res)
                { cout <<" \n Erreur de lecture de courbes 1D, deux courbes ont le meme nom \n";
                  cout <<" nom = " << nom_courbe << '\n';
                  cout <<"LesCourbes1D::LectureLesCourbes1D(UtilLecture & entreePrinc)" 
                       << endl;
                  entreePrinc.MessageBuffer("lecture des  courbes1D");                                    
                  throw (UtilLecture::ErrNouvelleDonnee(-1));
                  Sortie (1);
                 }
              else
                listeDeCourbe1D[nom_courbe]=courbe;
              entreePrinc.NouvelleDonnee(); // nouvelle ligne                    
              };
           if (ParaGlob::NiveauImpression() >= 4) cout << " fin de la lecture de courbes " << endl;
           }
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch(...)
        { cout << "\n ** erreur en lecture d'une courbes 1D ";
          throw (UtilLecture::ErrNouvelleDonnee(-1));
          Sortie(1);
        };
      };
     // maintenant on établit les liens éventuels entres les courbes qui peuvent dépendre les unes des autres
     // (exemple de courbe complexe construite à partir de courbe simples) 
     map < string, Courbe1D * , std::less <string> >::iterator idl,edlfin=listeDeCourbe1D.end();
     for (idl = listeDeCourbe1D.begin();idl != edlfin;idl++)
      {Courbe1D * co = (*idl).second; // pour plus de clarté 
       if (co->DependAutreCourbes())
         {// cas d'une courbe avec dépendance
          // -- récupération des noms de courbes de dépendance
          list <string> lico;
          co->ListDependanceCourbes(lico); 
          // -- création de la liste de pointeur de courbes correspondantes
          list <string>::iterator ili,ilifin=lico.end();
          list <Courbe1D *> liptco;
          for (ili=lico.begin();ili!=ilifin;ili++)
            liptco.push_back(LesCourbes1D::Trouve(*ili));
          // ---- on renseigne la courbe
          co->Lien_entre_courbe(liptco);
          };
       };
     };
    
// affichage et definition interactive des commandes 
void LesCourbes1D::Info_commande_lesCourbes1D(UtilLecture & entreePrinc)
 { string rep;
   cout << "\n voulez-vous utiliser des courbes 1D ? (rep o ou n (defaut)) ";
   rep = lect_return_defaut(false,"n");
   if (rep == "o")
    { // on récupère la liste des identificateurs de courbes actuellement disponible
      list <EnumCourbe1D> list_enuCourbe1D = Courbe1D::Liste_courbe_disponible();
      // affichage et choix de courbe1D
      cout << "\n Donner le type de courbe que vous souhaitez utiliser: ?  "
           << "\n (NB: l'utilitaire va definir un exemple de courbe qu'il faudra ensuite adapter !)   ";;
      string rep;int num; bool choix_valide = false;
      Tableau <bool> chooi(list_enuCourbe1D.size(),false); // tableau de travail
      list <string> nom_de_fichiers; bool inclusion_fichier=false;
      list <EnumCourbe1D>::iterator it,itfin=list_enuCourbe1D.end();
      while (!choix_valide)
      {
       try 
        { // affichage des éléments possibles
          int undeux=0;
          cout << "\n (0 ou f) fin \n";
          int inu;
          for (it=list_enuCourbe1D.begin(),inu=1;it!=itfin;it++,inu++)
            { cout << "\n";
              cout << " (" << inu << ") " << Nom_Courbe1D(*it) << "   ";
              //undeux++;
              //if (undeux==2) {cout << "\n";undeux=0;}
             };
          int nb_courbe = list_enuCourbe1D.size();
          cout << "\n (" << nb_courbe+1 << ")   inclusion d'un fichier de def de courbe ";
          cout << "\n un numero ? ";
          rep = lect_return_defaut(false,"f");
          if (rep == "fin_prog") Sortie(1);
          num = ChangeEntier(rep);
          if (Minuscules(rep) == "f")
            num = 0;
          choix_valide=false;  
          if (num == 0) 
           { choix_valide=true;}
          else if (num == nb_courbe+1)
           { string nom_fichier="";
             cout << "\n nom du fichier ? "; nom_fichier = lect_chaine();
             cout << " nom lu: "<<nom_fichier << "\n";
             nom_de_fichiers.push_back(nom_fichier);
             inclusion_fichier=true;
           }
          else // sinon
           { if ((num >= 0)&&(num<=list_enuCourbe1D.size())) 
              {if (chooi(num))
                 cout << "\n type d'element deja choisit, recommencer";
               else    
                chooi(num) = true;
               }
             else { cout << "\n Erreur on attendait un entier entre 0 et "<< list_enuCourbe1D.size()+1 <<" !!, "
                         << "\n redonnez une bonne valeur"
                         << "\n ou taper fin_prog pour arreter le programme"; 
                  };
            };
         }    
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
          {  cout << "\n Erreur on attendait un entier entre 0 et "<< list_enuCourbe1D.size() <<" !!, "
                  << "\n redonnez une bonne valeur"
                  << "\n ou taper fin_prog pour arreter le programme";
             choix_valide=false;
          };
       } //-- fin du while 
     // maintenant on définit un exemplaire de chaque courbe choisit
     int cot=1;string nom_courbe; Courbe1D * courbe=NULL;
     for (it=list_enuCourbe1D.begin();it!=itfin;it++,cot++)
      { if(chooi(cot))
         { nom_courbe = "exemple_courbe";
           nom_courbe += ChangeEntierSTring(cot);
           courbe = Courbe1D::New_Courbe1D(nom_courbe,*it);
           listeDeCourbe1D[nom_courbe]=courbe;
          }
       }
     // affichage des infos dans le fichier de commande
     ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
     sort << "\n#-------------------------------------"
          << "\n# definition facultative de courbe 1D|" 
          << "\n#-------------------------------------"
          << "\n \n            les_courbes_1D #------------"
          << endl;
     // puis chaque courbe sort ses infos
     map < string, Courbe1D * , std::less <string> >::iterator itc,itcfin =  listeDeCourbe1D.end();     
     for (itc= listeDeCourbe1D.begin();itc!=itcfin;itc++)
       (*itc).second->Info_commande_Courbes1D(entreePrinc);
     // dans le cas où il y a des inclusions de fichiers
     if (inclusion_fichier)     
       { list <string>::iterator ill,illfin = nom_de_fichiers.end();
         for (ill=nom_de_fichiers.begin();ill != illfin;ill++)
           sort << "\n < " << (*ill) ;
       };

     // fin def courbe
     sort << "\n#------------- fin def des courbes 1D ------------------------"
          << endl;     
     sort << flush;
    };
 };
          
     
 // affichage des courbes
void LesCourbes1D::Affiche() const 
  {   map < string, Courbe1D * , std::less <string> >::const_iterator i,ifin=listeDeCourbe1D.end();
      bool res = false;
      cout << " \n ------- affichage des listes de courbes ------- \n "; 
      for (i=listeDeCourbe1D.begin() ; i != ifin; i++)
          { cout << "\n";
            ((*i).second)->Affiche();
           } 
      cout << endl;          
  };
  
// test si la courbe de nom st1 existe reellement
// retourne false si n'existe pas , true sinon
bool LesCourbes1D::Existe(const string & st1) const 
  { // verification 
    bool res = false;
    map < string, Courbe1D *, std::less <string> > ::const_iterator il = listeDeCourbe1D.find(st1);
    if (il != listeDeCourbe1D.end()) res=true;
    return res;      
   };       

 // retourne la courbe correspondant a une cle
Courbe1D* LesCourbes1D::Trouve(const string & st1) const 
  { map < string, Courbe1D *, std::less <string> > ::const_iterator il = listeDeCourbe1D.find(st1);
    if (il != listeDeCourbe1D.end()) 
        return ((*il).second);
    cout << " \n pb la courbe1D de nom " << st1 << " n\'existe pas !! " << endl;
    Sortie (1);
    Courbe1D* bidon=NULL ;   // pour ne pas avoir de message de warning
    return  bidon;
   };       

// vérification que tout est ok, pres à l'emploi
// ramène true si ok, false sinon
bool LesCourbes1D::Complet()
  { // on passe en revue toutes les courbes
    map < string, Courbe1D *, std::less <string> > ::const_iterator il, ilfin = listeDeCourbe1D.end();
    bool retour = true;
    for (il=listeDeCourbe1D.begin();il!=ilfin;il++)
     { bool ret=((*il).second)->Complet_courbe();
       if (!ret)
        { cout << "\n erreur!!! la courbe n'est pas complete"; 
          ((*il).second)->Affiche();
          retour = false;
         }
      } 
    return retour;  
   };
   
    // utilitaire pour lire une courbe, soit qui ne sera pas stocké par LesCourbes1D
    // dans ce cas sont nom est "_", soit son nom correspond à une ref de nom de courbes existante
    // dans tous les cas on lit un nom et un type de courbe c-a-d un string et un EnumCourbe1D
    //                 -----     différents cas  -------
    // ptcourbe: soit == NULL, : on lit un nom, et on lit un type de courbe
    //                           1) si celui-ci est "_", cela signifie que la courbe à lire
    //                           est interne à l'utilisateur, on crée une courbe, on lit la courbe
    //                           avec Lecture_base_info de la courbe et on ramène un pointeur sur la 
    //                           nouvelle courbe 
    //                           2) si celui-ci est différent de "_", c'est une référence de courbe
    //                           on lit la référence et on ramène un pointeur sur la courbe de 
    //                           LesCourbes1D correspondant 
    //                           
    // soit == une courbe existante: on lit un nom, et on regarde le nom actuel de la courbe pointée
    //                               par ptcourbe que l'on appelera nom_ref
    //    1) nom = "_" et nom_ref = "_" 
    //                 1-a les deux courbes sont du même type on relie les données avec Lecture_base_info
    //                     et on ramène ptcourbe
    //                 1-b les deux courbes sont de type différent, on supprime la courbe pointée par
    //                     ptcourbe, on en crée une nouvelle adoc, et on ramène un pointeur dessus
    //    2) nom != "_" et nom_ref == "_" 
    //                  la courbes pointé par ptcourbe est supprimé, et on associe le pointeur de retour
    //                  a la courbe correspondant à nom de LesCourbes1D 
    //    3) nom == "_" et nom_ref != "_" 
    //                  on crée une nouvelle courbe adoc, on lie avec Lecture_base_info, et on ramène
    //                  un pointeur sur la courbe ainsi crée
    
Courbe1D * LesCourbes1D::Lecture_pour_base_info(ifstream& ent,const int cas,Courbe1D * ptcourbe)
  {  EnumCourbe1D type_de_courbe;string nom_courbe;
     ent >> nom_courbe >> type_de_courbe; 
     if (ptcourbe == NULL)
      {if (nom_courbe == "_")
        {// cas d'une courbe interne à l'appelant et pas de courbe défini, on en définit une
         ptcourbe = Courbe1D::New_Courbe1D(nom_courbe,type_de_courbe);
         // lecture des infos       
         ptcourbe->Lecture_base_info(ent,cas);
         }
       else
        {// cas d'une référence de courbe
         if (this->Existe(nom_courbe)) 
           { ptcourbe = this->Trouve(nom_courbe);}
         else
          {cout << "\n erreur 1 en lecture de la courbe  de nom " << nom_courbe
                << " elle n'existe pas dans la liste des courbes avec reference"
                << "\n LesCourbes1D::Lecture_pour_base_info(...";
           Sortie(1);     
           } 
          };
       }      
     else 
      { // cas où une courbe est déjà pointé
        if ((ptcourbe->NomCourbe() == "_") && (nom_courbe == "_"))
         { if (type_de_courbe == ptcourbe->Type_courbe())
            {// même type on se contente de relire
             ptcourbe->Lecture_base_info(ent,cas);
             }
           else
            {// pas de même type on supprime, on recrée, on li
             delete ptcourbe;     
             ptcourbe = Courbe1D::New_Courbe1D(nom_courbe,type_de_courbe);
             ptcourbe->Lecture_base_info(ent,cas);
             }
          }
        else if ((ptcourbe->NomCourbe() == "_") && (nom_courbe != "_"))
         { // l'ancien est interne et le nouveau est une ref, on supprime, on récup la ref
           delete ptcourbe;     
           if (this->Existe(nom_courbe)) 
            { ptcourbe = this->Trouve(nom_courbe);}
           else
            {cout << "\n erreur 2 en lecture de la courbe  de nom " << nom_courbe
                  << " elle n'existe pas dans la liste des courbes avec reference"
                  << "\n LesCourbes1D::Lecture_pour_base_info(...";
             Sortie(1);     
             } 
          }  
        else if ((ptcourbe->NomCourbe() != "_") && (nom_courbe == "_"))
         { // l'ancien est une ref et le nouveau est interne, on crée et on li
           ptcourbe = Courbe1D::New_Courbe1D(nom_courbe,type_de_courbe);
           ptcourbe->Lecture_base_info(ent,cas);
          }
       } //-- fin du cas ou ptcourbe != NULL 
   // retour du pointeur
   return ptcourbe;            
 };
  
    // écriture pour base info
    // c'est le pendant de  Lecture_pour_base_info, de manière à être cohérent
void LesCourbes1D::Ecriture_pour_base_info(ofstream& sort,const int cas,Courbe1D * ptcourbe)
 { // la courbe d'écrouissage
   sort << ptcourbe->NomCourbe() << " " << ptcourbe->Type_courbe() << " ";
   // écriture le la courbe elle-même que si le nom est "_"
   if (ptcourbe->NomCourbe() == "_")
     {ptcourbe->Ecriture_base_info(sort,cas);};
  };
	 
     
//----- lecture écriture de base info -----
//   lecture base info
// = 1 : on récupère tout
// = 2 : on récupère uniquement les données variables (supposées comme telles)
void LesCourbes1D::Lecture_base_info(ifstream& entr,const int cas)
 {if (cas == 1)
   {cout << " == lecture des courbes \n";
    string toto;int taille; entr >> toto >> taille ; // passage de l'entête
    // on boucle sur le nombre de courbe à lire
    EnumCourbe1D type_de_courbe; //   "
    Courbe1D* courbe; string nom_courbe; string type_courbe; //               "
    
    for (int i=1;i<= taille; i++)
     { // lecture du nom de la courbe et de son type 
       entr >> nom_courbe >> type_de_courbe;
       // création de la courbe
       courbe = Courbe1D::New_Courbe1D(nom_courbe,type_de_courbe);
       // lecture de la courbe
       courbe->Lecture_base_info(entr,cas);
       // verification que l'on n'a pas deux noms de courbes identiques
       bool res = false;
       map < string, Courbe1D* , std::less <string> > ::iterator il = listeDeCourbe1D.find(nom_courbe);
       if (il != listeDeCourbe1D.end()) res=true;

       if (res)
        { cout <<" \n Erreur de lecture de courbes 1D, deux courbes ont le meme nom \n";
          cout <<" nom = " << nom_courbe << '\n';
          cout <<"LesCourbes1D::Lecture_base_info(..." << endl;
          Sortie (1);
         }
       else
         // intégration dans la liste
         listeDeCourbe1D[nom_courbe]=courbe;
       }
     }   
    };    
        
//   écriture base info   
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void LesCourbes1D::Ecriture_base_info(ofstream& sort,const int cas)
 {
  if (cas == 1)
   {sort << "\n \n****les_courbes1D_:_nombre= " << listeDeCourbe1D.size() ;
    // on balaie la liste 
    map < string, Courbe1D* , std::less <string> >::iterator i,ifin=listeDeCourbe1D.end();
    for (i=listeDeCourbe1D.begin() ; i != ifin; i++)
     { // on écrit le nom de la courbe et de sont type, sous forme énuméré, car ensuite dans chaque courbe le nom
       // en string est écrit
       sort << "\n" << (*i).first << " " << ((*i).second)->Type_courbe();
       // puis écriture de la courbe
       ((*i).second)->Ecriture_base_info(sort,cas);
      }
     }
    sort << "\n";   
   };       

     
// sortie du schemaXML: en fonction de enu  
void LesCourbes1D::SchemaXML_lesCourbes1D(ofstream& sort,const Enum_IO_XML enu) 
 { switch (enu)
    {case XML_TYPE_GLOBAUX: // cas du premier passage
 	  {// cas des classes de base, on commence par créé la liste globale des courbes possible
       // on récupère la liste des identificateurs de courbes actuellement disponible
       list <EnumCourbe1D> list_enuCourbe1D = Courbe1D::Liste_courbe_disponible();
       // maintenant on définit un exemplaire de chaque courbe possible
       list <EnumCourbe1D>::iterator it,itfin=list_enuCourbe1D.end();
       int cot=1;string nom_courbe; Courbe1D * courbe=NULL;
       for (it=list_enuCourbe1D.begin();it!=itfin;it++,cot++)
         { nom_courbe = "exemple_courbe";
           nom_courbe += ChangeEntierSTring(cot);
           courbe = Courbe1D::New_Courbe1D(nom_courbe,*it);
           listeDeCourbe1D[nom_courbe]=courbe;
          };           
       break;		
      }
     case XML_IO_POINT_INFO:
      {// cas de def de  LesMaillages
   /*    sort  << "\n<xsd:element name=\"LesMaillages\" >"
  	          << "\n  <xsd:complexType>"
  	          << "\n    <xsd:element  name=\"****les_maillages:_nombre=\" type=\"xs:positiveInteger\" "
  	          << "\n              use=\"required\" minOccurs=\"1\" maxOccurs=\"unbounded\" />"
  	          << "\n    <xsd:element  name=\"defMaillages\" type=\"Maillage\" use=\"required\" />"
  	          << "\n  </xsd:complexType>"
              << "\n</xsd:element>";*/
     // def de Maillage
//     SchemaXML_Maillage(sort,niveau);
         break;		
      }
    };
  // on balaie l'ensemble des courbes
  map < string, Courbe1D * , std::less <string> >::iterator itc,itcfin =  listeDeCourbe1D.end();     
  for (itc= listeDeCourbe1D.begin();itc!=itcfin;itc++)
       (*itc).second->SchemaXML_Courbes1D(sort,enu);
    
 };


