// 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/>.

/************************************************************************
 *     DATE:        23/01/97                                            *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:     Gestion des listes de references.                       *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
#ifndef LESREFERENCES_H
#define LESREFERENCES_H

#include "Reference.h"
#include <list>
#include <map>
#include "UtilLecture.h"
#include "MotCle.h"

#ifdef UTILISATION_MPI
  #include <boost/mpi/environment.hpp>
  #include <boost/mpi/communicator.hpp>
  #include <boost/serialization/string.hpp>
  #include <boost/serialization/vector.hpp>
  #include <boost/mpi.hpp>
  namespace mpi = boost::mpi;
#endif

/// @addtogroup Les_classes_Reference
///  @{
///

///  Gestion des listes de references.
///
/// \author    Gérard Rio
/// \version   1.0
/// \date      23/01/97

//-------- une méthode permettant d'utiliser des tableaux de map de références -----
   // surcharge de l'operator d'ecriture
   ostream & operator << (ostream & sort, const map < string, Reference*, std::less <string> > & );

//----------- fin de la méthode permettant d'utiliser des tableaux de map de références -----
/// @}  // end of group

/// @addtogroup Les_classes_Reference
///  @{
///

///  Gestion des listes de references.
///
/// \author    Gérard Rio
/// \version   1.0
/// \date      23/01/97

class LesReferences
{
  public :
    // CONSTRUCTEURS :
    LesReferences ();  // par defaut
    // DESTRUCTEUR :
    ~LesReferences ();
    // METHODES PUBLIQUES :
    
    // def du numero de maillage courant, utilise avant la lecture
    void NbMaille(int nb);
    // def du type de reference a lire, utilise avant la lecture
    // type peut-être : noeud,element,surface,arete
    void Indic(string type);
    
    // lecture des references
    void Lecture(UtilLecture & entreePrinc);
    
    // ajout d'une référence déjà construite par ailleurs
    void Ajout_reference(Reference * refi); 
    
    // suppression d'une référence 
    void SupprimeReference(const string & st1,int num_mail);
    // suppression de tous les référence d'un maillage donné
    // si avec_diminution_num_maillage = true: 
    // tous les numéros de maillage, > num_mail,  associé aux maillages qui restent
    // sont diminués de un, pour tenir compte de la disparition du maillage et donc
    // d'une nouvelle numérotation des maillages
    // si avec_diminution_num_maillage = false, le conteneur des ref de maillage num_mail
    // est vidé, mais il continu à exister: on considère qu'il y a toujours un maillage num_mail potentiel
    void Supprime_tour_lesRef_un_maillage(int num_mail, bool avec_diminution_num_maillage);
    
    // affichage des informations contenu dans les references
    // par défaut affiche toutes les infos
    // si niveau = 1 : affiche que les noms des ref
    void Affiche(int niveau=0) const ;
 
    // affichage des informations contenu dans les references d'un certain type
    // défini par indic :
    // indic =  1 -> noeud, =2 -> element
    // =3 -> surface associée à un élément , =4 -> arete associée à un élément
    // =5 -> noeud associée à un élément
    // =6 -> point d'intégration associée à un élément
    // =7 -> de points d'intégrations relatifs à des surfaces d'éléments
    // =8 -> de points d'intégrations relatifs à des arete d'éléments
    // =0 -> rien_actuellement
    // par défaut affiche toutes les infos
    // si niveau = 1 : affiche que les noms des ref
    void Affiche(int indic, int niveau) const ;
		
	   // Affiche les donnees des références pour le maillage imail dans un fichier
	   // dont le nom est construit à partir du nom du maillage au format   ".lis"
	   void Affiche_dans_lis(const string& nom_maillage,int imail);
    
    // affichage et definition interactive des commandes 
    // nbMaxiNoeud: nombre maxi de noeud pour les exemples
    // nbMaxiElem : nombre maxi d'éléments pour les exemples
    // cas : =1 premier passage, il s'agit de références de noeuds uniquement
    // cas : =2 second passage, il s'agit de l'ensemble des possibilités de références
    void Info_commande_lesRef(int nbMaxiNoeud,int nbMaxiElem,UtilLecture * entreePrinc,int cas);
    
    //--- utilisation d'une boucle pour balayer l'ensemble des références existantes:
    // ***** très important: ce balaiyage ne fonctionne que si on ne modifie pas le stockage
    // ***** par exemple en supprimant une référence existante ou en ajoutant une nouvelle référence
    // ***** ou en lisant des références (donc ajout !!)
    // ***** par contre on peut changer le contenu des références existantes
    // initialise le questionnement de la récupération de référence et
    // retourne la première référence si elle existe sinon un pointeur nul
    const Reference* Init_et_Premiere();
    // retourne la référence suivante ou, s'il n'y en n'a plus, retourne
    // un pointeur nul
    const Reference* Reference_suivante();   
    //--- fin méthode pour faire une boucle pour balayer l'ensemble des références existantes:
    
    // test si la reference existe reellement
    // retourne false si n'existe pas , true sinon
    bool Existe(const string & st1,int num_mail) const ;
    bool Existe(const string & st1,const string* nom_mail) const; 
    // retourne la reference correspondant a une cle
    const Reference& Trouve(const string & st1,int num_mail) const ;
    const Reference& Trouve(const string & st1,const string* nom_mail) const ;
    // mise à jour de la map qui fait la liaison nom de maillage <=> numéro de maillage
    void MiseAJourMap( const map < string, int , std::less <string> >& listNomMail)
          { listeNomMail = & listNomMail;};  
            
    // mise à jour des références de noeud, dans le cas où les numéros de noeuds ont changés
//1) cas où l'on supprime éventuellement des noeuds de la référence,	qui ne sont plus référencé  
    // nv_tab est tel que : nv_tab(i) est le nouveau numéro qui avait auparavant le numéro "i"
    // non_referencer(i) : = true signifie qu'il ne faut plus tenir compte de ce noeud
    //                     = false indique qu'il continue d'être actif
    void Mise_a_jour_ref_noeud(Tableau <int >& nv_tab,int num_mail,Tableau <bool>& non_referencer);
//2) cas où on considère tous les noeuds 
    // nv_tab est tel que : nv_tab(i) est le nouveau numéro qui avait auparavant le numéro "i"
    void Mise_a_jour_ref_noeud(Tableau <int >& nv_tab,int num_mail);

    // mise à jour des références d'élément, dans le cas où les numéros d'élément ont changés
//1) cas où l'on supprime éventuellement des éléments de la référence,	qui ne sont plus référencé  
    // nv_tab est tel que : nv_tab(i) est le nouveau numéro qui avait auparavant le numéro "i"
    // non_referencer(i) : = true signifie qu'il ne faut plus tenir compte de cet élément
    //                     = false indique qu'il continue d'être actif
    void Mise_a_jour_ref_element(Tableau <int >& nv_tab,int num_mail,Tableau <bool>& non_referencer);
 
    // mise à jour du numéro de maillage d'une référence
    void Mise_a_jour_num_maillage_ref(const string nom_ref, int old_num_maill, int new_num_maill)
       { Trouve_interne(nom_ref,old_num_maill).Change_Nbmaille(new_num_maill);};
    
	//----- lecture écriture dans base info -----
	// cas donne le niveau de la récupération
    // = 1 : on récupère tout
    // = 2 : on récupère uniquement les données variables (supposées comme telles)
	   void Lecture_base_info(istream& ent,const int cas);
    // cas donne le niveau de sauvegarde
    // = 1 : on sauvegarde tout
    // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
	   void Ecriture_base_info(ostream& sort,const int cas);
 
#ifdef UTILISATION_MPI
    // retour de la taille globale des sorties retardées
    // concernant les sorties sur .BI
    int Taille_buffer_sortie_BI();
    // récupération de l'offset global sur .BI pour la classe
    // et mise à jour des offsets de classes dérivées si besoin
    void Mise_a_jour_Offset_BI_ecriture(int offset,const int cas);
    // idem en lecture, mais là il s'agit uniquement de la mise à jour
    // de l'offset seul puis c'est la classe qui s'en débrouille
    void Mise_a_jour_Offset_BI_lecture(int offset,const int cas);

    // lecture MPI des infos bufferisées
    void Lecture_base_info_MPI_IO(MPI_File * ent_MPI,const int cas);
    // écriture MPI des infos bufferisées
    void Ecriture_base_info_MPI_IO(MPI_File * sort_MPI, const int cas);
#endif

  protected :
    // variable transitoires utilise pendant la lecture
    int nbMaille; // nb courant de maillage
    int indic ; // type courant de reference : = 1 -> noeud, =2 -> element
    // =3 -> surface associée à un élément , =4 -> arete associée à un élément
    // =5 -> noeud associée à un élément
    // =6 -> point d'intégration associée à un élément
    // =7 -> de points d'intégrations relatifs à des surfaces d'éléments
    // =8 -> de points d'intégrations relatifs à des arrete d'éléments
    // =0 -> rien_actuellement
    Reference * ref; // une variable de travail
      
    // VARIABLES PROTEGEES :
//    list <Reference*> listeDeRef; // liste des references
    
    // on utilise une map pour récupérer plus rapidemment une référence à partir d'un nom
    // t_mapDeRef (i) est la map relative au maillage i
    Tableau < map < string, Reference*, std::less <string> > > t_mapDeRef;
    
    // liste des noms de maillages associée à un numéro sous forme d'un arbre pour faciliter la recherche
    const map < string,  int , std::less <string> >* listeNomMail;
    // a utiliser avec Existe et Trouve, mais pas avant la lecture, seulement après
    
    static MotCle motCle; // liste des mots clés
    
    //list <Reference*>::const_iterator iref; 
    // deux variables intermédiaires pour les méthodes Init_et_Premiere et Reference_suivante
    map < string, Reference*, std::less <string> >::const_iterator iref; 
    int num_mail_presuivant;
    
 #ifdef UTILISATION_MPI
    // cas d'un calcul parallèle: // passage des infos entre process
    // pour les i/o
    int nb_buffer; // ici = 1 seul buffer
    Tableau <std::string > buffer_ioBI_MPI; // les buffers pour la sortie retardée
      // uniquement les buffers propres : ici taille 1 pour tous les proc
    std::vector<int>  tailles_buffer_ioBI_MPI; // tailles des buffers
      // size 1 pour tous les proc
    // offsets , offset_LesReferences[0] est l'offset de début (premier char)
    // [1] : position de la fin +1 (premier char après les ref)
    std::vector<int> offset_LesReferences;
    int taille_offset; // = 2 ici
 #endif
    
    // METHODES PROTEGEES :
    // lecture d'une  reference
    bool LectureReference(UtilLecture & entreePrinc);
    // retourne la reference correspondant a une cle, en non constant
    Reference& Trouve_interne(const string & st1,int num_mail) const ;
    Reference& Trouve_interne(const string & st1,const string* nom_mail) const ;
 

 };
 /// @}  // end of group

#endif