// FICHIER : ReferenceAF.cp
// CLASSE : ReferenceAF


#include "ReferenceAF.h"
#include "PtTabRel.h"

#ifndef  REFERENCEAF_H_deja_inclus

#ifndef MISE_AU_POINT
  inline 
#endif
// Constructeur par defaut (appel au constructeur par defaut de Tableau<T>)
ReferenceAF::ReferenceAF (string nom):
 Reference(nom),tab_Elem(),tab_FA() 
    { };

    
#ifndef MISE_AU_POINT
  inline 
#endif
// Constructeur fonction  du nb de maillage et du type de ref		
ReferenceAF::ReferenceAF (int nb , int ind) :
  Reference(nb,ind),tab_Elem(),tab_FA() 
   { };
   
#ifndef MISE_AU_POINT
  inline 
#endif
// Constructeur fonction  de deux  tableaux de numeros, le premier pour les numéros
// d'éléments le second pour les numéros de faces, d'aretes, de noeud d'element,  ou de point d'integ
// du nb de maillage, du type de ref
ReferenceAF::ReferenceAF (const Tableau<int>& tabelem,const Tableau<int>& tab
		             ,int nbmaille , int indic, string nom):
  Reference(nom,nbmaille,indic),tab_Elem(tabelem),tab_FA(tab) 
       { };


#ifndef MISE_AU_POINT
  inline 
#endif
// Constructeur fonction  de deux listes de numeros, la première pour les numéros
// d'éléments la seconde pour les numéros de faces, d'aretes, de noeud d'element,  ou de point d'integ
// du nb de maillage, du type de ref
ReferenceAF::ReferenceAF (const list <int>& list_elem,const list <int>& list_num
		             ,int nbmaille , int indic, string nom):
  Reference(nom,nbmaille,indic),tab_Elem(list_elem.size()),tab_FA(list_num.size()) 
	{ int tail = tab_Elem.Taille();
	  list <int>::const_iterator it=list_elem.begin();
	  for (int i=1;i<= tail;i++,it++)
	    tab_Elem(i)=(*it);
	  tail = tab_FA.Taille(); it = list_num.begin();	 
	  for (int i=1;i<= tail;i++,it++)
	    tab_FA(i)=(*it);
	}; 

#ifndef MISE_AU_POINT
  inline 
#endif
// Constructeur utile si le nom de la reference est connu 
ReferenceAF::ReferenceAF (string nom,int nb , int ind) :
  Reference(nom,nb,ind),tab_Elem(),tab_FA()
       { };


#ifndef MISE_AU_POINT
  inline 
#endif
// Constructeur de copie 
ReferenceAF::ReferenceAF (const ReferenceAF& ref):
    Reference (ref),tab_Elem(ref.tab_Elem),tab_FA(ref.tab_FA)
       { };
	
// Destructeur 
#ifndef MISE_AU_POINT
  inline 
#endif
ReferenceAF::~ReferenceAF ()
      { };

//================== METHODES : ================================
		
#ifndef MISE_AU_POINT
  inline 
#endif
Reference& ReferenceAF::operator= (const Reference& ref)
   {  *this = this->Reference::operator=(ref); // pour la partie de la classe mère
      #ifdef MISE_AU_POINT
        // vérification du type de ref
        if ((ref.Indic() != 3) && (ref.Indic() != 4)&& (ref.Indic() != 5)&& (ref.Indic() != 6))
          {if (ParaGlob::Francais()) 
			   {cout << " \n erreur dans l'affectation de reference : ReferenceAF::operator= (const Reference& ref)"
                  << "\n  la reference ref n'est ni celle de face, d'arete, de noeud d'element  "
                  << " ou de pt d'integ ";
					}
			  else  
				{cout << " \n error in the operator of reference : ReferenceAF::operator= (const Reference& ref)"
                  << "\n  the reference ref is not a reference of a face, an edge, a node   "
                  << " or a gauss point  ";
					};
			 };
      #endif  
      tab_Elem = ((ReferenceAF&) ref).tab_Elem;	
      tab_FA = ((ReferenceAF&) ref).tab_FA;	
	  return (*this);
    };



// change un numéro i de référence
// nbe: le numéro d'élément, nbAF: le numéro de de faces, ou d'arêtes, ou de noeud d'element,
//       ou de points d'integ
#ifndef MISE_AU_POINT
  inline 
#endif
void ReferenceAF::Change_num_AF_dans_ref(int i,int nbe, int nbAF)
  { if ((i < 1)|| (i>tab_Elem.Taille()))
     { cout << "\n *** erreur de changement de numero dans la reference : " << this->Nom()
            << "\n le numero demande est le " << i << " ce qui est en dehors des valeurs possibles "
            << " qui doivent etre comprises entre 1 et "<<tab_Elem.Taille()<< " on affiche la ref actuelle : ";
       this->Affiche();
       Sortie(1);
     };
    tab_Elem(i)=nbe;tab_FA(i)= nbAF;
  };

// change les 2 tableaux de la ref	
#ifndef MISE_AU_POINT
  inline 
#endif
void ReferenceAF::Change_tab_num(const Tableau<int>& tabele,const Tableau<int>& tab)
  { // on vérifie que les deux tableaux ont la même taille
    if (tabele.Taille() != tab.Taille())
     { cout << "\n *** erreur de changement des deux tableaux dans la reference : " << this->Nom()
            << "\n les tailles des deux tableaux sont differentes: taille des elements="<< tabele.Taille()
            << ", taille du second tableau =" << tab.Taille() << " on affiche la ref actuelle : ";
       this->Affiche();
       Sortie(1);
     };
    tab_Elem=tabele;
    tab_FA= tab;
  };

// Affiche les donnees liees a la reference
#ifndef MISE_AU_POINT
  inline 
#endif
// indique si le numéro d'élément et le numéro de faces, d'arête ou de noeud d'élément 
// ou de pt d'integ passé  en argument, fait partie de la référence
// nbe: le numéro d'élément, nbAF: le numéro de face, d'arête, de noeud d'element ou de pt d'integ
bool ReferenceAF::Contient_AF(int nbe, int nbAF) const 
 { int tail_tab=tab_Elem.Taille();
   for (int i=1;i<= tail_tab;i++)
     if ((tab_Elem(i)==nbe) && (tab_FA(i)==nbAF)) return true;
   return false;  
  };      
		
// Affiche les donnees liees a la reference
#ifndef MISE_AU_POINT
  inline 
#endif
void ReferenceAF::Affiche () const 
		{ // affichage du type de référence
		  if (indic == 3) 
		     { if (ParaGlob::Francais()) {cout << "\n reference de face d'element";}
			    else {cout << "\n reference of an element face ";};}
		  else if (indic == 4)
		     { if (ParaGlob::Francais()) {cout << "\n reference d'arete d'element";}
			    else {cout << "\n reference of an element edge ";};}
		  else if (indic == 5)
		     { if (ParaGlob::Francais()) {cout << "\n reference de noeud d'element";}
			    else {cout << "\n reference of node ";};}
		  else if (indic == 6)
		     { if (ParaGlob::Francais()) {cout << "\n reference de pt d'integ d'element";}
			    else {cout << "\n reference of a gauss point ";};}
    else if (indic == 7)
       { if (ParaGlob::Francais()) {cout << "\n reference de pt d'integ relatif a une face d'element";}
       else {cout << "\n reference of a gauss point for a facet of an element ";};}
    else if (indic == 8)
       { if (ParaGlob::Francais()) {cout << "\n reference de pt d'integ relatif a une arete d'element";}
       else {cout << "\n reference of a gauss point for an edge of an element";};}
		  else   
		     { if (ParaGlob::Francais()) {cout << "\n reference de type non defini ";}
			    else {cout << "\n reference not defined ";};}
		  // affichage pour la partie de la classe mère
		   this->Reference::Affiche();
		   // partie spécifique
			if (ParaGlob::Francais()) {cout << "Taille des tableaux : " ;}
			else {cout << "size of the  tab : " ;};
			cout << tab_Elem.Taille() << " .\n";
			if (ParaGlob::Francais()) 
			  {cout << "Composante(s) (1 element puis une face ou arete ou noeud ou pt integ ):\n\t[  ";}
			else 
			  {cout << "Components(s) (1 element then one face or edge or node or gauss point ):\n\t[  ";};
			for (int i=1;i<=tab_Elem.Taille();i++)
				cout << tab_Elem(i) << "  "<< tab_FA(i) << "  ";
			cout << "]\n\n";
		};

// supprime les doublons internes éventuels dans la référence
#ifndef MISE_AU_POINT
  inline 
#endif
void ReferenceAF::Supprime_doublons_internes()
{ //Tableau<int> tab_Elem; // tableau des numeros des éléments de la reference
		//Tableau<int> tab_FA; // tableau des numeros des faces ou arêtes de la reference
		                     // ou noeud d'element, ou de points d'intégrations d'élément
  int taille = tab_Elem.Taille();
  list <int> agarder; // contiendra les seules numéros à sauvegarder
  for (int i=1;i<=taille;i++)
   { bool bon=true;
     for (int j=i+1;j<=taille;j++)
       if ((tab_Elem(i)==tab_Elem(j))&& (tab_FA(i)==tab_FA(j)))
          {bon=false;
           if (ParaGlob::NiveauImpression() > 3)
            { cout << "\n *** attention suppression doublon: ref "<<nom_ref
                   << " maillage:"<<nbmaille<<" element " << tab_Elem(i)
                   << " face/arrete.. "<< tab_FA(i)<<endl;
            };
           break;
           } // cas d'un doublon
     if (bon)
       agarder.push_back(i);
   };
  int new_taille = agarder.size();
  // on modifie la liste initiale si la nouvelle taille est différente
  if (new_taille != taille)
    {list <int>::iterator ili,ilifin = agarder.end();
     int position=1;
     for (ili=agarder.begin();ili!=ilifin;ili++,position++)
        {tab_Elem(position) = tab_Elem(*ili); //position est toujours < *ili donc on écrase a partir du bas
         tab_FA(position) = tab_FA(*ili); // et tab_Elem(*ili) et tab_FA(*ili) sont toujours valides
        };
     // on supprime les données de new_taille à taille
     tab_Elem.Change_taille(new_taille);
     tab_FA.Change_taille(new_taille);
    };
};
    
// lecture d'une liste de references pt d'integ, ou de noeud, ou arêtes ou faces  d'éléments
#ifndef MISE_AU_POINT
  inline 
#endif
bool ReferenceAF::LectureReference(UtilLecture & entreePrinc)
 {   *(entreePrinc.entree) >> nom_ref; // lecture d'une reference
	 // si l'on est à la fin de la ligne on passe à la ligne suivante
	 //cout << "\n rdstate " << entreePrinc.entree->rdstate() << endl;
     if ((entreePrinc.entree->eof() != 0) && (!(entreePrinc.entree->fail())))
          {   entreePrinc.NouvelleDonnee(); }
     // on utilise une liste pour la lecture, ce qui permet de lire une nombre quelconque 
     // de numéros attachés à une référence
     list <Reels2> inter; // on utilise des réels car c'est déjà défini par ailleurs
     // mais cela n'a aucune importance sur le traitement
     int il;
     
     if ((entreePrinc.entree->rdstate() != 0) 
          && (!motCle.SimotCle(entreePrinc.tablcar)))
         // si le buffer ne contiend pas de mot cle et qu'il y a un  
         //  pb de lecture ( donc pas de def de reference)
       { if (ParaGlob::Francais()) 
				 {cout << " \n Erreur de lecture de reference \n contenu du buffer = ";}
			else {cout << " \n Error of reference reading \n  buffer = ";};
			cout << entreePrinc.tablcar << endl;
         if (ParaGlob::Francais())
			 {entreePrinc.MessageBuffer
             ("lecture d une  reference de face ou d'arete ou de noeud d'element ou de pt d'integ"); }                                  
			else  
			 {entreePrinc.MessageBuffer
             ("reading of a reference of face or edge or node or gauss point "); };                                  
         throw (UtilLecture::ErrNouvelleDonnee(-1));
         Sortie (1);
       } 
     else if (motCle.SimotCle(entreePrinc.tablcar))
       { // fin de la lecture de reference
         // remise correcte du flot
         entreePrinc.FlotDebutDonnee();
         return false;    
       }  
     else 
     {
          // cas ou on a bien lu un nom de reference
        { 
          il = 0; // nb de nb d'entier lu
          bool fin = false;
          // les deux cas qui font sortir de la boucle sont l'apparition
          // d'un mot cle ou une erreur en lecture dans entier
          // apres une bonne lecture sur la meme ligne
          bool aumoinsune = true;
          bool prem = true; // ne sert que pour le cas d'une reference sans numero
          while ( (!fin) & aumoinsune)
           {aumoinsune = false;
            // def du maillon à lire dans la liste
            Reels2 as1;
  //          while (!entreePrinc.entree->rdstate()) // lecture tant qu'il n'y a pas d'erreur
            while ((!entreePrinc.entree->rdstate())&& // lecture tant qu'il n'y a pas d'erreur
                        (!(entreePrinc.entree->eof())))
             { // lecture de deux entiers mis dans deux réels      
              *(entreePrinc.entree) >> as1.donnees[0] ;
              // si jamais on est à la fin d'une ligne on passe à la ligne suivante
              if (entreePrinc.entree->eof())
               {
                #ifdef ENLINUX
                 if (!(entreePrinc.entree->bad()))
                // on continue que si le flot est correcte car en linux il s'apperçoit du pb
                // qu'après la mauvaise lecture, c'est-à-dire eof() ne fonctionne pas correctement
                   { break; }
                #endif  
 /*              #ifdef SYSTEM_MAC_OS_X_unix
                 if (!(entreePrinc.entree->bad()))
                // on continue que si le flot est correcte car en linux il s'apperçoit du pb
                // qu'après la mauvaise lecture, c'est-à-dire eof() ne fonctionne pas correctement
                   { break; }
                #endif  */
                 entreePrinc.NouvelleDonnee();  // lecture d'une nouvelle ligne
                 }  
              *(entreePrinc.entree) >> as1.donnees[1]; 
             // pour la verif
             // pour mémoire ici on a 
           /*       enum io_state
                    {  badbit   = 1<<0, // -> 1 dans rdstate()
                       eofbit   = 1<<1, // -> 2 
                       failbit  = 1<<2, // -> 4 
                       goodbit  = 0     // -> O 
                     };*/
//              if ((entreePrinc.entree->rdstate() == 0)||
//                  (entreePrinc.entree->eof() ))
             #ifdef ENLINUX
               if (entreePrinc.entree->rdstate() == 0)
             #else
    /*          #ifdef SYSTEM_MAC_OS_X_unix
               if (entreePrinc.entree->rdstate() == 0)
              #else*/
               if (((entreePrinc.entree->rdstate() == 0)||
                  (entreePrinc.entree->eof()))&&(!(entreePrinc.entree->bad()))
                  &&(!(entreePrinc.entree->fail())))
    //          #endif     
             #endif     
                 {il++;
                  aumoinsune = true;
                  prem = false;
                  inter.push_back(as1); 
                  }
             }
             
            if ((aumoinsune) || prem )                      
             {entreePrinc.NouvelleDonnee();  // lecture d'une nouvelle ligne
              if (motCle.SimotCle(entreePrinc.tablcar)) 
                // c'est un mot cle
                fin = true;
              }
            else
              // remise correcte du flot pour la lecture
              //d'une prochaine reference
              entreePrinc.FlotDebutDonnee();
            }
          if (il == 0 )
            { if (ParaGlob::Francais()) {cout << "\n WARNING : aucun numero attache a la reference = ";}
				  else                      {cout << "\n WARNING : no number linked to the reference = ";};
				  cout << nom_ref << endl;
             }
          // transfert dans les tableaux            
          tab_Elem.Change_taille(il);
          tab_FA.Change_taille(il);
          listdouble2Iter b; int a;
          for (b=inter.begin(),a=1 ;b != inter.end();b++,a++)
            { tab_Elem(a) = (int) (b->donnees[0]); // transformation en entier
              tab_FA(a) = (int) (b->donnees[1]); // transformation en entier
             } 
          return true;
         }
      }
    return false;      
    };
    
// affichage et definition interactive des commandes 
// nbMaxi: nombre maxi de noeud ou 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
#ifndef MISE_AU_POINT
  inline 
#endif
void ReferenceAF::Info_commande_Ref(int nbMaxi,UtilLecture * entreePrinc,int cas)
 { ofstream & sort = *(entreePrinc->Commande_pointInfo()); // pour simplifier
   if (cas == 1)
     { if (ParaGlob::Francais()) {cout << "\n erreur: cas = "; }
	    else { cout << "\n error: case = "; };
	    cout << cas << "\n ReferenceAF::Info_commande_Ref(....";
       Sortie(1);      
      }
   else       
     { if (indic ==3) // cas d'une ref de surface d'élément
         { if (ParaGlob::Francais()) 
			          {sort << "\n #    -- exemple de reference de face d'element";}
			        else {sort << "\n #    -- exemple of a reference of an element face ";};
           cout << "\n F_tout  ";
           int compteur_ligne=0;
           for (int n1=1;n1<= nbMaxi;n1++,compteur_ligne++)
            { if (compteur_ligne > 10) 
               { compteur_ligne = 0; sort << "\n";}
              sort << setw (6) << n1 << setw (6)<< 1 <<" ";
             }
           sort << "\n \n";
          } 
       else if (indic ==4) // cas d'une ref d'arete  d'élément  
         { if (ParaGlob::Francais()) 
			          { sort << "\n #    -- exemple de reference d'arete d'elements ";}
			        else {sort << "\n #    -- exemple of a reference of an element edge ";};
           cout << "\n A_tout  ";
           int compteur_ligne=0;
           for (int n1=1;n1<= nbMaxi;n1++,compteur_ligne++)
            { if (compteur_ligne > 10) 
               { compteur_ligne = 0; sort << "\n";}
              sort << setw (6) << n1 << setw (6)<< 1<<" ";
             }
           sort << "\n \n";
         }
       else if (indic ==5) // cas d'une ref de noeuds  d'élément  
         { if (ParaGlob::Francais()) 
			         { sort << "\n #    -- exemple de reference de noeuds d'elements ";}
			        else {sort << "\n #    -- exemple of a reference of an element node ";};
           cout << "\n P_tout  ";
           int compteur_ligne=0;
           for (int n1=1;n1<= nbMaxi;n1++,compteur_ligne++)
            { if (compteur_ligne > 10) 
               { compteur_ligne = 0; sort << "\n";}
              sort << setw (6) << n1 << setw (6)<< 1<<" ";
             }
           sort << "\n \n";
         }
       else if (indic ==6) // cas d'une ref de pt d'integ  d'élément  
         { if (ParaGlob::Francais()) 
			          { sort << "\n #    -- exemple de reference de point d'integration d'elements ";}
			        else {sort << "\n #    -- exemple of a reference of an element gauss point ";};
           cout << "\n G_tout  ";
           int compteur_ligne=0;
           for (int n1=1;n1<= nbMaxi;n1++,compteur_ligne++)
            { if (compteur_ligne > 10) 
               { compteur_ligne = 0; sort << "\n";}
              sort << setw (6) << n1 << setw (6)<< 1<<" ";
             }
           sort << "\n \n";
         }

       else if (indic ==7) // cas d'une ref de pt d'integ  de face d'élément
         { if (ParaGlob::Francais())
            { sort << "\n #    -- exemple de reference de point d'integration de face d'elements "
                   << "\n nb_elem nb_face nb_pti " ;}
           else {sort << "\n #    -- exemple of a reference of Gauss point for an element facet "
                      << "\n nb_elem nb_facet nb_Gauss ";};
           cout << "\n P_tout  ";
           int compteur_ligne=0;
           for (int n1=1;n1<= nbMaxi;n1++,compteur_ligne++)
            { if (compteur_ligne > 10)
               { compteur_ligne = 0; sort << "\n";}
              sort << setw (6) << n1 << setw (6)<< 1 << setw (6)<< 1 <<" ";
            };
           sort << "\n \n";
         }
       else if (indic ==8) // cas d'une ref de pt d'integ  d'arête d'élément
         { if (ParaGlob::Francais())
            { sort << "\n #    -- exemple de reference de point d'integration d'arete d'elements "
                   << "\n nb_elem nb_arete nb_pti " ;}
           else {sort << "\n #    -- exemple of a reference of Gauss point for an element edge "
                      << "\n nb_elem nb_edge nb_Gauss ";};
           cout << "\n L_tout  ";
           int compteur_ligne=0;
           for (int n1=1;n1<= nbMaxi;n1++,compteur_ligne++)
            { if (compteur_ligne > 10)
               { compteur_ligne = 0; sort << "\n";}
              sort << setw (6) << n1 << setw (6)<< 1 << setw (6)<< 1<<" ";
            };
           sort << "\n \n";
         }
      }
  };           	                 

//----- 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)
#ifndef MISE_AU_POINT
  inline 
#endif
void ReferenceAF::Lecture_base_info(ifstream& ent,const int cas)
 { // ici a priori il n'y a pas de de données supposées variables
   if (cas == 1)
      {
      // appelle de la méthode de la classe mère
        Lect_int_base_info(ent);    
      // lecture des deux tableaux d'entiers qui ont la même taille
        int tab_FATaille; string toto;
        ent >> toto >> tab_FATaille;
        tab_Elem.Change_taille(tab_FATaille);
        tab_FA.Change_taille(tab_FATaille);
        for (int i=1;i<= tab_FATaille; i++)
          ent >> tab_Elem(i) >> tab_FA(i) ;
       };
  };     
        // cas donne le niveau de sauvegarde
        // = 1 : on sauvegarde tout
        // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
#ifndef MISE_AU_POINT
  inline 
#endif
void ReferenceAF::Ecriture_base_info(ofstream& sort,const int cas)
 { // ici a priori il n'y a pas de de données supposées variables
   if (cas == 1)
      {
      // appelle de la méthode de la classe mère
        Ecrit_int_base_info(sort);    
      // écriture des deux tableau d'entier, normalement ils ont la même taille
        int tab_FATaille = tab_FA.Taille();
        #ifdef MISE_AU_POINT
        if ( tab_FATaille != tab_Elem.Taille())
          { if (ParaGlob::Francais()) 
			       {cout << " \n erreur, les deux tableaux ont une taille differente : ";}
				else {cout << " \n error, the two tabs have not the same size : ";};
            cout << tab_FATaille << "  " << tab_Elem.Taille();
            Sortie(1);     
           }
        #endif 
        sort << "tailleAF " << tab_FATaille << "  ";
        for (int i=1;i<= tab_FATaille; i++)
          sort << tab_Elem(i) << "  " << tab_FA(i) << "  ";
        sort << "\n";  
       };
  };     
                
#ifndef MISE_AU_POINT
  inline 
#endif
// Affiche les donnees des références dans le flux passé en paramètre
void ReferenceAF::Affiche_dans_lis(ofstream&  sort) const  
  { int taille_tab= tab_Elem.Taille();
    // dans le cas où il n'y a pas de numéro associé à la référence on ne l'écrit pas
    if (taille_tab > 0 )
       { sort << "\n" << setw (6) << nom_ref << " ";
         int nb_par_ligne=20;
         for (int i=1,nb_p_l=1;i<=taille_tab;i++,nb_p_l++)
           { if(nb_p_l > nb_par_ligne) 
                { nb_p_l=1; sort << "\n";}
             sort << tab_Elem(i) << " " << tab_FA(i) << " ";
            };
         sort << "\n";
       }
  #ifdef MISE_AU_POINT
    else if (ParaGlob::NiveauImpression() > 1)
     { cout << "\n attention: ref "<<nom_ref <<" sans numero associe, on ne la sauvegarde pas ";}
  #endif
   };


			
#endif
