// GetDP - Copyright (C) 1997-2021 P. Dular and C. Geuzaine, University of Liege
//
// See the LICENSE.txt file for license information. Please report all
// issues on https://gitlab.onelab.info/getdp/getdp/issues.

#include <stdlib.h>
#include "ProData.h"
#include "GeoData.h"
#include "DofData.h"
#include "Get_DofOfElement.h"
#include "Get_ConstraintOfElement.h"
#include "ExtendedGroup.h"
#include "Cal_Quantity.h"
#include "Message.h"

extern struct Problem Problem_S ;
extern struct CurrentData Current ;

extern int     TreatmentStatus ;

extern double  Flag_ORDER ;

extern List_T  *PreResolutionIndex_L ;

struct BasisFunction    * BasisFunction_P ;
int                     Nbr_ElementaryBF, Flag_SubSpace ;
struct Group            * GroupSupport_P, * GroupEntity_P ;

/* ------------------------------------------------------------------------ */
/*  G e t _ I n i t D o f O f E l e m e n t                                 */
/* ------------------------------------------------------------------------ */

void  Get_InitDofOfElement(struct Element * Element)
{
  Element->ElementTrace = NULL ;
  Element->NumLastElementForNodesCoordinates      = -1 ;
  Element->NumLastElementForGroupsOfEntities      = -1 ;
  Element->NumLastElementForSolidAngle            = -1 ;
  Element->NumLastElementForSortedNodesByFacet    = -1 ;
}

/* ------------------------------------------------------------------------ */
/*  G e t _ D o f O f E l e m e n t                                         */
/* ------------------------------------------------------------------------ */

void  Get_DofOfElement(struct Element          * Element,
		       struct FunctionSpace    * FunctionSpace_P,
		       struct QuantityStorage  * QuantityStorage_P,
		       List_T                  * BasisFunctionIndex_L)
{
  struct BasisFunction  * BasisFunction_P0 ;
  int  Nbr_BasisFunction, Nbr_BasisFunctionAll, i_BFunction, StartingIndex, i ;
  int  * BasisFunctionIndex_P0 = NULL ;

  Current.Element = Element ;
  Nbr_ElementaryBF = 0 ;

  /* Get the SubSpace */

  Nbr_BasisFunctionAll = List_Nbr(FunctionSpace_P->BasisFunction) ;
  BasisFunction_P0 = (Nbr_BasisFunctionAll) ?
    (struct BasisFunction*)List_Pointer(FunctionSpace_P->BasisFunction, 0) : NULL ;

  if (!BasisFunctionIndex_L) {
    Flag_SubSpace = 0 ;
    Nbr_BasisFunction = Nbr_BasisFunctionAll ;
  }
  else {
    Flag_SubSpace = 1 ;
    Nbr_BasisFunction = List_Nbr(BasisFunctionIndex_L) ;
    BasisFunctionIndex_P0 = (Nbr_BasisFunction) ?
      (int*)List_Pointer(BasisFunctionIndex_L, 0) : NULL ;
  }

  /* Set the DofData if explicitely specified */

  switch (TreatmentStatus) {
  case STATUS_CAL :  case STATUS_POS :
    if(QuantityStorage_P->DefineQuantity->DofData)
      FunctionSpace_P->DofData = QuantityStorage_P->DefineQuantity->DofData ;
    else
      FunctionSpace_P->DofData = FunctionSpace_P->MainDofData ;
    break;
  }

  /*  For each subset of Basis Functions */

  for (i = 0 ; i < Nbr_BasisFunction ; i++) {

    i_BFunction = (!Flag_SubSpace)? i : BasisFunctionIndex_P0[i] ;

    BasisFunction_P = BasisFunction_P0 + i_BFunction ;
    GroupSupport_P = (struct Group*)
      List_Pointer(Problem_S.Group, BasisFunction_P->SupportIndex) ;

    /*  If the BasisFunction exists for this kind of element
	   the interpolation order is lower or equal to the maximum order allowed
	   the element is in the support of the BasisFunction */

    if ( ( BasisFunction_P->ElementType & Current.Element->Type )
	 &&
	 ( Flag_ORDER < 0. || BasisFunction_P->Order <= Flag_ORDER )
	 &&
	 ( (GroupSupport_P->Type == REGIONLIST  &&
	    List_Search(GroupSupport_P->InitialList, &Element->Region, fcmp_int))
	   ||
	   (GroupSupport_P->Type == ELEMENTLIST  &&
	    Check_IsEntityInExtendedGroup(GroupSupport_P, Element->Num, 0)) ) ) {

      GroupEntity_P = (struct Group*)
	List_Pointer(Problem_S.Group, BasisFunction_P->EntityIndex) ;

      switch (GroupEntity_P->FunctionType) {

      case NODESOF :
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
           Element->GeoElement->NbrNodes, Element->GeoElement->NumNodes,
	   0, i_BFunction, NODESOF, NULL) ;
	break ;

      case EDGESOF :  case EDGESOFTREEIN :
	if (Element->GeoElement->NbrEdges == 0)
	  Geo_CreateEdgesOfElement(Element->GeoElement) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
           Element->GeoElement->NbrEdges, Element->GeoElement->NumEdges,
	   0, i_BFunction, EDGESOF, NULL) ;
	break ;

      case FACETSOF :  case FACETSOFTREEIN :
	if (Element->GeoElement->NbrEdges == 0)
	  Geo_CreateEdgesOfElement(Element->GeoElement) ;
	if (Element->GeoElement->NbrFacets == 0)
	  Geo_CreateFacetsOfElement(Element->GeoElement) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
           Element->GeoElement->NbrFacets, Element->GeoElement->NumFacets,
	   0, i_BFunction, FACETSOF, NULL) ;
	break ;

      case VOLUMESOF :
	Get_CodesOfElement(FunctionSpace_P, QuantityStorage_P,
                           1, &Element->GeoElement->Num,
			   0, i_BFunction, VOLUMESOF, NULL) ;
	break ;

      case GROUPSOFNODESOF :
	Get_GroupsOfElementaryEntitiesOfElement
	  (Element, &StartingIndex,
	   Element->GeoElement->NbrNodes, Element->GeoElement->NumNodes,
	   BasisFunction_P) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
	   Element->NbrGroupsOfEntities, Element->NumGroupsOfEntities,
	   StartingIndex, i_BFunction, GROUPSOFNODESOF, Element->NumSubFunction[1]) ;
	break ;

      case GROUPSOFEDGESONNODESOF :
	if (Element->GeoElement->NbrEdges == 0)
	  Geo_CreateEdgesOfElement(Element->GeoElement) ;
	Get_GroupsOfEdgesOnNodesOfElement(Element, &StartingIndex) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
	   Element->NbrGroupsOfEntities, Element->NumGroupsOfEntities,
	   StartingIndex, i_BFunction, GROUPSOFEDGESONNODESOF, NULL) ;
	break ;

      case GROUPSOFEDGESOF :
	if (Element->GeoElement->NbrEdges == 0)
	  Geo_CreateEdgesOfElement(Element->GeoElement) ;
	Get_GroupsOfElementaryEntitiesOfElement
	  (Element, &StartingIndex,
	   Element->GeoElement->NbrEdges, Element->GeoElement->NumEdges,
	   BasisFunction_P) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
	   Element->NbrGroupsOfEntities, Element->NumGroupsOfEntities,
	   StartingIndex, i_BFunction, GROUPSOFEDGESOF, NULL) ;
	break ;

      case GROUPSOFFACETSOF :
	if (Element->GeoElement->NbrFacets == 0)
	  Geo_CreateFacetsOfElement(Element->GeoElement) ;
	Get_GroupsOfElementaryEntitiesOfElement
	  (Element, &StartingIndex,
	   Element->GeoElement->NbrFacets, Element->GeoElement->NumFacets,
	   BasisFunction_P) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
	   Element->NbrGroupsOfEntities, Element->NumGroupsOfEntities,
	   StartingIndex, i_BFunction, GROUPSOFFACETSOF, NULL) ;
	break ;

      case REGION :
	Get_RegionForElement(Element, &StartingIndex, BasisFunction_P) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
	   Element->NbrGroupsOfEntities, Element->NumGroupsOfEntities,
	   StartingIndex, i_BFunction, REGION, Element->NumSubFunction[1]) ;
	break ;

      case GROUPOFREGIONSOF :
        Get_GroupOfRegionsForElement(Element, &StartingIndex, BasisFunction_P) ;
        Get_CodesOfElement
          (FunctionSpace_P, QuantityStorage_P,
           Element->NbrGroupsOfEntities, Element->NumGroupsOfEntities,
           StartingIndex, i_BFunction, GROUPOFREGIONSOF, Element->NumSubFunction[1]) ;
        break ;

      case GLOBAL :
	Get_GlobalForElement(Element, &StartingIndex, BasisFunction_P) ;
	Get_CodesOfElement
	  (FunctionSpace_P, QuantityStorage_P,
	   Element->NbrGroupsOfEntities, Element->NumGroupsOfEntities,
	   StartingIndex, i_BFunction, GLOBAL, NULL) ;
	break ;
      }

    }  /* if Region ... */

  }  /* for i ... */

  QuantityStorage_P->NbrElementaryBasisFunction = Nbr_ElementaryBF ;
}

/* ------------------------------------------------------------------------ */
/*  G e t _ G r o u p s O f E l e m e n t a r y E n t i t i e s             */
/*                                                       O f E l e m e n t  */
/* ------------------------------------------------------------------------ */

void  Get_GroupsOfElementaryEntitiesOfElement
  (struct Element * Element,
   int * StartingIndex, int Nbr_ElementaryEntities, int Num_ElementaryEntities[],
   struct BasisFunction * BasisFunction_P)
{
  /* external input/output :  GroupEntity_P     : In  */

  int            i, j, Num_Entity, Nbr_SubFunction, i_SF ;
  struct TwoInt  * Key_P ;

  if (Element->NumLastElementForGroupsOfEntities != Element->Num) {
    Element->NumLastElementForGroupsOfEntities = Element->Num ;
    Element->NbrGroupsOfEntities = 0 ;
  }

  *StartingIndex = Element->NbrGroupsOfEntities ;

  if (GroupEntity_P->ExtendedList == NULL) Generate_ExtendedGroup(GroupEntity_P) ;

  for (i = 0 ; i < Nbr_ElementaryEntities ; i++) {
    Num_Entity = abs(Num_ElementaryEntities[i]) ;

    for (std::multimap<int, TwoInt>::iterator it =
           GroupEntity_P->ExtendedListForSearch.lower_bound(Num_Entity);
         it != GroupEntity_P->ExtendedListForSearch.upper_bound(Num_Entity); ++it) {

      Key_P = &it->second;

      j = *StartingIndex ;
      while ((j < Element->NbrGroupsOfEntities) &&
	     (Element->NumGroupsOfEntities[j] != Key_P->Int2))  j++ ;

      if (!BasisFunction_P->SubFunction) {
	if (j == Element->NbrGroupsOfEntities) {
	  Element->NumSubFunction[1][j] = 0 ;
	  Element->NumSubFunction[0][j] = -1 ;
	  Element->NumGroupsOfEntities[j] = Key_P->Int2 ;
	  Element->NbrEntitiesInGroups[Element->NbrGroupsOfEntities++] = 0 ;
          if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
            Message::Error("Reached limit number of groups of entities");
            return;
          }
	}
	Element->NumEntitiesInGroups[j][Element->NbrEntitiesInGroups[j]++] =
	  (Key_P->Int1 > 0)?  (i+1) : -(i+1) ;
      }
      else { /* For SubFunctions (basis functions for a global function) */
	Nbr_SubFunction = List_Nbr(BasisFunction_P->SubFunction) ;

	if (j == Element->NbrGroupsOfEntities) {
	  for (i_SF = 0 ; i_SF < Nbr_SubFunction ; i_SF++) {
	    Element->NumSubFunction[1][j+i_SF] = i_SF ;
	    Element->NumSubFunction[0][j+i_SF] =
	      *((int *)List_Pointer(BasisFunction_P->SubFunction, i_SF)) ;
	    if (BasisFunction_P->SubdFunction)
	      Element->NumSubFunction[2][j+i_SF] =
		*((int *)List_Pointer(BasisFunction_P->SubdFunction, i_SF)) ;
	    Element->NumGroupsOfEntities[j+i_SF] = Key_P->Int2 ;
	    Element->NbrEntitiesInGroups[Element->NbrGroupsOfEntities++] = 0 ;
            if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
              Message::Error("Reached limit number of groups of entities");
              return;
            }
          }
	}
	for (i_SF = 0 ; i_SF < Nbr_SubFunction ; i_SF++)
	  Element->NumEntitiesInGroups[j+i_SF][Element->NbrEntitiesInGroups[j+i_SF]++] =
	    (Key_P->Int1 > 0)?  (i+1) : -(i+1) ;
      }

    }

  }
}

/* ------------------------------------------------------------------------ */
/*  G e t _ G r o u p s O f E d g e s O n N o d e s O f E l e m e n t       */
/* ------------------------------------------------------------------------ */

void  Get_GroupsOfEdgesOnNodesOfElement(struct Element * Element,
					int * StartingIndex)
{
  /* external input/output :  GroupEntity_P     : In  */

  int  i, j, Num_Edge, * Num_Nodes, Num_Node ;

  if (Element->NumLastElementForGroupsOfEntities != Element->Num) {
    Element->NumLastElementForGroupsOfEntities = Element->Num ;
    Element->NbrGroupsOfEntities = 0 ;
  }

  *StartingIndex = Element->NbrGroupsOfEntities ;

  if (GroupEntity_P->ExtendedList == NULL) Generate_ExtendedGroup(GroupEntity_P) ;

  for (i = 0 ; i < Element->GeoElement->NbrEdges ; i++) {
    Num_Edge = abs(Element->GeoElement->NumEdges[i]) ;
    if (List_Search(GroupEntity_P->ExtendedList, &Num_Edge, fcmp_int )) {

      Num_Nodes = Geo_GetNodesOfEdgeInElement(Element->GeoElement, i) ;

      Num_Node = Element->GeoElement->NumNodes[abs(Num_Nodes[0])-1] ;
      j = *StartingIndex ;
      while ((j < Element->NbrGroupsOfEntities) &&
	     (Element->NumGroupsOfEntities[j] != Num_Node))  j++ ;
      if (j == Element->NbrGroupsOfEntities) {
	Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = Num_Node ;
        if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
          Message::Error("Reached limit number of groups of entities");
          return;
        }
        Element->NbrEntitiesInGroups[j] = 0 ;
      }
      Element->NumEntitiesInGroups[j] [Element->NbrEntitiesInGroups[j]++] =
	(Element->GeoElement->NumEdges[i] > 0)? -(i+1) : (i+1) ;
      /*-        edge
	node 1 o--->---o node 2   =>   (Phi2 - Phi1) s12 ...
	-> minus sign associated with node 1 for positive edge from node 1 to node 2
      */

      Num_Node = Element->GeoElement->NumNodes[abs(Num_Nodes[1])-1] ;
      j = *StartingIndex ;
      while ((j < Element->NbrGroupsOfEntities) &&
	     (Element->NumGroupsOfEntities[j] != Num_Node))  j++ ;
      if (j == Element->NbrGroupsOfEntities) {
	Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = Num_Node ;
        if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
          Message::Error("Reached limit number of groups of entities");
          return;
        }
        Element->NbrEntitiesInGroups[j] = 0 ;
      }
      Element->NumEntitiesInGroups[j] [Element->NbrEntitiesInGroups[j]++] =
	(Element->GeoElement->NumEdges[i] > 0)? (i+1) : -(i+1) ;
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  G e t _ R e g i o n F o r E l e m e n t                                 */
/* ------------------------------------------------------------------------ */

void  Get_RegionForElement(struct Element * Element, int * StartingIndex,
			   struct BasisFunction * BasisFunction_P)
{
  int Nbr_SubFunction, i_SF ;

  if (Element->NumLastElementForGroupsOfEntities != Element->Num) {
    Element->NumLastElementForGroupsOfEntities = Element->Num ;
    Element->NbrGroupsOfEntities = 0 ;
  }

  *StartingIndex = Element->NbrGroupsOfEntities ;

  if (!BasisFunction_P->SubFunction) {
    Element->NumSubFunction[1][Element->NbrGroupsOfEntities] = 0 ;
    Element->NumSubFunction[0][Element->NbrGroupsOfEntities] = -1 ;
    Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = Element->Region ;
    if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
      Message::Error("Reached limit number of groups of entities");
      return;
    }
  }
  else { /* For SubFunctions (basis functions for a global function) */
    Nbr_SubFunction = List_Nbr(BasisFunction_P->SubFunction) ;

    for (i_SF = 0 ; i_SF < Nbr_SubFunction ; i_SF++) {
      Element->NumSubFunction[1][Element->NbrGroupsOfEntities] = i_SF ; /* Index SF */
      Element->NumSubFunction[0][Element->NbrGroupsOfEntities] =
	*((int *)List_Pointer(BasisFunction_P->SubFunction, i_SF)) ; /* Index Expression */
      if (BasisFunction_P->SubdFunction)
	Element->NumSubFunction[2][Element->NbrGroupsOfEntities] =
	  *((int *)List_Pointer(BasisFunction_P->SubdFunction, i_SF)) ; /* Index Expression */
      Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = Element->Region ;
      if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
        Message::Error("Reached limit number of groups of entities");
        return;
      }
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  G e t _ G r o u p O f R e g i o n s F o r E l e m e n t                 */
/* ------------------------------------------------------------------------ */

void  Get_GroupOfRegionsForElement(struct Element * Element, int * StartingIndex,
                                   struct BasisFunction * BasisFunction_P)
{
  int Nbr_SubFunction, i_SF ;

  if (Element->NumLastElementForGroupsOfEntities != Element->Num) {
    Element->NumLastElementForGroupsOfEntities = Element->Num ;
    Element->NbrGroupsOfEntities = 0 ;
  }

  *StartingIndex = Element->NbrGroupsOfEntities ;

  if (!BasisFunction_P->SubFunction) {
    Element->NumSubFunction[1][Element->NbrGroupsOfEntities] = 0 ;
    Element->NumSubFunction[0][Element->NbrGroupsOfEntities] = -1 ;
    Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = GroupEntity_P->Num ;
    if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
      Message::Error("Reached limit number of groups of entities");
      return;
    }
  }
  else { /* For SubFunctions (basis functions for a global function) */
    Nbr_SubFunction = List_Nbr(BasisFunction_P->SubFunction) ;

    for (i_SF = 0 ; i_SF < Nbr_SubFunction ; i_SF++) {
      Element->NumSubFunction[1][Element->NbrGroupsOfEntities] = i_SF ; /* Index SF */
      Element->NumSubFunction[0][Element->NbrGroupsOfEntities] =
        *((int *)List_Pointer(BasisFunction_P->SubFunction, i_SF)) ; /* Index Expression */
      if (BasisFunction_P->SubdFunction)
        Element->NumSubFunction[2][Element->NbrGroupsOfEntities] =
          *((int *)List_Pointer(BasisFunction_P->SubdFunction, i_SF)) ; /* Index Expression */
      Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = GroupEntity_P->Num ;
      if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
        Message::Error("Reached limit number of groups of entities");
        return;
      }
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  G e t _ G l o b a l F o r E l e m e n t                                 */
/* ------------------------------------------------------------------------ */

void  Get_GlobalForElement(struct Element * Element, int * StartingIndex,
			   struct BasisFunction * BasisFunction_P)
{
  int Nbr_Global, i, * Num_Global ;

  if (Element->NumLastElementForGroupsOfEntities != Element->Num) {
    Element->NumLastElementForGroupsOfEntities = Element->Num ;
    Element->NbrGroupsOfEntities = 0 ;
  }

  *StartingIndex = Element->NbrGroupsOfEntities ;

  Nbr_Global = List_Nbr(GroupEntity_P->InitialList) ;
  Num_Global = (Nbr_Global)? (int*)List_Pointer(GroupEntity_P->InitialList, 0) : NULL ;

  if (BasisFunction_P->GlobalBasisFunction) {
    for (i = 0 ; i < Nbr_Global ; i++) {
      Element->GlobalBasisFunction[Element->NbrGroupsOfEntities  ] =
        (struct GlobalBasisFunction *)
        List_Pointer(BasisFunction_P->GlobalBasisFunction, i) ;
      /* Attention: correspondance i-i si liste triee ! fait dans yacc */
      Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = Num_Global[i] ;
      if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
        Message::Error("Reached limit number of groups of entities");
        return;
      }
    }

    if (TreatmentStatus == STATUS_PRE)
      Get_PreResolutionForGlobalBasisFunction(Nbr_Global, *StartingIndex, Element) ;
  }
  else {
    for (i = 0 ; i < Nbr_Global ; i++) {
      Element->NumGroupsOfEntities[Element->NbrGroupsOfEntities++] = Num_Global[i] ;
      if(Element->NbrGroupsOfEntities >= NBR_MAX_GROUPS_IN_ELEMENT - 1){
        Message::Error("Reached limit number of groups of entities");
        return;
      }
    }
  }

}

/* ------------------------------------------------------------------------ */
/*  G e t _ C o d e s O f E l e m e n t                                     */
/* ------------------------------------------------------------------------ */

void  Get_CodesOfElement(struct FunctionSpace    * FunctionSpace_P,
			 struct QuantityStorage  * QuantityStorage_P,
			 int Nbr_Entity, int Num_Entity[],
			 int StartingIndex,
			 int i_BFunction, int TypeConstraint, int * Num_SubFunction)
{
/* external input/output :
     GroupSupport_P    : In
     GroupEntity_P     : In  */

  int         i_Entity, CodeExist = 0, Code_BasisFunction ;
  struct Dof  * Dof_P = NULL;

  /*  1.  F o r   e a c h   e n t i t y   t o   w h i c h   a   b a s i s
          f u n c t i o n   c o u l d   b e   a s s o c i a t e d :
          (Node, Edge, Facet, Volume, GroupOfNodes, Region, ...)  */

  for (i_Entity = StartingIndex ; i_Entity < Nbr_Entity ; i_Entity++) {

    Code_BasisFunction =
      BasisFunction_P->Num + (Num_SubFunction? Num_SubFunction[i_Entity] : 0) ;

    switch (TreatmentStatus) {
    case STATUS_CAL :
    case STATUS_POS :
    case STATUS_CST :
      if(!FunctionSpace_P->DofData){
	Message::Error("Empty DofData in FunctionSpace '%s' (no unknowns?)",
                       FunctionSpace_P->Name);
        return;
      }
      CodeExist =
	((Dof_P =
	  Dof_GetDofStruct(FunctionSpace_P->DofData,
			   Code_BasisFunction, abs(Num_Entity[i_Entity]), 0))
	 != NULL) ;

      if (Flag_SubSpace && CodeExist && TreatmentStatus != STATUS_POS)
	CodeExist =
	  Check_IsEntityInExtendedGroup(GroupEntity_P, abs(Num_Entity[i_Entity]), 0) ;
      /* ... parce que le code peut ne pas exister quand sous-espace ! */
      break ;

    case STATUS_PRE :
      CodeExist =
	Check_IsEntityInExtendedGroup(GroupEntity_P, abs(Num_Entity[i_Entity]), 0) ;
      break ;

    default :
      Message::Error("Unknown TreatmentStatus (%d)", TreatmentStatus);
      return;
    }

    /*  2.  O n e   a s s o c i a t e s   a   b a s i s   f u n c t i o n :  */

    if (CodeExist) {

      QuantityStorage_P->BasisFunction[Nbr_ElementaryBF].Dof
	= Dof_P ;
      QuantityStorage_P->BasisFunction[Nbr_ElementaryBF].NumEntityInElement
	= i_Entity ;
      QuantityStorage_P->BasisFunction[Nbr_ElementaryBF].CodeBasisFunction
	= Code_BasisFunction ;
      QuantityStorage_P->BasisFunction[Nbr_ElementaryBF].CodeEntity
	= abs(Num_Entity[i_Entity]) ;
      QuantityStorage_P->BasisFunction[Nbr_ElementaryBF].BasisFunction
	= BasisFunction_P ;

      if (TreatmentStatus == STATUS_PRE ||
	  TreatmentStatus == STATUS_CST)  /* Associated Contraints? */
	Treatment_ConstraintForElement(FunctionSpace_P, QuantityStorage_P,
				       Num_Entity, i_Entity,
				       i_BFunction, TypeConstraint) ;

      Nbr_ElementaryBF++ ;

    }  /* if CodeExist ... */

  }  /* for i_Entity ... */
}

/* ------------------------------------------------------------------------ */
/*  G e t _ D o f O f R e g i o n                                           */
/* ------------------------------------------------------------------------ */

void  Get_DofOfRegion(int  Num_Region,
		      struct GlobalQuantity   * GlobalQuantity_P,
		      struct FunctionSpace    * FunctionSpace_P,
		      struct QuantityStorage  * QuantityStorage_P)
{
  int  CodeExist = 0, Num_BasisFunction, Num_AssociateBasisFunction ;
  int  Num_Entity = -1;
  struct Dof  * Dof_P = NULL;

  Nbr_ElementaryBF = 0 ;

  BasisFunction_P = (struct BasisFunction*)
    List_Pointer(FunctionSpace_P->BasisFunction,
		 GlobalQuantity_P->ReferenceIndex) ;
  GroupEntity_P =  (struct Group*)
    List_Pointer(Problem_S.Group, BasisFunction_P->EntityIndex) ;

  if (GroupEntity_P->Type == REGIONLIST  &&
      List_Search(GroupEntity_P->InitialList, &Num_Region, fcmp_int)) {

    if (GlobalQuantity_P->Type == ALIASOF) {
      Num_BasisFunction = BasisFunction_P->Num ;
      Num_AssociateBasisFunction = 0 ;
    }
    else {
      Num_BasisFunction = GlobalQuantity_P->Num ;
      Num_AssociateBasisFunction = BasisFunction_P->Num ;
    }

    if (GroupEntity_P->FunctionType == GROUPOFREGIONSOF)
      Num_Entity = GroupEntity_P->Num;
    else
      Num_Entity = Num_Region;

    switch (TreatmentStatus) {
    case STATUS_CAL :
    case STATUS_POS :
    case STATUS_CST :
      if(!FunctionSpace_P->DofData){
	Message::Error("Empty DofData in FunctionSpace '%s' (no unknowns?)",
		   FunctionSpace_P->Name);
        return;
      }

      CodeExist =
	((Dof_P = Dof_GetDofStruct(FunctionSpace_P->DofData,
				   Num_BasisFunction, Num_Entity, 0)) != NULL) ;
      break ;
    case STATUS_PRE :
      CodeExist = 1 ;
      break ;
    default : break ;
    }

    if (CodeExist) {
      QuantityStorage_P->BasisFunction[0].Dof = Dof_P ;

      QuantityStorage_P->BasisFunction[0].CodeBasisFunction = Num_BasisFunction ;
      QuantityStorage_P->BasisFunction[0].CodeEntity        = Num_Entity ;

      QuantityStorage_P->BasisFunction[0].CodeAssociateBasisFunction =
	Num_AssociateBasisFunction ;

      if (TreatmentStatus == STATUS_PRE ||
	  TreatmentStatus == STATUS_CST)  /* Contrainte associee ? */
	Treatment_ConstraintForRegion(GlobalQuantity_P,
				      FunctionSpace_P, QuantityStorage_P) ;
      Nbr_ElementaryBF = 1 ;

    }  /* if CodeExist ... */

  }  /* if REGIONLIST ... */

  QuantityStorage_P->NbrElementaryBasisFunction = Nbr_ElementaryBF ;
}

/* ------------------------------------------------------------------------ */
/*  G e t _ P r e R e s o l u t i o n F o r GlobalBasisFunction             */
/* ------------------------------------------------------------------------ */

void  Get_PreResolutionForGlobalBasisFunction(int Nbr_Global, int StartingIndex,
					      struct Element * Element)
{
  int i ;
  struct PreResolutionInfo  PreResolutionInfo_S ;

  for (i = 0 ; i < Nbr_Global ; i++)
    if(List_ISearchSeq(PreResolutionIndex_L,
		       &(Element->GlobalBasisFunction[StartingIndex + i]->
			 ResolutionIndex), fcmp_int) < 0) {
      PreResolutionInfo_S.Index =
	Element->GlobalBasisFunction[StartingIndex + i]->ResolutionIndex ;
      PreResolutionInfo_S.Type  = PR_GLOBALBASISFUNCTION ;
      List_Add(PreResolutionIndex_L, &PreResolutionInfo_S) ;
      Message::Info("  Adding Resolution '%s' for Pre-Resolution (Global BF)",
		((struct Resolution*)List_Pointer(Problem_S.Resolution,
						  PreResolutionInfo_S.Index))->Name) ;
    }
}
