// 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 "Mail_initiale_vrml.h"

#include <iomanip>
#include <limits>

    // CONSTRUCTEURS :
// par defaut
Mail_initiale_vrml::Mail_initiale_vrml () :
   OrdreVisu(".................................maillage initiale"
             ,"visualisation des maillages initiaux","mi")
   ,filaire(true),surface(true),numero(false)
   ,Rcoull(0.0),Gcoull(0.0),Bcoull(1.0)
   ,Rcoulf(0.0),Gcoulf(1.0),Bcoulf(0.0)
   ,Rcouln(1.0),Gcouln(0.0),Bcouln(0.0)
   ,taille_numero(0.2)
     {}; 
     
     // constructeur de copie 
Mail_initiale_vrml::Mail_initiale_vrml (const Mail_initiale_vrml& ord) :
    OrdreVisu(ord),filaire(ord.filaire) 
   ,surface(ord.surface),numero(ord.numero)
   ,Rcoull(ord.Rcoull),Gcoull(ord.Gcoull),Bcoull(ord.Bcoull)
   ,Rcoulf(ord.Rcoulf),Gcoulf(ord.Gcoulf),Bcoulf(ord.Bcoulf)
   ,Rcouln(ord.Rcouln),Gcouln(ord.Gcouln),Bcouln(ord.Bcouln)
   ,taille_numero(ord.taille_numero)
      {};
               
    // DESTRUCTEUR :
Mail_initiale_vrml::~Mail_initiale_vrml () 
     {};  
    
    // METHODES PUBLIQUES :
// execution de l'ordre
// tab_mail : donne les numéros de maillage concerné
// incre : numéro d'incrément qui en cours
// type_incre : indique si c'est le premier le dernier ou l'incrément courant a visualiser ou pas
// animation : indique si l'on est en animation ou pas
// unseul_incre : indique si oui ou non il y a un seul increment à visualiser
void Mail_initiale_vrml::ExeOrdre(ParaGlob * paraGlob,const Tableau <int>& tab_mail,LesMaillages * lesMail,bool ,LesReferences*
                      ,LesLoisDeComp* ,DiversStockage*,Charge*,LesCondLim*
//                      ,LesContacts*,Resultats*,ostream & sort,EnumTypeIncre type_incre,int incre
                      ,LesContacts*,Resultats*,UtilLecture & entreePrinc,OrdreVisu::EnumTypeIncre ,int incre
//                      ,bool animation)
                      ,bool,const map < string, const double * , std::less <string> >&
                      ,const List_io < TypeQuelconque >& listeVecGlob)
 {ostream &sort = entreePrinc.Sort_princ_vrml();
  // visualisation du maillage pointé si actif
  if ((actif)&&(incre==0))
  {
   // on boucle sur les maillages
   int nbmail = tab_mail.Taille();
   for (int im=1;im<=nbmail;im++)
    { int numMail=tab_mail(im);
      // on commence par définir la liste des points 
       {
         // def de l'entité forme
         sort << "\n Shape { "
           << "\n  appearance Appearance {}";
         // création des points
         // tout d'abord le nom
         ostrstream tab_out;
         tab_out << "Coordinates-0" << numMail << ends;
         string nom_coordinate = tab_out.str() ;  // le nom
         // on utilise une géométrie de face indexée bien qu'aucune face soit définit 
         sort << "\n  geometry IndexedFaceSet {"
              << "\n     coord DEF " << nom_coordinate <<  " Coordinate {"
              << "\n                   point [ ";
         // on balaie tous les noeuds du maillage
         int nbmaxinoeud = lesMail->Nombre_noeud(numMail);
         for (int numNoeud=1; numNoeud<= nbmaxinoeud;numNoeud++) 
               { // recup du noeud
                 Noeud & noe = lesMail->Noeud_LesMaille(numMail,numNoeud);
                 // ecriture des coordonnee à 0 
                 sort <<"\n                        "
                      << setw (16);  noe.Coord0().Affiche(sort,16);
                 // si l'on n'est pas en dimension 3 on complete avec des zeros
                 if (paraGlob->Dimension () == 2)
                   { sort << setw (16) << 0 <<" ";
                    }
                 else if (paraGlob->Dimension () == 1)
                    { sort << setw (16) << 0  <<" " << setw (16) << 0  <<" ";
                    }
                 sort <<  " , ";
                 }
          // fermeture du groupe point, coordinate, de la géométrie et de la forme
          sort << "\n                     ] } } }";
         } 
      if (surface) // cas d'une visualisation par face
       { 
         // def de l'entité forme
         sort << "\n Shape { "
           << "\n   appearance Appearance {}";
         // définition de la forme géométrique
         sort << "\n   geometry IndexedFaceSet {"
         // utilisation des points définis
              << "\n      coord USE Coordinates-0" << numMail; 
          // définition de la couleur
          sort << "\n                 color Color {"
               << "\n                     color ["
               << "\n                       " 
               << Rcoulf << " " << Gcoulf << " " << Bcoulf<< " ,"
               << "\n                     ]"
               << "\n                 }";
          // def des arrêtes
          sort << "\n                 coordIndex [";
          // un compteur qui globalise le nombre de facette dessinée
          int nbfacette=0;     
             // on balaie tous les éléments du maillage
          int nbmaxiElement = lesMail->Nombre_element(numMail);
          for (int numElem=1; numElem<= nbmaxiElement;numElem++) 
           { // recup de l'élément
             Element & elem = lesMail->Element_LesMaille(numMail,numElem);
             Tableau<Noeud *>& tab_noeud = elem.Tab_noeud (); // ses noeuds
             // connection des noeuds des faces par rapport a ceux de l'element
             // en fait on utilise une décomposition triangulaire linéaire de chaque facette
             // on récupère donc tout d'abord ces informations
                // le tableau des triangles linéaire
             const Tableau<Tableau<Tableau<int> > >&  
                        tabtria = elem.ElementGeometrique().Trian_lin();
             // le nombre de face à visualiser           
             int nb_FA = tabtria.Taille();
             for (int k=1;k<= nb_FA;k++)
              { sort << "\n                    "; //début de la face
                // nombre de triangle de la face
                int nbtriangle = tabtria(k).Taille();
                for (int ikt=1;ikt<=nbtriangle;ikt++,nbfacette++)
                 { //const Tableau<int> * tabn = &(tabtria(k)(ikt)); // pour simplifier
                   #ifdef MISE_AU_POINT
                   // vérification du nombre de noeud du triangle
                    if (tabtria(k)(ikt).Taille() != 3)
                      { cout << "\n erreur, les facettes n'ont pas 3 noeuds,"
                             << " nbnoeud = " << tabtria(k)(ikt).Taille()
                             << " \n Mail_initiale_vrml::ExeOrdre(... " ;
                        Sortie(1);     
                       }
                   #endif
                   for (int no = 1; no<=3; no++)
                       sort << (tab_noeud(tabtria(k)(ikt)(no))->Num_noeud() - 1) << ", "; 
                   sort << "-1, "; 
                  }
                }
              }
          // fin pour les faces et activation de la couleur
          sort << "\n                ]";
          sort << "\n               colorIndex [ ";
          // le tableau des couleurs ici identique
          int ic; // un compteur inter pour qu'il y ait plusieurs numéros sur la même ligne
          int icmax = 10; int nf;
          for (nf=1,ic=1; nf< nbfacette;nf++,ic++) 
             { sort << " 0,"; 
               if (ic >= icmax) { ic = 1; sort << "\n";} // pour limiter la ligne
               }
          sort << " 0 ]"; // la dernière couleur
          // on signale que l'on veut voir que l'extérieur
          sort << "\n                solid TRUE";
          // ON signal que l'on tourne dans le sens positif géométrique
          sort << "\n                ccw TRUE";
          // et que les faces sont convexes
          sort << "\n                convex TRUE";
          // que l'on utilise une couleur par face
          sort << "\n       colorPerVertex FALSE";
          sort << "\n            }";
          // fin: on ferme l'entité forme
          sort << "\n         }";
         }
      if (filaire)
       { 
         // def de l'entité forme
         sort << "\n Shape { "
           << "\n   appearance Appearance {}";
         // définition de la forme géométrique 
         sort << "\n   geometry IndexedLineSet {"
         // utilisation des points définis
              << "\n      coord USE Coordinates-0" << numMail; 
          // définition de la couleur
          sort << "\n                 color Color {"
               << "\n                     color ["
               << "\n                       " 
               << Rcoull << " " << Gcoull << " " << Bcoull<< " ,"
               << "\n                     ]"
               << "\n                 }";
          // def des arrêtes
          sort << "\n                 coordIndex [";
          // def d'un compteur du nombre d'arrete dessiné
          int nbarr = 0;
             // on balaie tous les éléments du maillage
          int nbmaxiElement = lesMail->Nombre_element(numMail);
          for (int numElem=1; numElem<= nbmaxiElement;numElem++) 
           { // recup de l'élément
             Element & elem = lesMail->Element_LesMaille(numMail,numElem);
             Tableau<Noeud *>& tab_noeud = elem.Tab_noeud (); // ses noeuds
             // connection des noeuds des arêtes par rapport a ceux de l'element
             Tableau<Tableau<int> > const & nomS =  elem.ElementGeometrique().NonS();
             int nb_ar = nomS.Taille(); // nombre d'arrêtes
             for (int k=1;k<= nb_ar;k++,nbarr++)
              { sort << "\n                    "; //début de l'arrête 
                Tableau<int>const & tabn = nomS(k); 
                int nb_no = tabn.Taille(); // le nb de noeud de l'arrête
                for (int no = 1; no<=nb_no; no++)
                  sort << (tab_noeud(tabn(no))->Num_noeud() - 1) << ", "; 
                sort << " -1,"; 
                }
              }
          // fin pour les arrêtes et activation de la couleur
          sort << "\n                ]";
          sort << "\n               colorIndex [ ";
           // le tableau des couleurs ici identique
          int ic; // un compteur inter pour qu'il y ait plusieurs numéros sur la même ligne
          int na; int icmax = 10;
          for (na=1,ic=1; na< nbarr;na++,ic++) 
             { sort << " 0,"; 
               if (ic >= icmax) { ic = 1; sort << "\n";} // pour limiter la ligne
               }
          sort << " 0 ]"; // la dernière couleur
          sort << "\n                colorPerVertex FALSE";
          sort << "\n            }";
          // fin: on ferme l'entité forme
          sort << "\n         }";
         }                         
      if (numero) // cas d'une des numéros
       { 
         // on balaie tous les noeuds du maillage
         int nbmaxinoeud = lesMail->Nombre_noeud(numMail);
         for (int numNoeud=1; numNoeud<= nbmaxinoeud;numNoeud++) 
               { // recup du noeud
                 Noeud & noe = lesMail->Noeud_LesMaille(numMail,numNoeud);
                 // définition de l'entité billboard qui permet que les numéros restent faces
                 // à l'utilisateur
       //          sort << "\n Billboard { axisOfRotation 0.0 0.0 0.0       children [ ";
                 // on définit un ensemble de déplacement qui permet de ce positionner
                 // aux coordonnées des noeuds 
                 sort << "\n        Transform {  #           X   Y   Z ";
                  // ecriture des coordonnee à 0 
                 sort <<"\n              translation "
                      << setw (16);  noe.Coord0().Affiche(sort,16);
                 // si l'on n'est pas en dimension 3 on complete avec des zeros
                 if (paraGlob->Dimension () == 2)
                   { sort << setw (16) << 0 <<" ";
                    }
                 else if (paraGlob->Dimension () == 1)
                    { sort << setw (16) << 0  <<" " << setw (16) << 0  <<" ";
                    }
                 // on définit le numéro
                  sort   << "\n                children [";
                 // def de l'entité forme
                 sort << "\n          Shape { "
                   << "\n                appearance Appearance {"
                   << "\n                  material Material { }"
                   << "\n                             }";
                 // le numéro 
                 sort << "\n             geometry Text {"
                      << "\n             string \"" << numNoeud <<"\""
                      << "\n               fontStyle FontStyle {size " << taille_numero << " } "
                      << "\n                 }} ] }";
                 // on ferme le billboard  et la forme générale       
       //          sort << "\n             ]}";        
                 }
         }
    }; //-- fin de la boucle sur les maillages
   // et on vide le buffer de sortie
   sort << endl; 
  };//-- fin du test d'actif

 };

// choix de l'ordre, cet méthode peut entraîner la demande d'informations
// supplémentaires si nécessaire. qui sont ensuite gérer par la classe elle même
void Mail_initiale_vrml::ChoixOrdre()
   { // demande de précision
     bool choix_valide = false;
     while (!choix_valide)
      { // tout d'abord on met le choix valide a priori
        choix_valide = true;
        cout << "\n ----> preparation de la visualisation du maillage initiale"
             << "\n  parametre par defaut ? : affichage en filaire, couleur bleu,"
             << "\n                           et  affichage des facettes, couleur vert,"
             << " \n                          pas d'affichage de numeros. "
             << "   (rep 'o') pour accepter ces parametres sinon autre ";
        string rep;
        cout << "\n reponse ? "; rep = lect_return_defaut(true,"o");
        if (rep != "o") 
          { // cas du filaire 
            cout << "\n en fillaire (par defaut rep 'o') "
                 << "ou pas de filaire (rep autre) ? "; 
            rep = lect_return_defaut(true,"o");
            if (rep!= "o")
              {  choix_valide = choix_valide && true;
                 filaire = false;
               }
            else 
              { choix_valide = choix_valide && true;
                filaire = true;
               }
            // cas des face 
            cout << "\n affichage des facettes (par defaut rep 'o') "
                 << "ou pas de facette (rep autre) ? "; 
            rep = lect_return_defaut(true,"o");
            if (rep!= "o")
              {  choix_valide = choix_valide && true;
                 surface = false;
               }
            else 
              { choix_valide = choix_valide && true;
                surface = true;
               }
            // cas des numéros 
            cout << "\n affichage des numeros (non par defaut  rep 'o') "
                 << "ou on veut l'affichage des numeros (rep autre) ? "; 
            rep = lect_return_defaut(true,"o");
            if (rep!= "o")
              {  choix_valide = choix_valide && true;
                 numero = true;
               }
            else 
              { choix_valide = choix_valide && true;
                numero = false;
               }
            // puis choix de la taille des numéros   
            cout << "\n taille des numeros (non par defaut 0.2 rep 'o') "
                 << "ou autre taille (rep autre) ? "; 
            rep = lect_return_defaut(true,"o");
            if (rep!= "o")
              {  cout << "\n nouvelle taille (un réel) ? : ";
                 taille_numero=lect_double();
                 choix_valide = choix_valide && true;
               }
            else 
              { choix_valide = choix_valide && true;
                taille_numero = 0.2;
               }
            
            // choix de la couleur (en RGB) du filaire
            cout << "\n couleur au standard RGB : par defaut bleu (rep 'o') ";
            rep = lect_return_defaut(false,"o");
            if (rep != "o")
              { cout << "\n couleur au standard RGB (trois réels entre 0 et 1) ?  ";
                double Rco,Gco,Bco;
                cin >> Rco >> Gco >> Bco;
                std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
                if ((Rco <= 1.)&& (Rco >= 0) && (Gco <= 1.)&& (Gco >= 0)
                  &&(Bco <= 1.)&& (Bco >= 0))
                  { Rcoull = Rco; Gcoull = Gco; Bcoull = Bco;
                    choix_valide = choix_valide && true;
                   }
                else
                  { cout << " \n *****choix non valide de couleur**** ";
                    choix_valide = choix_valide && false;
                   }
                }
            else
              { Rcoull = 0; Gcoull = 0; Bcoull = 1;
                choix_valide = choix_valide && true;
               }    
             // choix de la couleur (en RGB) des facettes
            cout << "\n couleur au standard RGB : par defaut vert (rep 'o') ";
            rep = lect_return_defaut(false,"o");
            if (rep != "o")
              { cout << "\n couleur au standard RGB (trois reels entre 0 et 1) ?  ";
                double Rco,Gco,Bco;
                cin >> Rco >> Gco >> Bco;
                std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
                if ((Rco <= 1.)&& (Rco >= 0) && (Gco <= 1.)&& (Gco >= 0)
                  &&(Bco <= 1.)&& (Bco >= 0))
                  { Rcoulf = Rco; Gcoulf = Gco; Bcoulf = Bco;
                    choix_valide = choix_valide && true;
                   }
                else
                  { cout << " \n *****choix non valide de couleur**** ";
                    choix_valide = choix_valide && false;
                   }
                }
            else
              { Rcoulf = 0; Gcoulf = 1; Bcoulf = 0;
                choix_valide = choix_valide && true;
               }    
             // choix de la couleur (en RGB) des numéros
            cout << "\n couleur au standard RGB : par defaut blanc (rep 'o') ";
            rep = lect_return_defaut(false,"o");
            if (rep != "o")
              { cout << "\n couleur au standard RGB (trois reels entre 0 et 1) ?  ";
                double Rco,Gco,Bco;
                cin >> Rco >> Gco >> Bco;
                std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
                if ((Rco <= 1.)&& (Rco >= 0) && (Gco <= 1.)&& (Gco >= 0)
                  &&(Bco <= 1.)&& (Bco >= 0))
                  { Rcouln = Rco; Gcouln = Gco; Bcouln = Bco;
                    choix_valide = choix_valide && true;
                   }
                else
                  { cout << " \n *****choix non valide de couleur**** ";
                    choix_valide = choix_valide && false;
                   }
                }
            else
              { Rcouln = 0; Gcouln = 0; Bcouln = 0;
                choix_valide = choix_valide && true;
               }    
            }
         else
            choix_valide = choix_valide && true;  
          }  
       // appel de la méthode de la classe mère
       OrdreVisu::ChoixOrdre();    
     };     
            
    
// lecture des paramètres de l'ordre dans un flux
void Mail_initiale_vrml::Lecture_parametres_OrdreVisu(UtilLecture & entreePrinc)
 { // si dans le flot il existe l'identificateur adoc on lit sinon on passe
   if (strstr(entreePrinc.tablcarCVisu,"debut_maillage_initial")!=NULL)
     {// sauvegarde des paramètres  actuelles
      bool filaire_s=filaire; bool surface_s=surface; bool numero_s = numero;
      double Rcoull_s = Rcoull; double Gcoull_s=Gcoull; double Bcoull_s=Bcoull;
      double Rcoulf_s = Rcoulf; double Gcoulf_s=Gcoulf; double Bcoulf_s=Bcoulf;
      double Rcouln_s = Rcouln; double Gcouln_s=Gcouln; double Bcouln_s=Bcouln;
      // essaie de lecture
      try 
        { string nom; 
          (*entreePrinc.entCVisu) >> nom ;
          if (nom != "debut_maillage_initial")
            { cout << "\n Erreur en lecture des parametres du maillage initial a partir d'un fichier .CVisu,"
                   << " le premier enregistrement doit etre le mot clef: debut_maillage_initial "
                   << " on ne tiens pas compte  des parametres fournies !! ";
              }
          else
           { // appel de l'ordre de la classe mère
             OrdreVisu::Lect_para_OrdreVisu_general(entreePrinc);
             while (nom != "fin_maillage_initial")
               { (*entreePrinc.entCVisu) >> nom;
                 if (nom == "en_filaire") (*entreePrinc.entCVisu) >> filaire;
                 if (nom == "surface")  (*entreePrinc.entCVisu) >> surface;
                 if (nom == "les_numeros") (*entreePrinc.entCVisu) >> numero;
                 if (nom == "couleurs_filaires_RGB")  
                    (*entreePrinc.entCVisu) >> Rcoull >> Gcoull >> Bcoull;
                 if (nom == "couleurs_surfaces_RGB")  
                    (*entreePrinc.entCVisu) >> Rcoulf >> Gcoulf >> Bcoulf;
                 if (nom == "couleurs_numeros_RGB")  
                    (*entreePrinc.entCVisu) >> Rcouln >> Gcouln >> Bcouln;
                 entreePrinc.NouvelleDonneeCVisu();                    
                }
            }       
         }    
      catch (ErrSortieFinale)
           // cas d'une direction voulue vers la sortie
           // on relance l'interuption pour le niveau supérieur
         { ErrSortieFinale toto;
           throw (toto);
         }
      catch (...)// erreur de lecture
       {  cout << "\n Erreur en lecture des parametres du maillage initial a partir d'un fichier .CVisu,"
               << " on ne tiens pas compte  des parametres fournies !! ";
          // récup des infos  sauvées
          filaire=filaire_s; surface=surface_s; numero = numero_s;
          Rcoull = Rcoull_s; Gcoull=Gcoull_s; Bcoull=Bcoull_s;
          Rcoulf = Rcoulf_s; Gcoulf=Gcoulf_s; Bcoulf=Bcoulf_s;
          Rcouln = Rcouln_s; Gcouln=Gcouln_s; Bcouln=Bcouln_s;
          if (ParaGlob::NiveauImpression() >= 4)     
             cout  << "\n Mail_initiale_vrml::Lecture_parametres_OrdreVisu(..";
        }
      } 
  };

// écriture des paramètres de l'ordre dans un flux
void Mail_initiale_vrml::Ecriture_parametres_OrdreVisu(UtilLecture & entreePrinc)
 { // récup du flot  
   ostream & sort = (*(entreePrinc.Sort_CommandeVisu()));
   // on commente le fonctionnement
   sort << "\n #  ----------------------------- definition des parametres du maillage initial: ---------------- "
        << "\n debut_maillage_initial  #  un mot cle de debut de liste ";
   // appel de l'ordre de la classe mère
   OrdreVisu::Ecrit_para_OrdreVisu_general(entreePrinc);
   // on sort l'entête des paramètres
   sort << "\n # les parametres avec des valeurs: (sur une meme ligne) ";   
   // puis la liste des paramètres
   sort << "\n en_filaire " << filaire << " # en_filaire  <0 ou 1> (indique si l'on veut le dessin en filaire)"
        << "\n surface " << surface << " # surface  <0 ou 1> (indique si l'on veut le dessin des faces ou surfaces)"
        << "\n les_numeros " << numero << " # numero  <0 ou 1> (indique si l'on veut le dessin des numeros)"
        << "\n # couleurs_filaires_RGB  <3 réels> (indique la couleur en RGB du trace filaire)"
        << "\n couleurs_filaires_RGB " << Rcoull << " " << Gcoull << " " << Bcoull
        << "\n # couleurs_surfaces_RGB  <3 réels> (indique la couleur en RGB du trace des surfaces)"
        << "\n couleurs_surfaces_RGB " << Rcoulf << " " << Gcoulf << " " << Bcoulf
        << "\n # couleurs_numeros_RGB  <3 réels> (indique la couleur en RGB du trace des numeros)"
        << "\n couleurs_numeros_RGB " << Rcouln << " " << Gcouln << " " << Bcouln;
   // fin      
   sort << "\n fin_maillage_initial " << " #   le mot cle de fin  \n";    
  };