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

/************************************************************************
 *     DATE:        03/12/2017                                          *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:  une classe qui permet de dfinir des identificateurs de     *
 *           grandeurs secondaires associes  des EnumTypeQuelconque.    *
 *           Ces grandeurs ne sont pas vraiment des EnumTypeQuelconque, *
 *           mais ils s'en  déduisent. Ainsi pour ne pas alourdir l'enum*
 *    de base on crée cette classe associe. Elle est prévue en particu- *
 *           lier pour gérer les sorties de résultats.                  *
 *           les éléments sont ordonnés selon la règle suivante :       *
 *           si c'est un EnumTypeQuelconque pur ->  ordre de l'Enum     *
 *           si c'est un élment de tab_Daa -> ordre dans tab_Daa        *
 *           + maxi des EnumTypeQuelconque                              *
 *           lorsqu'il s'agit d'un EnumTypeQuelconque tout simple,      *
 *           dans ce cas  Non_vide == true                              *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *                                                                $     *
 ************************************************************************/
#ifndef TYPEQUELCONQUE_ENUM_ETENDUE_H
#define TYPEQUELCONQUE_ENUM_ETENDUE_H

#include "Enum_TypeQuelconque.h"
#include <string.h>
#include "List_io.h"
#include <iomanip>
#include <algorithm>

/** @defgroup Group_TypeQuelconque_enum_etendu Group_TypeQuelconque_enum_etendu
*
*     BUT:  une classe qui permet de dfinir des identificateurs de
*           grandeurs secondaires associes  des EnumTypeQuelconque.
*           Ces grandeurs ne sont pas vraiment des EnumTypeQuelconque,
*           mais ils s'en  déduisent. Ainsi pour ne pas alourdir l'enum
*    de base on crée cette classe associe. Elle est prévue en particu-
*           lier pour gérer les sorties de résultats.
*           les éléments sont ordonnés selon la règle suivante :
*           si c'est un EnumTypeQuelconque pur ->  ordre de l'Enum
*           si c'est un élment de tab_Daa -> ordre dans tab_Daa
*           + maxi des EnumTypeQuelconque
*           lorsqu'il s'agit d'un EnumTypeQuelconque tout simple,
*           dans ce cas  Non_vide == true
*
*
* \author    Gérard Rio
* \version   1.0
* \date      03/12/2017
* \brief       classe qui permet de définir des identificateurs de grandeurs secondaires associées à des EnumTypeQuelconque.
*
*/

/// @addtogroup Group_TypeQuelconque_enum_etendu
///  @{

/// Initialisation_tab_Daa:  definition d'une  classe pour l'initialisation du tableau tab_Daa
class Initialisation_tab_Daa { public: Initialisation_tab_Daa(); };
/// @}  // end of group

/// @addtogroup Group_TypeQuelconque_enum_etendu
///  @{

/// TypeQuelconque_enum_etendu: la classe qui gère les types quelconques étendus

class TypeQuelconque_enum_etendu
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream & ent, TypeQuelconque_enum_etendu & a)
    { string no; ent >> no; a=TypeQuelconque_enum_etendu(no);
      ent >> a.enu >> a.type_grandeur;
      return ent;};
 
 // !!! voir aussi lecture éléments distinctes qui doit être cohérent

 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream & sort , const TypeQuelconque_enum_etendu & a)
    { if (a.Nom_vide()) sort << " " << NomTypeQuelconque(a.enu); else sort << " " << a.nom;
      sort << " " << a.enu << " " << a.type_grandeur << " ";
      return sort;};

 // permition pour l'initialisation du tableau tab_Daa
  friend class Initialisation_tab_Daa;
  
  public :
    // CONSTRUCTEURS :
    // constructeur par défaut
    TypeQuelconque_enum_etendu(EnumTypeQuelconque en = RIEN_TYPEQUELCONQUE, string no = "-");
    // constructeur fonction d'un string 
    TypeQuelconque_enum_etendu( string no );
    // constructeur fonction  d'une chaine
    TypeQuelconque_enum_etendu( char * no );
    // constructeur de copie
    TypeQuelconque_enum_etendu(const TypeQuelconque_enum_etendu& a) :
         nom(a.nom), enu(a.enu), posi_nom(a.posi_nom) ,type_grandeur(a.type_grandeur)
          {};
    // DESTRUCTEUR :
    ~TypeQuelconque_enum_etendu() {};
    
    // METHODES PUBLIQUES :
 
    // ajout d'un nouveau typeQuelconque étendu
    // s'il existait avant, il n'y a pas d'ajout
    // ramène un exemplaire de la création
    static  TypeQuelconque_enum_etendu Ajout_un_TypeQuelconque_enum_etendu
                (EnumTypeQuelconque enu, const string no,EnumTypeGrandeur type_grandeur);

    // surcharge d'affectation
    TypeQuelconque_enum_etendu & operator = ( const TypeQuelconque_enum_etendu & a)
      { nom = a.nom; enu = a.enu; posi_nom = a.posi_nom;type_grandeur = a.type_grandeur;
        return *this;};
    // surcharge d'égalité
    bool operator == ( const TypeQuelconque_enum_etendu & a) const
      { if (posi_nom == a.posi_nom) return true; else return false;};
    // surcharge de non égalité
    bool operator != ( const TypeQuelconque_enum_etendu & a) const
      { if (posi_nom != a.posi_nom) return true; else return false;};
    // surcharge de comparaison
    bool operator > (const TypeQuelconque_enum_etendu & a) const
      { return (posi_nom > a.posi_nom);};
    bool operator >= (const TypeQuelconque_enum_etendu & a) const
      { return (posi_nom >= a.posi_nom);};
    bool operator < (const TypeQuelconque_enum_etendu & a) const
       { return (posi_nom < a.posi_nom);};
    bool operator <= (const TypeQuelconque_enum_etendu & a) const
      { return (posi_nom <= a.posi_nom);};
    
    // récup de l'énumération
    EnumTypeQuelconque EnumTQ() const {return enu;};
    // récup du nom
    string Nom() const {return nom;};
    // récup du nom plein
    string NomPlein() const
      {if (nom=="-"){return NomTypeQuelconque(enu);}
       else {return nom;};
      };
    // récup du nom générique (sans les indices de composantes)
    string NomGenerique() const 
      {if (nom=="-"){return NomGeneriqueTypeQuelconque(enu);}
       else {return string(nom.substr(1,nom.length()-2));};
       };
    // position donne un numéro équivalent du type enum
    int Position() const {return posi_nom;};
    // modification du nom
    // test pour savoir si le nom est vide
    bool Nom_vide() const { if (nom == "-") return true; else return false; };
    // retour le type de grandeur auquel apartient le type quelconque tendue
    // par exemple :  vecteur ou scalaire
    EnumTypeGrandeur TypeDeGrandeurTG() const {return type_grandeur;};
    
    // test pour savoir si le nom passer en paramètre est valide
    // ramène vrai si no correspond à un EnumTypeQuelconque  ou
    // s'il correspond  un type dérivé
    static bool VerifExistence(string no)  ;
    // récupération d'un TypeQuelconque_enum_etendu correspondant  un string
    static TypeQuelconque_enum_etendu RecupTypeQuelconque_enum_etendu(string to)  ;
    // transformation d'une liste d'EnumTypeQuelconque en TypeQuelconque_enum_etendu
    static List_io <TypeQuelconque_enum_etendu> TransfoList_io(const  List_io <EnumTypeQuelconque> &  li) ;
    // transformation d'un tableau d'énumération en un tableau de TypeQuelconque_enum_etendu
    static Tableau < TypeQuelconque_enum_etendu > TransfoTableau(const Tableau <EnumTypeQuelconque> & tab) ;
    // test si un élément existe dans une liste donnée
    static bool Existe_dans_la_liste
           (const List_io <TypeQuelconque_enum_etendu> & lis, const TypeQuelconque_enum_etendu& dd) ;
    // récupération du nombre maximum de ddl tendu existant
    static int NBmax_TypeQuelconque_enum_etendue()
        {return taillTab+ClassPourEnumTypeQuelconque::NombreEnumTypeQuelconque();};
 
    // lecture éléments distinctes: idem la surcharge de lecture mais sans création d'un
    // TypeQuelconque_enum_etendu
    // permet de récupérer les grandeurs pour crer un nouveau type étendu
    // on ne le fait pas systématiquement, de manière à pouvoir contrôler les créations éventuelles
    static void Lecture_element_distinctes(istream & ent, string& no,EnumTypeQuelconque& enu
                                            ,EnumTypeGrandeur& type_grandeur)
       { ent >> no >> enu >> type_grandeur; };
    // lecture avec création éventuelle si le type n'existe pas
    static TypeQuelconque_enum_etendu Lecture_avec_creation_eventuelle(istream & ent);
 
  protected :  
    // VARIABLES PROTEGEES :
    string nom;
    EnumTypeQuelconque enu;
    int posi_nom;  // position du nom  : équivalent à un type énumréré
    EnumTypeGrandeur type_grandeur;
    
    // on définie le  tableau des TypeQuelconque_enum_etendu qui sont valides
    // en variables globales
    static Tableau < TypeQuelconque_enum_etendu > tab_Daa;
    static Initialisation_tab_Daa init_tab_Daa;
    static int taillTab; // taille du tableau tab_Daa
    
    // METHODES PROTEGEES :

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

#endif  
