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



#include "DdlLim.h"
#include <fstream>
#include <sstream>
#include <cstring>


# include <iostream>
using namespace std;  //introduces namespace std
#include <stdlib.h>
#include "Sortie.h"
#include "ConstMath.h"
#include "CharUtil.h"



DdlLim::DdlLim () :  // par defaut
  tab(),ref(),t_min(0.),t_max(ConstMath::tresgrand),precedent(false)
  ,nom_maillage(NULL),champ(false),blocage_relatif(false),mvtsolide(NULL)
  ,nom_fnD_t_min(""),nom_fnD_t_max("")
  ,typeCL(RIEN_TYPE_CL)
{   
};

// de copie
DdlLim::DdlLim (const DdlLim& d) :
   t_min(d.t_min),t_max(d.t_max),ref(d.ref),tab(d.tab),precedent(d.precedent)
   ,nom_maillage(NULL),champ(d.champ),blocage_relatif(d.blocage_relatif)
   ,mvtsolide(NULL),typeCL(d.typeCL)
   ,nom_fnD_t_min(d.nom_fnD_t_min)
   ,nom_fnD_t_max(d.nom_fnD_t_max)
// Constructeur de copie
{	if (d.nom_maillage != NULL) nom_maillage = new string(*(d.nom_maillage));
    if (d.mvtsolide != NULL)
      mvtsolide = new MvtSolide(*(d.mvtsolide));
};

DdlLim::~DdlLim ()
// Destructeur
{ if (nom_maillage != NULL) delete nom_maillage; 
  if (mvtsolide != NULL) delete mvtsolide;
};

// Remplace la reference  par nouveau
// ATTENTION : Les modifications liees au changement de la reference 
//  sont a la charge de l'utilisateur.
void DdlLim::Change_ref (string nouveau)
    {	if (nouveau.length() == 0)
		  { cout << "\nErreur : reference non valide  car de longueur nulle !\n";
			cout << "DdlLim::CHANGE_REF(string ) \n";
			Sortie(1);
		   }	
	    ref = nouveau;
	};
	
// idem pour le changement de nom de maillage
void DdlLim::Change_nom_maillage(const string& nouveau)
  {	if (nouveau.length() == 0)
	   { cout << "\nErreur : reference de nom de maillage non valide  car de longueur nulle ! "
	          << " nom_mail= " << nouveau << "\n";
		 cout << "DdlLim::Change_nom_maillage(....) \n";
		 Sortie(1);
		}
     if (nom_maillage == NULL)
       { nom_maillage = new string(nouveau);}
     else 
       { *nom_maillage = nouveau;};  	
	};

// lecture des degres de liberte
// sur le fichier d'entree
// util pour la lecture de ddl bloque    
void DdlLim::Lecture(UtilLecture & entreePrinc)
{ // on regarde tout d'abord si il y a un nom de maillage, qui doit être le premier nom
  string nom;
  *(entreePrinc.entree) >> nom;
  if (nom == "nom_mail=")
      { // cas où il y a un nom de maillage
        *(entreePrinc.entree) >> nom; // lecture du nom
        if (nom_maillage == NULL) { nom_maillage = new string(nom);}
        else                      { *nom_maillage = nom;};  	
        // puis on prépare la suite en lisant la référence
        *(entreePrinc.entree) >> nom;
      }
  // lecture de la reference
  char tat[250]; char * ta = tat; char tt[100]; char * t = tt;
  char ch = '\''; char * pt = & ch; char bl = ' '; char* pbl = &bl;
  ref = nom;  //          *(entreePrinc.entree) >> ref;
  if (ref.length() == 0)
      { // pas de  reference
        cout << "\n erreur de lecture d'une reference de ddl bloquee "
             << " la chaine a une longueur nulle \n";
        entreePrinc.MessageBuffer("*** lecture d'une reference de ddl bloquee ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);     
       }
   // def de la liste de ddl
   list <Ddlbloque> lili;
   // on regarde si un type de condition limite est indiqué
   if (strstr(entreePrinc.tablcar,"typeCL_=")!=NULL)
   	{ string mot;
      *(entreePrinc.entree) >> mot ;
      if (mot != "typeCL_=")
   		 { cout << "\n erreur de lecture d'une reference  "
             << " on s'attandait a lire le mot cle : typeCL_=  et on a lue: " << mot << " \n";
           entreePrinc.MessageBuffer("*** lecture d'une reference de ddl bloquee: mot cle typeCL_= ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
      // sinon c'est ok pour le mot cle, on passe au contenu,
      *(entreePrinc.entree) >> mot;
      if (Existe_typeCL(mot))
       {  typeCL = Id_nomTypeCL(mot);} // cas ou le type de cl existe
      else
   		 { cout << "\n erreur de lecture d'un type de condition limite  "
             << " on a lue: " << mot << " \n";
           entreePrinc.MessageBuffer("*** lecture d'une reference de ddl bloquee: type de CL  ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
   	} 
   else // sinon on précise qu'il n'y a pas de type de CL particulier
    { typeCL = RIEN_TYPE_CL; };
   
   // maintenant les cas particulier   
   if (strstr(entreePrinc.tablcar,"champ_de:")!=NULL)
      // on regarde si c'est un champ de valeur c'est-à-dire une valeur par noeud de la ref
      // dans ce cas appel de la procédure a doc
       { lili = Lecture_champ(entreePrinc); champ = true;}
   else if (strstr(entreePrinc.tablcar,MvtSolide::MotCleMvtSolide().c_str())!=NULL)
      // on regarde si c'est un mouvement solide, si oui appel de la procédure a doc
       { // petite vérif: incompatible avec la condition de tangente imposée
         if (typeCL == TANGENTE_CL)
           {cout << "\n erreur en lecture, la condition de mouvement solide est incompatible "
                 << " avec une  condition de tangente imposée !!! revoir l'entree de la  "
                 << " condition " ;
            cout << "\n DdlLim::Lecture(.. " << endl ;
            entreePrinc.MessageBuffer("**erreur**");
            throw (UtilLecture::ErrNouvelleDonnee(-1));
            Sortie(1);
           };          
         lili = Lecture_mvtSolide(entreePrinc); champ = false ;
       }
   else
    {champ = false;   
     // --- dans la suite comme il ne s'agit pas d'un champ toutes les données sont sur une seule ligne -----  
     //recup de la fin de la ligne
     char tout[150] ; char * ptout = tout;
     (entreePrinc.entree)->get(ptout,150);
     // avant la lecture on remplace toutes les virgules par des espaces
     char * ii = strchr(ptout,',');
     while (ii != NULL)
       { *ii = ' ';
         ii = strchr(ptout,',');
        }
	 // def d'un flot intermédiaire         
     #ifndef ENLINUX_STREAM
        istringstream flot(ptout);
     #else 
        istrstream flot(ptout);
     #endif    
   
     // lecture tant que le flot est valide
     while (flot.rdstate() == 0)
         // tout d'abord on passe les espaces  qui sont des séparateurs
           // lecture du prochain caractère sans modifier le flot
     {  char car; 
        flot >> car;
        // éventuellement il n'avait pas bien déterminé la fin de l'enregistrement
        // au niveau du while, dans ce cas si durant la lecture de car il y a eu un pb
        // cela signifie qu'en fait la ligne était terminée donc on s'arrête
        if (flot.rdstate() != 0) break;
        while ( (car==' ')  && (flot.rdstate() == 0 ))
         // cas où le prochain caractère est un espace 
         { flot >> car;};
        flot.putback(car);
      bool un_ddl_a_lire=true;   
      // on démarre une boucle qui se termine lorsqu'il n'y a plus de ddl à lire
      while(un_ddl_a_lire)
       {// on définit un  ddl pour la lecture
        Ddlbloque elem;  
        // deux cas, soit un ddl nulle par defaut, soit une valeur non nulle imposee
        // soit le caractère est ' , signifie que c'est un ddl avec une valeur
        // imposée
        if ( (car=='\'') && (flot.rdstate() == 0 ))
          { // on passe le premier  '
            flot >> car; 
            // on lit jusqu'au prochain ' en non formaté
            flot.get(ta,150,'\'');
            // on passe ce dernier '
            flot >> car; 
            // on recherche le  = pour mettre un blanc a la place
            char * ii = strchr(ta,'\'');char * pii=ii; // sauvegarde de l'adresse
            ii = strchr(ta,'='); // on recherche le =
            if (ii == NULL)
              { cout << "\n erreur de syntaxe dans la definition des conditions limites "
                     << " imposees a une valeur non nulle ";
                cout << " le ddl doit etre separe de la valeur par le signe = , caractere non"
                    << "  trouve ";
                entreePrinc.MessageBuffer("*** lecture d'une reference de ddl bloquee ****" );
                throw (UtilLecture::ErrNouvelleDonnee(-1));
                Sortie(1); 
              };
            *ii = ' '; // supprime le =   
            // def d'un flux intermediaire
            #ifndef ENLINUX_STREAM
               istringstream flux (ta);
            #else 
               istrstream flux (ta);
            #endif          
           
            flux >> t ;
            elem.ddl.Change_nom(t);
            // on vérifie que le ddl est compatible avec la dimension
            if (!CompatDim(t))
              { cout << "\n erreur de choix de ddl  dans la definition des conditions limites "
                     << " le ddl " << t << " n'est pas compatible avec la dimension du probleme ";
                entreePrinc.MessageBuffer("*** lecture d'une reference de ddl bloquee ****" );
                throw (UtilLecture::ErrNouvelleDonnee(-1));
                Sortie(1); 
		            };
           
            // on regarde s'il ne s'agit pas d'une courbe ou fonction de charge imposée
            bool sans_courbe_ou_fct_nD=true; // variable locale
            // l'ordre d'apparition de la courbe de charge ou de la fonction nD peut être
            // quelconque
            if ((strstr(ta,"COURBE_CHARGE:")!=0)|| (strstr(ta,"Fonction_nD_CHARGE:")!=0))
             {string nom_fonct;string nom_cle;
              flux >> nom_cle >> nom_fonct;
              // a) cas d'une courbe
              if(nom_cle == "COURBE_CHARGE:")
               { // cas d'une courbe de charge
//               flux >> toto >> elem.co_charge;
                 elem.co_charge = nom_fonct;
                 sans_courbe_ou_fct_nD=false;
                 // on regarde s'il y a une fct nD qui suit
                 if(strstr(ta,"Fonction_nD_CHARGE:")!=0)
                  { // cas d'une fonction nD
                    string toto;
                    flux >> toto >> elem.f_charge;
                    // on vérifie la présence au bon endroit du mot clé Fonction_nD_CHARGE:
                    if (toto != "Fonction_nD_CHARGE:")
                     {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD ";
                      cout << " on attendait  Fonction_nD_CHARGE: "
                           << " et on a lu "<< toto;
                      cout << "\n DdlLim::Lecture(.. " << endl ;
                      entreePrinc.MessageBuffer("**erreur**");
                      throw (UtilLecture::ErrNouvelleDonnee(-1));
                      Sortie(1);
                     };
                  };
               }
              else if (nom_cle == "Fonction_nD_CHARGE:")
               { elem.f_charge = nom_fonct;
                 sans_courbe_ou_fct_nD=false;
                 // on regarde s'il y a une courbe 1D qui suit
                 if(strstr(ta,"COURBE_CHARGE:")!=0)
                  { // cas d'une courbe de charge
                    string toto;
                    flux >> toto >> elem.co_charge;
                    elem.co_charge = nom_fonct;
                    // on vérifie la présence au bon endroit du mot clé Fonction_nD_CHARGE:
                    if (toto != "COURBE_CHARGE:")
                     {cout << "\n erreur de syntaxe en lecture du nom de la courbe ";
                      cout << " on attendait COURBE_CHARGE:  "
                           << " et on a lu "<< toto;
                      cout << "\n DdlLim::Lecture(.. " << endl ;
                      entreePrinc.MessageBuffer("**erreur**");
                      throw (UtilLecture::ErrNouvelleDonnee(-1));
                      Sortie(1);
                     };
                  };
               }
              else
                {cout << "\n erreur de syntaxe en lecture du nom de la courbe ou du nom d'une fonction nD";
                 cout << " on attendait COURBE_CHARGE: ou Fonction_nD_CHARGE: "
                      << " et on a lu "<< nom_cle;
                 cout << "\n DdlLim::Lecture(.. " << endl ;
                 entreePrinc.MessageBuffer("**erreur**");
                 throw (UtilLecture::ErrNouvelleDonnee(-1));
                 Sortie(1);
                };
              // on récupère l'échelle éventuellement
              if(strstr(ta,"ECHELLE:")!=0)
                 { // cas où il y a un facteur d'échelle
                   string toto;
                   flux >> toto;
                   if (toto != "ECHELLE:")
                    {cout << "\n erreur de syntaxe en lecture du facteur d'échelle ";
                     cout << "\n DdlLim::Lecture(.. " << endl ;
                     entreePrinc.MessageBuffer("**erreur**");
                     throw (UtilLecture::ErrNouvelleDonnee(-1));
                     Sortie(1);          
                    };
                   // lecture du facteur
                   flux >> elem.echelle; 
                 };
             };
//            // b) cas d'une fonction nD
//            if(strstr(ta,"Fonction_nD_CHARGE:")!=0)
//             { // cas d'une fonction nD
//               string toto;
//               flux >> toto >> elem.f_charge;
//               sans_courbe_ou_fct_nD=false;
//               // on vérifie la présence au bon endroit du mot clé Fonction_nD_CHARGE:
//               if (toto != "Fonction_nD_CHARGE:")
//                {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD ";
//                 cout << "\n DdlLim::Lecture(.. " << endl ;
//                 entreePrinc.MessageBuffer("**erreur**");
//                 throw (UtilLecture::ErrNouvelleDonnee(-1));
//                 Sortie(1);
//                };
//             };
           
            // si aucune courbe ou fct nD
            if (sans_courbe_ou_fct_nD)
             // cas où c'est une valeur fixe
             {                
               flux  >> elem.ddl.Valeur();
             }
            elem.ddl.Change_fixe (true);
           }
        else if (flot.rdstate() == 0 ) // il s'agit d'un ddl à 0  
          { //un ddl nulle par defaut 
            flot >> t;
            // on vérifie que c'est bien un ddl
            if (!ExisteEnum_ddl(t))
             { cout << "\n erreur , on s'attendait a lire un ddl et on a lue: " << t
                    << " !!, partie de condition actuellement lue: ";
               this->Affiche();     
               cout << " DdlLim::Lecture(UtilLecture & entreePrinc)" << endl;
               entreePrinc.MessageBuffer("** erreur en lecture des conditions limites**");                     
               throw (UtilLecture::ErrNouvelleDonnee(-1));
               Sortie (1);          
             };
            elem.ddl.Change_nom(t); 
            elem.ddl.Valeur() = 0;
            elem.ddl.Change_fixe (true);
          };
        // on verifie que l'on n'utilise pas deux fois le meme identificateur de ddl
        // avec deux valeurs differentes
        list <Ddlbloque>::iterator imi;
        for (imi=lili.begin() ; imi != lili.end(); imi++)
          if (((*imi).ddl.Id_nom() == elem.ddl.Id_nom()) && ((*imi).ddl.Valeur() != elem.ddl.Valeur()))
            { cout << "\n erreur , un meme identificateur de ddl est utilisee avec"
                   << " deux valeurs differentes \n";
              cout << " premiere Ddl : ";  (*imi).ddl.Affiche();
              cout << "  seconde Ddl : "; elem.ddl.Affiche();    
              cout << " DdlLim::Lecture(UtilLecture & entreePrinc)" << endl;
              entreePrinc.MessageBuffer("** erreur en lecture des conditions limites**");                     
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie (1);          
            }
        // stockage  du ddl bloque 
        lili.push_back(elem);
        // --- maintenant on regarde si on a encore d'autre ddl à lire
        // 1- on passe les blancs
        flot >> car;
        while ( (car==' ')  && (flot.rdstate() == 0 ))
         // cas où le prochain caractère est un espace 
         { flot >> car;}
        flot.putback(car);
        // on enregistre la position actuelle dans le flot au premier caractère non nul
        streampos  posi=flot.tellg();
        // maintenant on regarde s'il reste un ddl à lire
        // en ayant passé éventuellement le caractère ', on regarde s'il s'agit
        //     d'un énum de ddl
        // manip pour passer le caractère '
        flot >> car; // lecture du prochain caractère
        if (flot.rdstate() == 0 )
         { // s'il ne s'agit pas de ' on le remet dans le flot
           if (!(car=='\'')) flot.putback(car); 
           // maintenant on lit la chaine
           string ddnom;
           flot >> ddnom; // lecture de la chaine
           // on cherche s'il y a éventuellement un signe =, si oui
           // on supprime le signe = et tout ce qui suit
           string::iterator ala,alafin=ddnom.end();
           for (ala=ddnom.begin();ala!=alafin;ala++)
           	if (*ala == '=')
           		{ ddnom.erase(ala,alafin);
           	      break;
           		};
           // est-ce que c'est un enum de ddl 
           if (ExisteEnum_ddl(ddnom)) 
              {un_ddl_a_lire=true;
               flot.clear(); // on remet ok le flot au cas où on avait été jusqu'au bout  à la
               }             // dernière lecture par exemple, car de toute manière on va relire
           else  {un_ddl_a_lire=false;};
         }
        else  {un_ddl_a_lire=false;}; // sinon fin
        // retour avant la lecture du futur ddl éventuel
        flot.seekg(posi, ios::beg);
        // on prépare le prochain caractère
        flot >> car;
        flot.putback(car);

       }; //-- fin de while(un_ddl_a_lire)

        // --- lecture éventuelle des temp mini et maxi ---
        if (((!flot.rdstate())&& (!(flot.eof())))) // lecture s'il n'y a pas d'erreur
        {if(strstr(ptout,"TEMPS_MINI=") != 0)
          { // cas d'un temps mini
            string toto;
            flot >> toto;
            // on vérifie la présence au bon endroit du mot clé TEMPS_MINI=
            if (toto != "TEMPS_MINI=")
             {cout << "\n erreur de syntaxe en lecture du temps mini, info lue: " << toto;
              cout << "\n DdlLim::Lecture(.. " << endl ;
              entreePrinc.MessageBuffer("**erreur**");
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);
              }          
            //lecture du temps mini
            string nomOuNombre;
            flot >> nomOuNombre;
            if (nomOuNombre != "fct_nD:")
             {t_min = ChangeReel(nomOuNombre);
              nom_fnD_t_min = "";
             }
            else
             {flot >> nom_fnD_t_min;};
           }
        };
        if (((!flot.rdstate())&& (!(flot.eof())))) // lecture s'il n'y a pas d'erreur
         {if(strstr(ptout,"TEMPS_MAXI=") != 0)
          { // cas d'un temps maxi
            string toto;
            flot >> toto;
            // on vérifie la présence au bon endroit du mot clé TEMPS_MAXI=
            if (toto != "TEMPS_MAXI=")
             {cout << "\n erreur de syntaxe en lecture du temps maxi ";
              cout << "\n DdlLim::Lecture(.. " << endl ;
              entreePrinc.MessageBuffer("**erreur**");
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);
              }          
            //lecture du temps maxi
            string nomOuNombre;
            flot >> nomOuNombre;
            if (nomOuNombre != "fct_nD:")
             {t_max = ChangeReel(nomOuNombre);
              nom_fnD_t_max = "";
             }
            else
             {flot >> nom_fnD_t_max;};
           }
          };  
        // lecture éventuel de l'indicateur de blocage "relatif"
        if (((!flot.rdstate())&& (!(flot.eof())))) // lecture s'il n'y a pas d'erreur
         if(strstr(ptout,"BLOCAGE_RELATIF_") != 0)
          { string toto; flot >> toto; // on passe le mot clé
            blocage_relatif = true;
            // message d'avertissement éventuel
            int taille_tab = tab.Taille();
            bool queDesCourbesDeCharge = true;
            for (int i=1; i<= taille_tab; i++) // on regarde s'il y n'y a que des courbes de charge
              if (tab(i).co_charge == "")     
                  { queDesCourbesDeCharge = false;} ;   
            if (!queDesCourbesDeCharge)
              	{ // cas où il n'y a au moins un ddl sans courbe de charge
              	  cout << "\n **** Warning !!! le blocage relatif ne fonctionne pas avec des blocages simples "
              	       << " le blocage relatif ne fonctionne qu'avec les ddls soumis a une courbe de charge ";
              	};
          };  
                   
       } // -- fin de lecture tant que le flot est valide
    }//-- fin du test sur existence de champ ou pas
   // enregistrement des infos 
   tab.Change_taille((int) lili.size());
   list <Ddlbloque>::iterator i;
   int j;
   for (i=lili.begin(),j=1 ; i != lili.end(); i++,j++)
           tab(j) = *i; 
   // dans le cas où il s'agit d'une condition de tangente imposée, il faut que 
   // le nombre de ddl =  la dimension de l'espace, car la condition représente un vecteur
   if (typeCL == TANGENTE_CL) 
   	 if (tab.Taille() != ParaGlob::Dimension())
       {cout << "\n erreur en lecture d'une   condition de tangente imposée,  "
             << " le nombre de dd (ici = " << tab.Taille() << ") doit etre egale a  la dimension"
             << "  de l'espace (ici = " << ParaGlob::Dimension()<<") ";
        cout << "\n DdlLim::Lecture(.. " << endl ;
        entreePrinc.MessageBuffer("**erreur**");
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);
        };          
      // verification en fonction de la dimension du pb
//       VerifDimDdl();
         
};

// examine si le ddlmin passé en argument possède les mêmes cibles que this
// c'est-à-dire s'il y a une intersection incohérente entre les deux tableaux de ddl de base
// ramène true s'il y a une intersection incohérente non nulle, false sinon
bool DdlLim::MemeCibleMaisDataDifferents(const DdlLim& d) const
	{ // l'opération est malheureusement combinatoire (en N^2) à moins de classer les ddlm
	  // mais pour l'instant ce n'est pas fait, je ne suis pas sûr que ici le temps soit un pb
      bool incoherence = false;	  
	  
      int tailtab = tab.Taille();
      int tailtabex = d.Taille();
      for (int i=1; i<= tailtab; i++)
       for (int j=1; j<= tailtabex; j++)
         if (tab(i).ddl.Id_nom() == d.ElemLim_const(j).Id_nom())
           if (tab(i).ddl != d.ElemLim_const(j))
             // si on a deux même noms de ddl et le reste qui n'est pas identique --> incohérence
               incoherence = true;
      // retour
      return incoherence;  
	};
        
// ramène true si le DdlLim contient l'enum_ddl passé en argument, false sinon
bool DdlLim::Existe_ici_leDdl(Enum_ddl enu) const
	{ // on passe en revue le tableau de ddl
	  int taille = tab.Taille();
	  for (int i=1;i<=taille;i++)
	    if (tab(i).ddl.Id_nom() == enu) 
	       return true;
	   // si on arrive ici, c'est que l'on n'a rien trouvé ! 
	   return false;   
	};
	
// ramène true si le DdlLim contient au moins un déplacement, false sinon
bool DdlLim::Existe_ici_un_deplacement() const
	{ // on passe en revue le tableau de ddl
	  int taille = tab.Taille();
	  for (int i=1;i<=taille;i++)
	  	{switch (ParaGlob::Dimension())
	  		{case 3: if (tab(i).ddl.Id_nom() == UZ) 
	                    return true;
	  		 case 2: if (tab(i).ddl.Id_nom() == UY) 
	                    return true;
	  		 case 1: if (tab(i).ddl.Id_nom() == UX) 
	                    return true;
	  		};
	  	};
	   // si on arrive ici, c'est que l'on n'a rien trouvé ! 
	   return false;   
	};
		
// Affiche les donnees liees au degre de liberte
void DdlLim::Affiche () const 
   { // affichage éventuelle du nom de maillage
     if (nom_maillage != NULL)
       { cout << "\n nom_mail= " << *nom_maillage;} else cout << "\n";
     // affichage éventuelle du type de CL
     if (typeCL != RIEN_TYPE_CL)
       { cout << "type_de_CL= " << NomTypeCL(typeCL);};
     // puis le reste
     if (champ)
        {cout << " ref_de_champ= "  << ref << ':';}
     else if (mvtsolide != NULL)
      {mvtsolide->Affiche();}
     else   	
        {cout << " ref= " << ref << ':';};
     for (int i=1; i<= tab.Taille();i++)
      {  (tab(i).ddl).Affiche();
         if (tab(i).co_charge != "")
            cout << " courbe_de_charge= " << (tab(i)).co_charge << " echelle= " << (tab(i)).echelle;
         if (tab(i).f_charge != "")
            cout << " fonction_nD_de_charge= " << (tab(i)).f_charge << " ";
         cout << " temps_mini= ";
         if (nom_fnD_t_min == "")
              {cout << t_min;}
         else {cout << " fct_nD: " << nom_fnD_t_min ;};
         cout   << " temps_maxi= ";
         if (nom_fnD_t_max == "")
              {cout << t_max;}
         else {cout << " fct_nD: " << nom_fnD_t_max ;};
         cout << " activité_actuelle: " << precedent;
         cout << "  blocage_relatif_ " << blocage_relatif << " ";
      };
     cout << endl;            
   };
		
		
// Realise l'egalite entre deux degres de liberte
 DdlLim& DdlLim::operator= (const DdlLim& d)
		{	if (d.nom_maillage == NULL)
		      { if (nom_maillage != NULL) {delete nom_maillage;nom_maillage = NULL;}}
		    else
		      { if (nom_maillage == NULL) nom_maillage = new string(*(d.nom_maillage));
		        else                      *nom_maillage = *(d.nom_maillage);
		       };
		    typeCL = d.typeCL;      
		    ref=d.ref;
		    tab = d.tab;
      nom_fnD_t_min = d.nom_fnD_t_min ;
      nom_fnD_t_max = d.nom_fnD_t_max ;
		    t_min = d.t_min;
		    t_max = d.t_max;
		    precedent = d.precedent;
		    champ = d.champ;
		    blocage_relatif = d.blocage_relatif;
		    if (d.mvtsolide != NULL)
		      { if (mvtsolide == NULL)
		      	  { mvtsolide = new MvtSolide(*(d.mvtsolide));}
		      	else
		      	  { (*mvtsolide) = *(d.mvtsolide);};
		      }
		    else // cas où d.mvtsolide est null
		     { if (mvtsolide != NULL)
		          {delete mvtsolide;mvtsolide = NULL;};
		     };
			return (*this);	
		};

//Surcharge d'operateur logique
bool DdlLim::operator == (const DdlLim& a) const
  {  if (nom_maillage == NULL)
        { if (a.nom_maillage != NULL) return false;        
         }
     else
        { if (a.nom_maillage == NULL) return false;
          // sinon les deux sont non null: on test leur égalité
          if (*nom_maillage != *(a.nom_maillage)) return false;         
         };    
     // maintenant on regarde les autres données
     if (typeCL != a.typeCL) return false;
     // 1) traitement du cas des mouvements solides
     bool apriorivrai = true;
     if (a.mvtsolide != NULL)
		{ if (mvtsolide == NULL)
		     { //apriorivrai = false; 
		       return false; }  // on arrete tout de suite
		  else
		     { apriorivrai = ((*mvtsolide) == *(a.mvtsolide));};
		};
	 // 2) traitement du rest	
     if (( ref==a.ref) && (tab==a.tab) 
         && (t_min == a.t_min) && (t_max == a.t_max)
         && (nom_fnD_t_min == a.nom_fnD_t_min)
         && (nom_fnD_t_max == a.nom_fnD_t_max)
         && (precedent == a.precedent)
         && (champ == a.champ) && (blocage_relatif == a.blocage_relatif)
         && apriorivrai)
         return true;
     else return false;    
   };
		 
// surcharge de l'operateur de lecture typée
istream & operator >> (istream & entree, DdlLim & dlim)
  { // vérification du type
    string type;
    entree >> type;
    if (type == "DdlLim") {dlim.champ = false;}
    else if (type == "DdlLim_de_champ") {dlim.champ = true;}
    else
      {cout << "\n erreur en lecture d'un DdlLim "; 
       Sortie (1);
       return entree;
       }
    // lecture d'un nom de maillage éventuel
    bool existe_nom_maillage; entree >> existe_nom_maillage;
    string nom;
    if (existe_nom_maillage) 
       { entree >> nom; 
         if (dlim.nom_maillage == NULL) 
            dlim.nom_maillage = new string(nom);
         else 
            *(dlim.nom_maillage) = nom;
        }; 
    // passage du nom de la référence puis le type de cl puis du tableau
    entree >> dlim.ref >> nom;
    dlim.typeCL = Id_nomTypeCL(nom);
    entree >> dlim.tab >> nom >> dlim.t_min >> nom >> dlim.t_max >> nom >> dlim.precedent; 
    entree >> nom >> dlim.blocage_relatif;
    // mouvement solide éventuel
    int iii=0;
    entree >> iii;
    if (iii == 0) // indique qu'il n'y a pas de mouvement solide
      {if (dlim.mvtsolide != NULL) // on supprime le mouvement solide s'il en existait un
          {delete dlim.mvtsolide;dlim.mvtsolide=NULL;};
      }
    else  // cas d'un mouvement solide
      { if (dlim.mvtsolide != NULL) // création s'il n'y en avait pas
          dlim.mvtsolide = new MvtSolide();
        entree >> *(dlim.mvtsolide); // lecture du mouvement solide
      };
      
    return entree;      
  };
  
// surcharge de l'operateur d'ecriture typée
ostream & operator << ( ostream & sort,const  DdlLim & dlim)
  { // tout d'abord un indicateur donnant le type 
    if (dlim.champ)
       {sort << "DdlLim_de_champ ";}
    else   
       {sort << "DdlLim ";};
    // puis le maillage éventuelle
    if (dlim.nom_maillage == NULL) 
       sort << false << " "; 
    else 
       sort << true << " " << *(dlim.nom_maillage) << " ";
    // maintenant la référence
    sort  << dlim.ref << " ";
    // le type de condition limite
    sort << NomTypeCL(dlim.typeCL) << " "; 
    // puis les data
    sort << dlim.tab;
    sort << " tmin= "  << dlim.t_min << " tmax= "  << dlim.t_max << " prec " << dlim.precedent;
    sort << " blocage_relatif= " << dlim.blocage_relatif;
    // mouvement solide éventuel
    if (dlim.mvtsolide == NULL)
       { sort << " 0 ";}
    else   
       { sort << " 1 " << (*(dlim.mvtsolide)) << " ";};
    sort << "\n"; 
    return sort;      
  };
    
// affichage et definition interactive des commandes
void DdlLim::Info_commande_DdlLim(ofstream & sort,bool plusieurs_maillages)
{  //On va proposer un menu
   string rep=" ";
   string nom_courbe="_";
   string nom_fonction_nD="_";
   double echelle = ConstMath::trespetit;
   double temps_mini = - ConstMath::trespetit;
   double temps_maxi =  ConstMath::tresgrand;
   // tableau des choix possibles
   Tableau <string> tab_choix(16);
   tab_choix(1) =  "\n (0 ou f) (defaut) (fin)               ";
   tab_choix(2) =   "\n (1)  choix d'un deplacement impose     ";
   tab_choix(3) =   "\n (2)  ou autre ddl impose     ";
   tab_choix(4) =   "\n (3)  valeur du ddl  ?     ";
   tab_choix(5) =   "\n (4)  ou utilisation d'une courbe de charge     ";
   tab_choix(6) =   "\n (5)  echelle  ";
   tab_choix(7) =   "\n (6)  temps mini ";
   tab_choix(8) =   "\n (7)  temps maxi ";
   tab_choix(9) =   "\n (8)  blocage relatif ";
   tab_choix(10) =   "\n (9)  condition de tangence ";
   tab_choix(11) =   "\n (10)  mouvement solide impose ";
   tab_choix(12) =   "\n (11)  champ de valeurs ";
   tab_choix(13) =   "\n (12)  liste de ddl existant ";
   tab_choix(14) =   "\n (13 ou ? )  information ";
   tab_choix(15) =   "\n (14)  plusieurs ddl de deplacement, nuls ";
   tab_choix(16) =   "\n (15)  utilisation d'une fonction nD de charge ";
   // tableau d'indexage pour limiter les choix
   int choix=1; // type de choix: ici le cas choix d'un ddl de depart
   Tableau <int> index(9);
   index(1) = 1; index(2) = 2; index(3) = 3;index(4) = 10;index(5) = 11;
   index(6) = 12; index(7) = 13; index(8) =14;index(9) =15;
   string nom_des_ddl="";
   bool blocage_relatif =false; // par défaut
   double valeur_du_ddl = 0.;
   bool plusieurs_ddl_deplacement_nul = false;
   string nom_ref="";
   string condition_tangence="";
   bool condition_mvt_solide=false;
   ostringstream  flux;
   bool champ_valeurs=false;
   string str_champ_valeurs="";
   
 
   while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
    {
     try
      { for (int i=1;i<=index.Taille();i++)
             cout << tab_choix(index(i));
        cout << "\n reponse ? ";
        rep = lect_return_defaut(false,"0"); cout << " grandeur lue " << rep;
        if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie 
          // c'est à la sortie que ce fait l'écriture donc ici
          {sort << "\n";
           if ((nom_des_ddl=="")&&(condition_tangence =="")&&(!condition_mvt_solide)
               &&(!champ_valeurs))
              break; // arrêt s'il n'y a pas eu de choix
           if (plusieurs_maillages)
             { cout << "\n nom du maillage ? ";
               string nom_mail;
               nom_mail= lect_chaine(); cout << " nom lu = "<< nom_mail;
               sort << "nom_mail= "<< nom_mail << " ";
             };
           sort << nom_ref <<" ";
           // ici plusieurs cas
           if ((condition_tangence =="")&&(!condition_mvt_solide)&&(!champ_valeurs))
            { // cas normal
              bool sortie_cote=false;
              if (((valeur_du_ddl != 0.)||(nom_courbe != "_")
                    || (nom_fonction_nD != "_"))
                  && (!plusieurs_ddl_deplacement_nul))
                {sort << " ' ";sortie_cote=true;};
              sort << nom_des_ddl ;
              if (sortie_cote) sort <<"= ";
              if (!plusieurs_ddl_deplacement_nul)
               {if (nom_courbe != "_")
                  {sort << " COURBE_CHARGE: "<<nom_courbe<<" ";}
                else if (sortie_cote == true)
                  {sort << valeur_du_ddl<<" ";};
                if (nom_fonction_nD != "_")
                  {sort << " Fonction_nD_CHARGE: "<<nom_fonction_nD<<" ";};
                if (echelle != ConstMath::trespetit)
                  sort << " ECHELLE: "<< echelle<<" ";
                if (sortie_cote)
                   sort << " ' ";
               };
             }
           else if (condition_mvt_solide)
            { // cas d'un mouvement solide
              sort << nom_des_ddl ;
              sort <<flux.str();
              if (nom_courbe != "_")
                {sort << " COURBE_CHARGE: "<<nom_courbe<<" ";};
              if (nom_fonction_nD != "_")
                {sort << " Fonction_nD_CHARGE: "<<nom_fonction_nD<<" ";};
              if (echelle != ConstMath::trespetit)
                sort << " ECHELLE: "<< echelle<<" ";
             }
           else if (champ_valeurs)
            { // cas d'un champ de valeur
              sort << str_champ_valeurs ;
             }
           else // cas d'une condition de tangence
            { sort << condition_tangence;};
           if (temps_mini != (- ConstMath::trespetit))
              sort << " TEMPS_MINI= "<< temps_mini<<" ";
           if (temps_maxi != ConstMath::tresgrand)
              sort << " TEMPS_MAXI= "<< temps_maxi<<" ";
           if (blocage_relatif)
              sort << " BLOCAGE_RELATIF_ "<<endl;
           break;
          };
        int num = ChangeEntier(rep);
        if (Minuscules(rep) == "?")
          num = 13;
        bool choix_valide=false;
        if ((num >= 0)&&(num<=16))
             { choix_valide=true; }
        else { cout << "\n Erreur on attendait un entier entre 0 et 16 !!, "
                    << "\n redonnez une bonne valeur"
                    << "\n ou taper f ou 0 pour arreter le programme"; 
               choix_valide=false;
             }
        switch (num)
         { case 0:  // sortie
             { break;} // normalement cela a déjà été filtré avant
           case 1:  // déplacement imposé
             { string repi=" ";
               cout    << "\n -- choix du ddl -- ";
               switch  (ParaGlob::Dimension())
                {case 1: cout << "\n (1)  UX "; break;
                 case 2: cout << "\n (1)  UX "
                              << "\n (2)  UY "; break;
                 case 3: cout << "\n (1)  UX "
                              << "\n (2)  UY "
                              << "\n (3)  UZ "; break;
                 default: cout << " ";
                }; cout << "\n";
               repi=lect_chaine();
               cout << " valeur lue "<<repi;
               if ((repi == "1")) {nom_des_ddl = " UX ";}
               else if ((repi == "2")) {nom_des_ddl = " UY ";}
               else if ((repi == "3")) {nom_des_ddl = " UZ ";}
               else { cout << "\n *** choix non valide !";break;};
               cout << "\n nom de la reference de noeuds associee? ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'N')
                {cout << "\n *** erreur, la premiere lettre de la ref de noeud "
                      << " doit etre N et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
               index.Change_taille(9);
               index(1) = 1; index(2) = 4; index(3) = 5; index(4) = 6;
               index(5) = 7;index(6) = 8;index(7) = 9;index(8) = 14;
               index(9) = 16;
               break;
              }
           case 2:  // un ddl autre qu'un déplacement
             { string repi="";
               cout    << "\n nom du ddl ? \n";
               repi=lect_chaine(); cout << " valeur lue "<<repi;
               if (!ExisteEnum_ddl(repi))
                {cout << "\n *** erreur, ce ddl n'existe pas ****";
                 break;
                };
               nom_des_ddl = repi;
               cout << "\n nom de la reference de noeuds associee? ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'N')
                {cout << "\n *** erreur, la premiere lettre de la ref de noeud "
                      << " doit etre N et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
               index.Change_taille(9);
               index(1) = 1; index(2) = 4; index(3) = 5; index(4) = 6;
               index(5) = 7;index(6) = 8;index(7) = 9;index(8) = 14;
               index(9) = 16;
               break;
              }
           case 3:  // une valeur de ddl
             { cout << "\n valeur du ddl (un reel)  ? ";
               valeur_du_ddl=lect_double();cout << " valeur lue ="<< valeur_du_ddl;
               index.Change_taille(5);
               index(1) = 1; index(2) = 7; index(3) = 8;
               index(4) = 9;index(5) = 14;
               break;
              }
           case 4:  // courbe de charge
             { cout << "\n nom de la courbe de charge  ? ";
               nom_courbe= lect_chaine();cout << " nom lu = "<< nom_courbe;
               index.Change_taille(7);
               index(1) = 1;index(2) = 6; index(3) = 7; index(4) = 8;index(5) = 9;
               index(6) = 14;index(7) = 16;
               break;
              }
           case 5:  // l'echelle
             { cout << "\n valeur de l'echelle (un reel)  ? ";
               echelle=lect_double();cout << " valeur lue ="<< echelle;
               index.Change_taille(6);
               index(1) = 1;index(2) = 7; index(3) = 8; index(4) = 9;index(5) = 14;
               index(6) = 16;
               break;
              }
           case 6:  // temps mini
              { cout << "\n valeur du temps mini (un reel)  ? ";
               temps_mini=lect_double();cout << " valeur lue ="<< temps_mini;
               index.Change_taille(5);
               index(1) = 1;index(2) = 7; index(3) = 8; index(4) = 9;index(5) = 14;
               break;
              }
           case 7:  // temps maxi
              { cout << "\n valeur du temps maxi (un reel)  ? ";
               temps_maxi=lect_double();cout << " valeur lue ="<< temps_maxi;
               index.Change_taille(5);
               index(1) = 1;index(2) = 7; index(3) = 8; index(4) = 9;index(5) = 14;
               break;
              }
           case 8:  // blocage relatif
              {cout << "\n --> le blocage est mis en relatif ";
               blocage_relatif = true;
               index.Change_taille(5);
               index(1) = 1;index(2) = 7; index(3) = 8; index(4) = 9;index(5) = 14;
               break;
              }
           case 9:  // condition de tangence
              {cout << "\n --> condition de tangence  ";
               if (ParaGlob::Dimension() != 3)
                { cout << "\n **** erreur il faut etre en dimension 3 pour cette condition !!";
                  break;
                };
               cout << "\n nom de la ref d'arete pour l'application de la condition ? ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'A')
                {cout << "\n *** erreur, la premiere lettre de la ref d'aretes "
                      << " doit etre A et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
               cout << "\n def du vecteur tangent ";
               condition_tangence += " typeCL_= TANGENTE_CL ";
               
               for (int i=1;i<=3;i++) // i représente la dimention
                { string compo; // on defini la composante
                  switch (i){ case 1: compo="UX";break; case 2:compo="UY";break;
                     case 3: compo="UZ";break;};
                  string repi=" ";
                  bool choix_valide=false;
                  while (!choix_valide)
                   { cout << "\n cas de "<<compo
                       << "\n (1)  valeur nulle    "
                       << "\n (2)  valeur non nulle   "
                       << "\n (3)  courbe de charge   "
                       << "\n (4)  fonction nD de charge \n";
                     repi=lect_chaine(); cout << " valeur lue "<<repi;
                     if ((repi == "1"))
                       {condition_tangence += " "+compo+" ";
                        choix_valide=true;                      
                       }
                     else if ((repi == "2"))
                       {condition_tangence += "' "+compo+"= ";
                        cout << "\n valeur de "<<compo<<"  ? ";
                        double val;
                        val=lect_double();cout << " valeur lue ="<< val;
                        condition_tangence += (ChangeReelSTring(val))+" ' ";
                        choix_valide=true;
                       }
                     else if ((repi == "3"))
                       {condition_tangence += "' "+compo+"= COURBE_CHARGE: ";
                        cout << "\n nom de la courbe de charge  ? ";
                        string nom_c;
                        nom_c= lect_chaine();cout << " nom lu = "<< nom_c;
                        condition_tangence += nom_c;
                        cout << "\n echelle (un reel)  ? ";
                        double val;
                        val=lect_double();cout << " valeur lue ="<< val;
                        condition_tangence += " ECHELLE: "+(ChangeReelSTring(val))+" ' ";
                        choix_valide=true;
                       }
                     else if ((repi == "4"))
                       {condition_tangence += "' "+compo+"= Fonction_nD_CHARGE: ";
                        cout << "\n nom de la fonction nD de charge  ? ";
                        string nom_c;
                        nom_c= lect_chaine();cout << " nom lu = "<< nom_c;
                        condition_tangence += nom_c;
                        choix_valide=true;
                       }
                     else { cout << "\n *** choix non valide !";choix_valide=false;};
                   };
                };
               index.Change_taille(5);
               index(1) = 1;index(2) = 7; index(3) = 8; index(4) = 9;index(5) = 14;
               break;
              }
           case 10:  // mouvement solide imposé
              {cout << "\n --> mouvement solide impose  ";
               cout << "\n nom de la reference de noeuds associee? ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'N')
                {cout << "\n *** erreur, la premiere lettre de la ref de noeud "
                      << " doit etre N et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
               // ici on utilise un string intermédiaire pour capter le flux
               MvtSolide mvt; // un mouvement par défaut
               mvt.Info_commande_MvtSolide(flux);
               condition_mvt_solide=true;
              
               index.Change_taille(8);
               index(1) = 1;index(2) = 5; index(3) = 6; index(4) = 7;index(5) = 8;
               index(6) = 9;index(7) = 14;index(8) = 16;
               break;
              }
           case 11:  // champ de valeurs
              {cout << "\n --> champ de valeurs impose  ";
               cout << "\n nom de la reference de noeuds associee? ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'N')
                {cout << "\n *** erreur, la premiere lettre de la ref de noeud "
                      << " doit etre N et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
               int nb_valeur=0;
               cout <<"\n nombre d'elements dans la reference ? ";
               nb_valeur=(int) lect_double(); cout << " nombre lu ="<< nb_valeur;
               string repa;
               str_champ_valeurs += "   champ_de:\n";
               bool erreur=false;
               for (int i=1;i<=nb_valeur;i++)
                { string nom_ddl="";
                  cout    << "\n nom du ddl "<<i<<" ? \n";
                  nom_ddl= lect_chaine(); cout << " nom lue "<<nom_ddl;
                  if (!ExisteEnum_ddl(nom_ddl))
                   {cout << "\n *** erreur, ce ddl n'existe pas ****, on sort de la condition !!";
                    erreur = true;
                    break;
                   };
                  str_champ_valeurs += "    ' "+nom_ddl+"= ";
                  // maintenant la valeur
                  cout << "\n  (1) valeur numerique ? "
                       << "\n  (2) courbe de charge ? "
                       << "\n  (4) fonction nD de charge ? ";
                  repa=lect_chaine(); cout << " rep lue: "<< repa;
                  if (repa=="1")
                   { double val= 0.;cout << "\n valeur ? ";
                     val=lect_double();cout << " valeur lue: "<< val;
                     str_champ_valeurs += (ChangeReelSTring(val))+" ' \n";
                   }
                  else if (repa=="2")
                   { cout << "\n nom de la courbe de charge  ? ";
                     string nom;
                     nom= lect_chaine();cout << " nom lu = "<< nom;
                     str_champ_valeurs += " COURBE_CHARGE: "+nom+" ' \n";
                   }
                  else if (repa=="3")
                   { cout << "\n nom de la fonction nD de charge  ? ";
                     string nom;
                     nom= lect_chaine();cout << " nom lu = "<< nom;
                     str_champ_valeurs += " Fonction_nD_CHARGE: "+nom+" ' \n";
                   };
                };
               if (erreur)
                break; // on sort s'il y a eu une erreur
               str_champ_valeurs += "fin_champ_de_ ";
               champ_valeurs=true;
               index.Change_taille(5);
               index(1) = 1;index(2) = 7; index(3) = 8; index(4) = 9;index(5) = 14;
               break;
              }
           case 12:  // liste des ddl existants
              {cout << "\n --> liste des ddl existants  ";
               int nb_ddl = nombre_maxi_de_type_de_ddl;
               cout << "\n";
               for (int i=1;i<= nombre_maxi_de_type_de_ddl;i++)
                 cout << Nom_ddl(Enum_ddl(i)) << " ";
               cout << "\n";
               break;
              }
           case 13:  // informations
              {cout << "\n Il faut se reporter a la document pour avoir une explication detaille de chaque  "
                    << "\n conditions. Globalement les conditions possibles sont les suivantes: "
                   << "\n (1)  choix d'un deplacement impose --> UX ou UY ou UZ   "
                    << "\n (2)  autre ddl impose --> a choisir dans la liste des ddl diponibles    "
                    << "\n (3)  valeur du ddl  --> on definit une valeur numerique "
                    << "\n (4)  utilisation d'une courbe de charge --> la valeur du ddl = la valeur d'une courbe de charge    "
                    << "\n (5)  echelle -->  facteur multiplicatif de la valeur du ddl (fixe ou dependant d'une fct f(t)"
                    << "\n (6)  temps mini --> en dessous du temps mini, la condition n'existe pas "
                    << "\n (7)  temps maxi --> au dessus du temps maxi la condition n'existe pas "
                    << "\n (8)  blocage relatif --> a partir de temps mini, la condition est ajoute a la valeur existante du ddl "
                    << "\n (9)  condition de tangence --> permet de definir des conditions limites pour les elements SFE "
                    << "\n (10)  mouvement solide impose --> permet de definir des mouvements d'ensemble pour un groupe de noeuds "
                    << "\n (11)  champ de valeurs --> permet de definir de maniere concise un ensemble de conditions non identiques "
                    << "\n (12)  liste de ddl existant --> donne la liste des ddl possibles "
                    << "\n (13 ou ? )  information --> ce message "
                    << "\n (14)  plusieurs ddl de deplacement, nuls --> forme concise pour mettre des deplacements  a 0  "
                    << "\n (15)  une fonction nD --> la valeur du ddl = la valeur de la fonction, eventuellement x Co charge  ";
               break;
              }
           case 14:  // plusieurs ddl de deplacement, nuls
             { string repi=" ";
               nom_des_ddl = "";
               while (repi != "f")
                { cout    << "\n -- choix du ddl -- ";
                  switch  (ParaGlob::Dimension())
                   {case 1: cout << "\n (1)  UX "
                                 << "\n (f) (defaut) fin"; break;
                    case 2: cout << "\n (1)  UX "
                                 << "\n (2)  UY "
                                 << "\n (f) (defaut) fin" ; break;
                    case 3: cout << "\n (1)  UX "
                                 << "\n (2)  UY "
                                 << "\n (3)  UZ "
                                 << "\n (f) (defaut) fin" ; break;
                    default: cout << " ";
                   }; cout << "\n";
                  repi= lect_return_defaut(false,"f");; cout << " valeur lue "<<repi;
                  if ((repi == "1")) {nom_des_ddl += " UX ";}
                  else if ((repi == "2")) {nom_des_ddl += " UY ";}
                  else if ((repi == "3")) {nom_des_ddl += " UZ ";}
                  else if ((Minuscules(repi) == "f")||(Minuscules(repi) == "0")) {}
                  else { cout << "\n *** choix non valide !";};
                };
               valeur_du_ddl=0.;
               cout << "\n nom de la reference de noeuds associee? ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'N')
                {cout << "\n *** erreur, la premiere lettre de la ref de noeud "
                      << " doit etre N et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
               index.Change_taille(7);
               index(1) = 1; index(2) = 5; index(3) = 6; index(4) = 7;
               index(5) = 8;index(6) = 9;index(7) = 14;
               break;
              }
           case 15:  // fonction nD de charge
             { cout << "\n nom de la fonction nD de charge  ? ";
               nom_fonction_nD= lect_chaine();cout << " nom lu = "<< nom_fonction_nD;
               index.Change_taille(7);
               index(1) = 1;index(2) = 6; index(3) = 7; index(4) = 8;index(5) = 9;
               index(6) = 14;index(7) = 5;
               break;
              }
           default:
             cout << "\n le cas "<<rep<<" n'est pas  traite !!, bizarre, il faut se plaindre !! ";
          };
        }    
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
        {  cout << "\n Erreur on attendait un des mots cles proposes !!, "
                << "\n redonnez une bonne valeur"
                << "\n ou taper f ou 0 pour sortir "; 
        };
      }; //-- fin du while
   sort << flush;

};
		
    
//------------------------------ FONCTIONS PROTEGEES --------------------    
     
// verification en fonction de la dimension du pb
// par exemple en dim 2 d'existance des UZ ou des X3 etc..
void DdlLim::VerifDimDdl()
  {  //pour l'instant ne fait rien
  };

// ====================================================================
//                       classe Ddlbloque  
// ====================================================================

// surcharge de l'operateur d'ecriture
ostream &  operator << (ostream & sort,const  DdlLim::Ddlbloque & a)
  { // écriture du type
    sort << "Ddlbloque ";
    // les données
    sort << a.ddl << " "  << a.co_charge << " " << a.echelle << " "<< a.f_charge << " " ;
    return sort;      
  };
  // surcharge de l'operator de lecture
istream & operator >> (istream & entree, DdlLim::Ddlbloque& a)
  { // vérification du type
    string type;
    entree >> type;
    if (type != "Ddlbloque")
      {Sortie (1);
       return entree;
       }
    // entrée des données  
    entree >> a.ddl;
    entree >> a.co_charge >> a.echelle >> a.f_charge;
    return entree;      
  };

  // surcharge de l'opérateur d'affectation
DdlLim::Ddlbloque& DdlLim::Ddlbloque::operator= (const DdlLim::Ddlbloque& d)
		{	ddl=d.ddl;
			co_charge=d.co_charge;
			echelle = d.echelle;
   f_charge = d.f_charge;
			return (*this);	
		};
		
		//Surcharge d'operateur logique
bool DdlLim::Ddlbloque::operator == ( DdlLim::Ddlbloque& a)
  {  if ( (ddl==a.ddl)
          && (co_charge == a.co_charge) && (echelle == a.echelle)
          && (f_charge == a.f_charge)
        )
         return true;
     else return false;    
   };
		 
bool DdlLim::Ddlbloque::operator != ( DdlLim::Ddlbloque& a)		 
    { return !(*this == a);}; 
    
// lecture dans le cas particulier d'un champ
list <DdlLim::Ddlbloque> DdlLim::Lecture_champ(UtilLecture & entreePrinc)
  {  // def de variables inter
     char tat[250]; char * ta = tat; char tt[100]; char * t = tt;
     // def de la liste de ddl qui sera retournée
     list <Ddlbloque> lili;
     // le traitement qui suit s'effectue soit une fois si ce n'est pas un champ, soit n fois jusqu'a
     // ce que la ligne contienne le mot clé fin_champ_de_ qui doit être le premier enregistrement de la ligne
     bool derniere_ligne = true; // le cas courant c'est qu'il y a une seule ligne a exploiter
     do  ///__________ la grande boucle
     { // dans ce cas dans le fichier d'entrée les infos se trouvent sur les lignes qui suivent
       // via normalement un fichier (mais ce n'est pas obligatoire)  donc on passe 
       // une ligne à chaque passage jusqu'à trouver le mot clé fin_champ_de_
       entreePrinc.NouvelleDonnee();  // lecture d'une nouvelle ligne 
       // on lira jusqu'à la ligne qui contiend le mot clé: fin_champ_de_ en début d'enregistrement
       if (strstr(entreePrinc.tablcar,"fin_champ_de_")!=NULL)
          {derniere_ligne= true; string toto; *(entreePrinc.entree) >> toto;
           if (toto != "fin_champ_de_")
            { cout << "\n erreur de lecture d'un champ de valeurs "
                   << " le premier mot de la derniere ligne devait etre fin_champ_de_ \n";
              entreePrinc.MessageBuffer("*** lecture champ de valeurs ****" );
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1); 
             } 
           }
       else
          {derniere_ligne = false;};
     
       //recup de la fin de la ligne
       char tout[150] ; char * ptout = tout; (entreePrinc.entree)->get(ptout,150);
       // avant la lecture on remplace toutes les virgules par des espaces
       char * ii = strchr(ptout,',');
       while (ii != NULL) { *ii = ' '; ii = strchr(ptout,',');}
	   // def du flot intermédiaire         
       #ifndef ENLINUX_STREAM
        istringstream flot(ptout);
       #else 
         istrstream flot(ptout);
       #endif       
       // lecture tant que le flot est valide
       while (flot.rdstate() == 0)
       // tout d'abord on passe les espaces  qui sont des séparateurs
        // lecture du prochain caractère sans modifier le flot
       {char car; // = flot.peek();
//---- debug
//cout << "\n debug DdlLim::Lecture_champ(  flot.rdstate()= " << flot.rdstate()<< endl;
//--- fin debug
       
        flot >> car;
        // éventuellement il n'avait pas bien déterminé la fin de l'enregistrement
        // au niveau du while, dans ce cas si durant la lecture de car il y a eu un pb
        // cela signifie qu'en fait la ligne était terminée donc on s'arrête
        if (flot.rdstate() != 0) break;
        while ( (car==' ')  && (flot.rdstate() == 0 ))
         // cas où le prochain caractère est un espace 
         { flot >> car; }
        flot.putback(car); 
          
        if (!derniere_ligne)
         {// on définit un  ddl pour la lecture
          Ddlbloque elem;  
          // deux cas, soit un ddl nulle par defaut, soit une valeur non nulle imposee
          // soit le caractère est ' , signifie que c'est un ddl avec une valeur
          // imposée
          if ( (car=='\'') && (flot.rdstate() == 0 ))
           {// on passe le premier  '
            flot >> car; 
            // on lit jusqu'au prochain ' en non formaté
            flot.get(ta,150,'\'');
            // on passe ce dernier '
            flot >> car; 
            // on recherche le  = pour mettre un blanc a la place
            char * ii = strchr(ta,'\'');char * pii=ii; // sauvegarde de l'adresse
            ii = strchr(ta,'='); // on recherche le =
            if (ii == NULL)
              { cout << "\n erreur de syntaxe dans la definition des conditions limites "
                     << " imposees a une valeur non nulle ";
                cout << " le ddl doit etre separe de la valeur par le signe = , caractere non"
                    << "  trouve ";
                entreePrinc.MessageBuffer("*** lecture d'une reference de ddl bloquee ****" );
                throw (UtilLecture::ErrNouvelleDonnee(-1));
                Sortie(1);     
               }
            *ii = ' '; // supprime le =  
            
            // def du flux intermediaire 
            #ifndef ENLINUX_STREAM
              istringstream flux (ta);
            #else 
              istrstream flux (ta);
            #endif          
           
            flux >> t ;
            elem.ddl.Change_nom(t);
            // on regarde s'il ne s'agit pas d'une courbe de charge imposée
            bool sans_courbe_ou_fct_nD=true; // variable locale
            // a) cas d'une courbe
            if(strstr(ta,"COURBE_CHARGE:")!=0)
               { // cas d'une courbe de charge
                 string toto;
                 flux >> toto >> elem.co_charge;
                 // on vérifie la présence au bon endroit du mot clé COURBE_CHARGE=
                 if (toto != "COURBE_CHARGE:")
                  {cout << "\n erreur de syntaxe en lecture du nom de la courbe ";
                   cout << "\n DdlLim::Lecture_champ(.. " << endl ;
                   entreePrinc.MessageBuffer("**erreur**");
                   throw (UtilLecture::ErrNouvelleDonnee(-1));
                   Sortie(1);          
                  };
                 // on récupère l'échelle éventuellement
                 if(strstr(ta,"ECHELLE:")!=0)
                   { // cas où il y a un facteur d'échelle
                     flux >> toto;
                     if (toto != "ECHELLE:")
                      {cout << "\n erreur de syntaxe en lecture du facteur d'échelle ";
                       cout << "\n DdlLim::Lecture_champ(.. " << endl ;
                       entreePrinc.MessageBuffer("**erreur**");
                       throw (UtilLecture::ErrNouvelleDonnee(-1));
                       Sortie(1);          
                      };
                     // lecture du facteur
                     flux >> elem.echelle; 
                   };
             };
            // b) cas d'une fonction nD
            if(strstr(ta,"Fonction_nD_CHARGE:")!=0)
             { // cas d'une fonction nD
               string toto;
               flux >> toto >> elem.f_charge;
               sans_courbe_ou_fct_nD=false;
               // on vérifie la présence au bon endroit du mot clé Fonction_nD_CHARGE:
               if (toto != "Fonction_nD_CHARGE:")
                {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD ";
                 cout << "\n DdlLim::Lecture_champ(.. " << endl ;
                 entreePrinc.MessageBuffer("**erreur**");
                 throw (UtilLecture::ErrNouvelleDonnee(-1));
                 Sortie(1);          
                };
             };
           
            // si aucune courbe ou fct nD
            if (sans_courbe_ou_fct_nD)
               // cas où c'est une valeur fixe
               { flux  >> elem.ddl.Valeur();} 
            elem.ddl.Change_fixe (true);
           }
          else if (flot.rdstate() == 0 ) // il s'agit d'un ddl à 0  
           {//un ddl nulle par defaut 
            flot >> t;
            elem.ddl.Change_nom(t); 
            elem.ddl.Valeur() = 0;
            elem.ddl.Change_fixe (true);
            }
          // on ne verifie pas que l'on n'utilise pas deux fois le meme identificateur de ddl
          // avec deux valeurs differentes car dans le cas d'un champ il y a obligatoirement plusieurs fois le même ddl
          // stockage   
          lili.push_back(elem);           
          }  
        else // cas de la dernière ligne
         {// lecture éventuelle des temp mini et maxi
          if (((!flot.rdstate())&& (!(flot.eof())))) // lecture s'il n'y a pas d'erreur
            {if(strstr(ptout,"TEMPS_MINI=") != 0)
             {// cas d'un temps mini
              string toto;
              flot >> toto;
              // on vérifie la présence au bon endroit du mot clé TEMPS_MINI=
              if (toto != "TEMPS_MINI=")
               {cout << "\n erreur de syntaxe en lecture du temps mini, info lue: " << toto;
                cout << "\n DdlLim::Lecture_champ(.. " << endl ;
                entreePrinc.MessageBuffer("**erreur**");
                throw (UtilLecture::ErrNouvelleDonnee(-1));
                Sortie(1);
                }          
              //lecture du temps mini
              flot >> t_min;
              }
             }  
            if (((!flot.rdstate())&& (!(flot.eof())))) // lecture s'il n'y a pas d'erreur
             {if(strstr(ptout,"TEMPS_MAXI=") != 0)
              {// cas d'un temps maxi
               string toto;
               flot >> toto;
               // on vérifie la présence au bon endroit du mot clé TEMPS_MAXI=
               if (toto != "TEMPS_MAXI=")
                {cout << "\n erreur de syntaxe en lecture du temps maxi ";
                 cout << "\n DdlLim::Lecture_champ(.. " << endl ;
                 entreePrinc.MessageBuffer("**erreur**");
                 throw (UtilLecture::ErrNouvelleDonnee(-1));
                 Sortie(1);
                 }          
               //lecture du temps maxi
               flot >> t_max;
               }
              };
            // à la fin on considère que c'est fini, il n'y a plus d'info spécifique à lire
            // donc on sort de la boucle
            break;
         } //-- fin du cas de la dernière ligne
             
       } //-- fin du while (flot.rdstate() == 0)
      }   ///__________ fin de la grande boucle
     while(! derniere_ligne); 
     
   // dans le cas où il s'agit d'un champ de conditions de tangente imposée, il faut que 
   // la condition soit un multiple de la dimension de l'espace, car chaque condition représente un
   // vecteur
   if (typeCL == TANGENTE_CL)
   	{if ((tab.Taille() % ParaGlob::Dimension()) != 0)
       {cout << "\n erreur en lecture d'un champ de condition de tangente imposée,  "
             << " le nombre de dd (ici = " << tab.Taille() << ") doit etre multiple de la dimension"
             << "  de l'espace (ici = " << ParaGlob::Dimension()<<") ";
        cout << "\n DdlLim::Lecture_champ(.. " << endl ;
        entreePrinc.MessageBuffer("**erreur**");
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);
        };          
   	};
   
   return lili;             
   };

// lecture dans le cas particulier d'un mouvement solide
list <DdlLim::Ddlbloque> DdlLim::Lecture_mvtSolide(UtilLecture & entreePrinc)
  {  // on commence par lire les mouvements solides
     if (mvtsolide == NULL)
        mvtsolide = new MvtSolide(); // création s'il n'existe pas
     mvtsolide->Lecture_mouvements_solides(&entreePrinc);
     // def de la liste de ddl qui sera retournée
     list <Ddlbloque> lili;
     // on définit les ddl bloque associés
     int dima = ParaGlob::Dimension(); 
     Ddlbloque elem; // def d'un ddl courant
     elem.ddl.Change_fixe (true);    
     switch (dima)
       { case 3: {elem.ddl.Change_nom(UZ); lili.push_front(elem);}
       	 case 2: {elem.ddl.Change_nom(UY); lili.push_front(elem);}
         case 1: {elem.ddl.Change_nom(UX); lili.push_front(elem);}
     	};
     // def d'un string pour les lectures de chaine
     string nom; 	
     // maintenant on regarde s'il y a une courbe de charge
     // on regarde s'il ne s'agit pas d'une courbe de charge imposée
     if (strstr(entreePrinc.tablcar,"COURBE_CHARGE:")!=NULL)
       { // cas d'une courbe de charge
         *(entreePrinc.entree) >> nom;
         // on vérifie la présence au bon endroit du mot clé COURBE_CHARGE=
         if (nom != "COURBE_CHARGE:")
          {cout << "\n erreur de syntaxe en lecture du nom de la courbe "
                << " on a lue " << nom << " alors que l'on attendait : COURBE_CHARGE: ";
           cout << "\n DdlLim::Lecture_mvtSolide(.. " << endl ;
           entreePrinc.MessageBuffer("**erreur**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          };
         // on se sert du premier ddlbloqué pour stocker la courbe de charge
         Ddlbloque & elem = *(lili.begin()); 
         // lecture de la courbe
         *(entreePrinc.entree) >> elem.co_charge;
         // on récupère l'échelle éventuellement
         if (strstr(entreePrinc.tablcar,"ECHELLE:")!=NULL)
           { // cas où il y a un facteur d'échelle
             *(entreePrinc.entree) >> nom;
             if (nom != "ECHELLE:")
              {cout << "\n erreur de syntaxe en lecture du facteur d'echelle "
                    << " on a lue " << nom << " alors que l'on attendait ECHELLE: ";
               cout << "\n DdlLim::Lecture(.. " << endl ;
               entreePrinc.MessageBuffer("**erreur**");
               throw (UtilLecture::ErrNouvelleDonnee(-1));
               Sortie(1);          
             }
             // lecture du facteur
             *(entreePrinc.entree) >> elem.echelle; 
           };
       };
     if (strstr(entreePrinc.tablcar,"Fonction_nD_CHARGE:")!=NULL)
       { // cas d'une fonction nD  de charge
         *(entreePrinc.entree) >> nom;
         // on vérifie la présence au bon endroit du mot clé Fonction_nD_CHARGE:
         if (nom != "Fonction_nD_CHARGE:")
          {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD "
                << " on a lue " << nom << " alors que l'on attendait : Fonction_nD_CHARGE: ";
           cout << "\n DdlLim::Lecture_mvtSolide(.. " << endl ;
           entreePrinc.MessageBuffer("**erreur**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          };
         // on se sert du premier ddlbloqué pour stocker la courbe de charge
         Ddlbloque & elem = *(lili.begin()); 
         // lecture de la courbe
         *(entreePrinc.entree) >> elem.f_charge;
       };
     // lecture éventuelle des temp mini et maxi
     if (strstr(entreePrinc.tablcar,"TEMPS_MINI=")!=NULL)
          { // cas d'un temps mini
            *(entreePrinc.entree) >> nom;
            // on vérifie la présence au bon endroit du mot clé TEMPS_MINI=
            if (nom != "TEMPS_MINI=")
             {cout << "\n erreur de syntaxe en lecture du temps mini, info lue: " << nom
                   << " alors que l'on attendait : TEMPS_MINI=";
              cout << "\n DdlLim::Lecture(.. " << endl ;
              entreePrinc.MessageBuffer("**erreur**");
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);
              }          
            //lecture du temps mini
            *(entreePrinc.entree)  >> t_min;
          };
     if (strstr(entreePrinc.tablcar,"TEMPS_MAXI=")!=NULL)
          { // cas d'un temps maxi
            *(entreePrinc.entree) >> nom;
            // on vérifie la présence au bon endroit du mot clé TEMPS_MAXI=
            if (nom != "TEMPS_MAXI=")
             {cout << "\n erreur de syntaxe en lecture du temps maxi, info lue: " << nom
                   << " alors que l'on attendait : TEMPS_MAXI=";
              cout << "\n DdlLim::Lecture(.. " << endl ;
              entreePrinc.MessageBuffer("**erreur**");
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);
              }          
            //lecture du temps maxi
            *(entreePrinc.entree) >> t_max;
           };
     // lecture éventuel de l'indicateur de blocage "relatif"
     if (strstr(entreePrinc.tablcar,"BLOCAGE_RELATIF_")!=NULL)
          { *(entreePrinc.entree) >> nom;
            // on vérifie la présence au bon endroit du mot clé BLOCAGE_RELATIF_
            if (nom != "BLOCAGE_RELATIF_")
             {cout << "\n erreur de syntaxe en lecture de l'indicateur de  blocage relatif, info lue: " << nom
                   << " alors que l'on attendait : BLOCAGE_RELATIF_";
              cout << "\n DdlLim::Lecture(.. " << endl ;
              entreePrinc.MessageBuffer("**erreur**");
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);
              }          
            blocage_relatif = true;
          };  
   
     return lili;             
   };
