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

#ifndef  LesContacts_2_deja_inclus
  #include "LesContacts.h"
#endif

#ifndef  LesContacts_2_deja_inclus

#include <vector>
#include "ReferenceNE.h"
#include "ReferenceAF.h"


//----- lecture écriture base info -----
// lecture base info
// on utilise deux pointeurs de fonctions qui permettent de récupérer le pointeur de noeud esclave
// idem au niveau de l'élément 
template <class T>
void LesContacts::Lec_base_info_LesContacts(ifstream& ent
						,T& instance  // l'instance qui permet d'appeler les pointeurs de fonctions
						,Noeud& (T::*RecupNoeud)(int i, int j) const
						,Element& (T::*RecupElement_LesMaille)(int i, int j) const)
  {
    int niveau_commentaire_lescontacts = Permet_affichage();
    // tout d'abord on lit le type
    string type_contact,no_taille; int taille=0; // taille par défaut
    ent >> type_contact >> no_taille >> taille;
    #ifdef MISE_AU_POINT
    if (type_contact != "LesContacts:")
      { cout << "\n erreur dans la lecture des contacts, on attendait la chaine: LesContacts:"
             << " alors que l'on a lue : " << type_contact
             << "\n LesContacts::Lec_base_info_LesContacts(i...";
        Sortie(1);     
       };
    if (no_taille != "taille")
      { cout << "\n erreur dans la lecture des contacts, on attendait la chaine: taille"
             << " alors que l'on a lue : " << no_taille
             << "\n LesContacts::Lec_base_info_LesContacts(i...";
        Sortie(1);     
       };
    #endif
    // on supprime tous les éléments de contact sauf... les collants qui restent collant
    {LaLIST <ElContact>::iterator iE ;
     // on met .end(), car cette borne peut changer au gré des suppression
     for (iE = listContact.begin(); iE != listContact.end(); iE++)
       if (!((*iE).Collant())   // et si ce n'est pas collant: si collant, on ne change rien
          )
         { // sinon on supprime
           LaLIST <ElContact>::iterator iiE = iE;
           iE--; // pointe sur le precedent element
           LaLIST < LaLIST<ElContact>::iterator >  & list_tesN
                                 = tesN_encontact((*iiE).Esclave()->Num_Mail())[(*iiE).Esclave()];
           list_tesN.remove(iiE);
           listContact.erase(iiE); // efface l'element
         };
    };
	   Tableau <int> compteur_inesc(nb_mail_Esclave,1); // compteur de compteur de noeuds esclaves
   
    // on initialise la liste des éléments en contact
//    listContact.clear(); // comme on redémarre, on efface la situation actuelle
    // non, il faut garder les éléments collants
    
    
    // --- on s'occupe du deuxième niveau de tesN_encontact
    // une map vide par défaut
    std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > > map_vide;
    tesN_encontact.Change_taille(nb_mail_Esclave,map_vide);

   
    for (int i=1;i<= taille;i++)
     {// on commence par créer un élément de contact de base en fonction des infos sauvegardées
	     // --- le noeud esclave
		    string toto; int numMail_esclave, numNoeud_esclave;
      string type;
	     int numMail_element, num_element, num_front_element;
		    Enum_type_geom enu ; string nom_enu; //N_es 1 72 El 2 2 SURFACE  1
	     ent >> toto >> numMail_esclave >> numNoeud_esclave  // le noeud esclave
		        >> type >>  numMail_element >> num_element   // partie relative à l'élément
		        >> enu  >> num_front_element; // et la frontière
		    // on ne continue que si le noeud fait partie des maillages esclave ou en auto-contact
		    // le nombre de maillages esclave et en auto-contact, peut-être redéfinit lors d'un restart
		    // donc n'est pas sauvegardé
		    if (numMail_esclave <= nb_mail_Esclave)
		     {	Noeud& no = (instance.*RecupNoeud)(numMail_esclave, numNoeud_esclave); // ""
				     // --- création de la frontière 
				     Element& elem = (instance.*RecupElement_LesMaille)(numMail_element,num_element);
				     ElFrontiere*  elfr;
				     switch (enu)
					    {  case POINT_G : elfr = elem.Frontiere_points(num_front_element,true) ; break;
						      case LIGNE : elfr = elem.Frontiere_lineique(num_front_element,true) ; break;
						      case SURFACE : elfr = elem.Frontiere_surfacique(num_front_element,true) ; break;
						      default :
							       cout << "\nErreur : valeur incorrecte du type de frontiere " << Nom_type_geom(enu) << " !\n";
							       cout << "LesContacts::Lec_base_info_LesContacts(... \n";
							       Sortie(1);
					    };
				     // création d'un Front
				     Front froont(*elfr,&elem,num_front_element);
         // froont ne contient pas forcément les éléments mitoyens, en particulier pour les élément d'angles morts
         // par contre il doit correspondre à un des éléments enregistrés dans t_listFront
         // on va donc le chercher dans t_listFront
         Front* froant=NULL; // le front que l'on cherche
         
         // ** pour le tableaux t_listFront, le numéros dit de maillage, n'est pas le numéro
         // ** intrinsèque de maillage (telle que ceux associés aux noeuds et éléments)
         // ** mais uniquement un numéro locale d'ordre
         // ** mais on a: les éléments de frontière de t_listFront(i) font partie du maillage
         // i + (nb_mail_Esclave-nbmailautocontact)
         int ii = numMail_element - (nb_mail_Esclave-nbmailautocontact);
         Tableau < LaLIST_io <Front> >& t_listFront_i = t_listFront(ii); // pour simplifier
         int nbzoneEt1 = 1+t_listFront_i.Taille();
         int num_zone = 0; // le numéro de zone éventuel
         bool trouver = false;
         for (int izone = 1; izone < nbzoneEt1;izone++)
          {LaLIST_io <Front>& t_listFront_i_izone = t_listFront_i(izone); // pour simplifier
           LaLIST_io <Front>::iterator it,itfin=t_listFront_i_izone.end();
           for (it = t_listFront_i_izone.begin();it != itfin; it++)
            {if ((*it).MemeOrigine(froont))
              {froant = &(*it);
               trouver = true;
               break;
              };
            };
           if (trouver)
            {num_zone=izone; break;}
          };
        // on vérifie que l'on a bien trouvé un front sinon, on signale
        if ((trouver == false) && (ParaGlob::NiveauImpression() > 0))
         {cout << "\n *** attention la frontiere de contact ";
          froont.Affiche(1);
          cout << " n'existe plus, on n'en tient plus compte ";
         };
        // même si l'élément n'existe plus
        // on continue la création pour ne pas corrompre la lecture
        // on créer un élément de contact ad hoc
        // création de l'élément de contact
				    ElContact courant(&froont,&no,fct_nD_contact);
				    // lecture des données particulières (qui ne contiennent pas les mitoyens)
				    courant.Lec_base_info_ElContact(ent);
        if (trouver)
          {// on met à jour les mitoyens
           // definition des elements mitoyens à partir du front enregistré qui lui contient les mitoyens
           // qui ont été créé à l'initialisation
           if (froant->TabMitoyen() != NULL)
             courant.Elfront()->DefMitoyen(*(froant->TabMitoyen()));
           // mis à jour du numéro de zone
           courant.Num_zone_contact() = num_zone;
           courant.Change_lissage_normale(lissage_de_la_normale(num_zone)); // affectation du lissage
           // sauvegarde si l'élément de contact n'existe pas déjà
           ElContact* test_existance= Element_contact_deja_present(courant);
           if (test_existance == NULL)
            {listContact.push_front(courant);
             LaLIST<ElContact>::iterator ipp = listContact.begin();
           // on met à jour le tableau tesN_encontact
      //*** la liste peut très bien ne pas exister !
  //         #ifdef MISE_AU_POINT
  //           if (tesN_encontact(numMail_esclave).find((*ipp).Esclave())
  //                 == tesN_encontact(numMail_esclave).end() )
  //            { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
  //                   << (*ipp).Esclave()->Num_noeud() << " du maillage " << numMail_esclave
  //                   << " la suite n'est pas possible "
  //                   << " LesContacts::Lec_base_info_LesContacts(.. \n";
  //              Sortie(1);
  //            };
  //         #endif
          
             // ajout dans la liste associé au noeud esclave
             tesN_encontact(numMail_esclave)[(*ipp).Esclave()].push_front(listContact.begin());
           };
         };
			    }	// fin de l'ajout d'un élément de contact
      else
       {if (ParaGlob::NiveauImpression() > 0)
          cout << "\n *** attention, le maillage "<<numMail_esclave<<" n'est plus esclave !"
               << " l'element de contact non pris en compte: "
               << "\n   N_es " <<numMail_esclave << " "<<numNoeud_esclave
               << type << " "<< numMail_element << " "<< num_element << " "
               << Nom_type_geom(enu) <<" "<<num_front_element;
       };
     };
    if (Permet_affichage()>4)
      // on va lister les éléments de contact
     { cout << "\n liste des Elcontact  (fct du niveau de commentaire des elcontact): ";
       LaLIST<ElContact>::iterator ipp,ippfin=listContact.end();
       for (ipp=listContact.begin();ipp != ippfin; ipp++)
         {(*ipp).Affiche(2);};
     };
    Calcul_Nb_contact_actif();
    if (((ParaGlob::NiveauImpression() > 2) && (nb_contact_actif != 0))
        || (niveau_commentaire_lescontacts > 0 )
       )
        cout << "\n >> restart: lecture elements contact : "<< nb_contact_actif << " elements lus " << endl ;
    string mot;
    ent >> mot >> tempsContact;
  };

     
 #endif   // fin du test d'inclusion : ifndef  LesContacts_2_deja_inclus



