// 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:        29/05/2004                                          *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:  une classe générique qui permet de définir                 *
 *           des identificateurs de grandeurs quelconque.               *
 *           Ces idendificateurs sont prévue en particulier pour gérer  *
 *           les sorties de résultats.                                  *
 *           Le type s'appuit sur un type énuméré pour les gestions     *
 *           rapide de tableau ou de choix (via case).                  *
 *           Le type contiend une grandeur pointée, mais ne crée pas    *
 *           ni ne détruit la grandeur pointée ! Ainsi au niveau de     *
 *           l'affectation, il ne gère que le changement de pointeur.   *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
#ifndef TYPE_QUELCONQUE_H
#define TYPE_QUELCONQUE_H

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

#include "EnumTypeGrandeur.h"
#include "Enum_TypeQuelconque.h"
#include "EnuTypeQuelParticulier.h"
#include "Enum_ddl.h"
#include "Mat_pleine.h"
#include "TypeQuelconque_enum_etendu.h"

/**  @defgroup Group_TypeQuelconque
*
*     BUT:  une classe générique qui permet de définir                 
*           des identificateurs de grandeurs quelconque.               
*           Ces idendificateurs sont prévue en particulier pour gérer
*           les sorties de résultats.
*           Le type s'appuit sur un type énuméré pour les gestions
*           rapide de tableau ou de choix (via case).
*           Le type contiend une grandeur pointée, mais ne crée pas
*           ni ne détruit la grandeur pointée ! Ainsi au niveau de
*           l'affectation, il ne gère que le changement de pointeur.
*
*
* \author    Gérard Rio
* \version   1.0
* \date       29/05/2004
* \brief       classe qui permet de définir des identificateurs de grandeurs quelconque.
*
*/


/// @addtogroup Group_TypeQuelconque
///  @{

/// TypeQuelconque : def de la classe générique globale qui sert a gérer la grandeur
/// particulière qui est attachée via un pointeur

class TypeQuelconque
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream & ent, TypeQuelconque & a);
  
 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream & sort , const TypeQuelconque & a);

  public :
    //----------------------------------------------------------------------------
    /// définition de la classe virtuelle qui serait déclinée en une grandeur particulière
    /// il s'agit ici de la classe conteneur
    //----------------------------------------------------------------------------
    class Grandeur 
       { // surcharge de l'operator de lecture
         friend istream & operator >> (istream & ent, Grandeur & a)
           { a.Lecture_grandeur(ent);return ent;};
         // surcharge de l'operator d'ecriture
         friend ostream & operator << (ostream & sort , const Grandeur & a)
           { a.Ecriture_grandeur(sort); return sort;};
         public: virtual ~Grandeur(){};
         virtual Grandeur* New_idem_grandeur() const =0; // ramène une grandeur identique, créée          
         virtual TypeQuelconque::Grandeur & operator = ( const TypeQuelconque::Grandeur & a) = 0; // surcharge d'affectation (totale a priori)
         // ** operations simples: si l'opération ne veut rien dire pour le type quelconque -> erreur
         // ** les opérations entre deux types quelconques ne doivent concerner que des grandeurs  de même type
         // affectation uniquement des données numériques (pas les pointeurs, pas les string)
         virtual void Affectation_numerique( const TypeQuelconque::Grandeur & a) = 0;
		       // Surcharge de l'operateur +=
	        virtual void operator+= (const Grandeur& c) = 0;
		       // Surcharge de l'operateur -= 
	        virtual void operator-= (const Grandeur& c) = 0;
		       // Surcharge de l'operateur *= 
	        virtual void operator*= (double val) = 0;
		       // Surcharge de l'operateur /= : division  par un scalaire
	        virtual void operator/= (double val)  = 0;
         // récup du nom de référence si diff de NULL
         // c'est un nom qui permet de discriminer différentes grandeurs quelconque qui
         // ont la même signature (mêmes énumérés) Cependant n'existe pas toujours
         virtual const string* Nom_ref() const {return NULL;};
         // récupération de la valeur numérique d'une grandeur correspondant à un numéro d'ordre
         // si pas possible, ramène 0
         virtual double GrandeurNumOrdre(int num) const =0;
         virtual void Change_GrandeurNumOrdre(int num, const double& val) =0; // modification
         virtual int NbMaxiNumeroOrdre() const = 0; // récup du nb maxi de numéros d'ordres
         virtual void Grandeur_brut(ostream & sort,int nbcar) const =0; // sortie de la grandeur brut sur sort
         // ramène le type de grandeur associée de la grandeur de base, car 
         // la grandeur peut être une grandeur complexe comme un tableau ou un liste de grandeur de base
         virtual EnumTypeGrandeur Type_grandeurAssocie() const =0;
         // ramène le type de la structure: tableau, liste ext..
         virtual EnumType2Niveau  Type_structure_grandeurAssocie() const = 0;
         // ramène le type de la grandeur particulière
         virtual EnuTypeQuelParticulier Type_enumGrandeurParticuliere() const = 0;
         // change de repère de la grandeur si nécessaire 
         virtual void Change_repere(const Mat_pleine& beta,const Mat_pleine& gamma) =0;
         // lecture 
         virtual istream & Lecture_grandeur(istream & ent) =0;
         // ecriture
         virtual ostream & Ecriture_grandeur(ostream & sort) const  =0;
         // initialise la grandeur à une valeur par défaut: = 0 pour les grandeurs numériques
         virtual void InitParDefaut() = 0;
       };

    // CONSTRUCTEURS :
    // constructeur par défaut
    // ensuite il faut utiliser ChangeGrandeur pour affecter une bonne valeur
    TypeQuelconque();
    // constructeur fonction d'un type donnée et d'une grandeur
    // c'est le 1er constructeur officiel, qui sert
    // posi_ddl: indique un ddl dont les points de calcul (ex: les pt d'integ) sont les même
    // que la grandeur particulière
    TypeQuelconque(TypeQuelconque_enum_etendu enuType,Enum_ddl posi_ddl,const TypeQuelconque::Grandeur& pt_gr);
    // le même constructeur mais à partir d'un énum
    TypeQuelconque(EnumTypeQuelconque enuType,Enum_ddl posi_ddl,const TypeQuelconque::Grandeur& pt_gr);

    // constructeur fonction d'un type donnée uniquement
    // c'est le 2er constructeur officiel, qui sert
    // ici il n'y a pas de grandeur associée, util uniquement pour gérer le type mais pas la grandeur
    TypeQuelconque(TypeQuelconque_enum_etendu enuType);
    // le même constructeur mais à partir d'un énum
    TypeQuelconque(EnumTypeQuelconque enuType);

// -- ces deux constructeurs ont été imaginés, mais a priori ne sont pas utilisés ---
//    // Constructeur fonction  d'un type de donnée, et d'un énuméré permettant de construire la grandeur
//    // celle-ci , si elle dépend de la dimension, est construite suivant la dimension courante
//    // posi_ddl: indique un ddl dont les points de calcul (ex: les pt d'integ) sont les même
//    // que la grandeur particulière
//    TypeQuelconque(TypeQuelconque_enum_etendu enuType,Enum_ddl posi_ddl,EnuTypeQuelParticulier enuGrandQuelParti);
//    // le même constructeur mais à partir d'un énum
//    TypeQuelconque(EnumTypeQuelconque enuType,Enum_ddl posi_ddl,EnuTypeQuelParticulier enuGrandQuelParti);
 
    // constructeur de copie
    TypeQuelconque(const TypeQuelconque& a);             
    // DESTRUCTEUR :
    ~TypeQuelconque();
    
    // METHODES PUBLIQUES :
    
    // changement d'une grandeur quelconque
    // la grandeur initiale est transformée en la grandeur passée en paramètre 
    // utile après une contruction par défaut
    void ChangeGrandeur(const TypeQuelconque& a);
    
    // surcharge d'affectation
    // ne doit concerner que des grandeurs quelconques de même type
    // il n'y a donc pas de changement automatique de type, volontairement pour éviter des erreurs
    // et un long temps de traitement
    TypeQuelconque & operator = ( const TypeQuelconque & a);
    
    // surcharge d'égalité: ne concerne que les types, ne concerne pas la grandeur elle-même pointée !
    bool operator == ( const TypeQuelconque & a) const { return (enuType == a.enuType);};
    // surcharge de non égalité
    bool operator != ( const TypeQuelconque & a) const { return (enuType != a.enuType);};
    // surcharge de comparaison
    bool operator > (const TypeQuelconque & a)   const {return (enuType > a.enuType);};
    bool operator >= (const TypeQuelconque & a)  const {return (enuType > a.enuType);};
    bool operator < (const TypeQuelconque & a)   const {return (enuType < a.enuType);};
    bool operator <= (const TypeQuelconque & a)  const {return (enuType < a.enuType);};

    // récup du type de grandeur associé
    // il s'agit ici du type de base, car la grandeur peut être un type complexe comme un tableau
    // de type de base ou une liste
    EnumTypeGrandeur EnuTypeGrandeur() const {return enuType.TypeDeGrandeurTG();};
    // récup du typeQuelconque
    const TypeQuelconque_enum_etendu& EnuTypeQuelconque() const {return enuType;};
    // écriture d'une chaine de caractère composés de l'Enumtypequlconque et du string additionnel
 
    // récup du type de calcul de la grandeur:
    // = 1 indique si la grandeur est naturellement exprimé dans le repère globale
    // = 0 indique que la grandeur est dans le repère naturelle (ou une combinaison)
    int TypeExpressionGrandeur() const {return EnumTypeQuelconqueGlobale(enuType.EnumTQ());};
    // sortie de la grandeur uniquement sur sort (sans info particulière c-a-d de typage)
    void Grandeur_brut(ostream & sort,int nbcar) const {Gestion_erreur();pt_grandeur->Grandeur_brut(sort,nbcar);};
    // ramène le ddl associé, qui correspond à un ddl éventuellement du même type, mais surtout
    // qui est calculé au même point géométrique !
    // si ce ddl n'exite pas => pas d'existance de la grandeur quelconque
    Enum_ddl Enum() const {return enu_ddl_posi;};
    // change de repère de la grandeur si nécessaire 
    void Change_repere(const Mat_pleine& beta0,const Mat_pleine& betat,const Mat_pleine& betatdt
                       ,const Mat_pleine& gamma0,const Mat_pleine& gammat,const Mat_pleine& gammatdt);
    // indique si c'est un type numérique ou non
    bool Type_numerique() const
          {return Type_grandeur_numerique(Type_de_grandeur_associee(enuType.EnumTQ()));};
    // retourne le nombre maxi de numéros d'ordre (c'est à dire de numéros de classement
    // des différents éléments de la grandeur, s'il y en a plusieurs
    // pour un tableau, un vecteur une liste, c'est directement le numéro d'ordre
    // pour des tenseurs, ou tableaux multidimentionnels c'est de dernier indice qui varie
    // d'abord puis on remonte 
    int NbMaxiNumeroOrdre() const {Gestion_erreur();return pt_grandeur->NbMaxiNumeroOrdre();};
    // récupération de la valeur numérique d'une grandeur correspondant à un numéro d'ordre
    // si pas possible, ramène 0
    double GrandeurNumOrdre(int num) const {Gestion_erreur();return pt_grandeur->GrandeurNumOrdre(num);};
    // récupération de la grandeur en lecture/écriture pour un cast !!! attention il faut savoir ce que l'on fait 
    Grandeur* Grandeur_pointee() {return pt_grandeur;};
    const Grandeur* Const_Grandeur_pointee() const {return pt_grandeur;};
    // écriture de l'entête de la grandeur : TypeQuelconque_enum_etendu EnumType2Niveau EnumTypeGrandeur et nombre de grandeur
    // numérique équivalente si c'est une grandeur numérique
    void Ecriture_entete_grandeur(ostream & sort);
    // --- lecture en 2 temps
    // lecture des infos internes sauf de la grandeur
    // retour de l'EnuTypeQuelParticulier de la grandeur
    EnuTypeQuelParticulier  Lecture_un (istream & ent);
 
    // idem mais avec création du TypeQuelconque_enum_etendu interne
    // s'il n'existe pas,: il s'agit uniquement du nom de def, mais les infos
    // associées:  EnumTypeQuelconque et EnumTypeGrandeur sont lues et vérifiés
    // le string, lui peut ne pas exister: intéressant lorsqu'il s'agit de grandeurs
    // qui sont crées pendant le calcul et/ou en restart
    EnuTypeQuelParticulier  Lecture_un_avec_creation_TypeQuelconque_enum_etendu(istream & ent);
 
    // gestion de l'activité du type quelconque
    void Active() {actif=true;};
    void Inactive() {actif = false;};
    bool Activite() const {return actif;};
    
  protected :  
    // VARIABLES PROTEGEES :
    TypeQuelconque_enum_etendu enuType;
    Enum_ddl enu_ddl_posi; // un enum d'un ddl qui est calculé au même point que le type quelconque
    Grandeur * pt_grandeur; // le pointeur sur la grandeur correspondantes
    bool actif; // un boolen qui permet une gestion du type: par exemple prise en compte ou non
        
    // METHODES PROTEGEES :
    // gestion de l'erreur dans le cas où il n'y a pas de grandeur associée
#ifdef MISE_AU_POINT	 	 
    void Gestion_erreur() const ;
#endif    
#ifndef MISE_AU_POINT	 	 
    void Gestion_erreur() const {};
#endif    

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

  
#endif