// GenFem - A high-level finite element library
// Copyright (C) 2010-2026 Eric Bechet
//
// See the LICENSE file for license information and contributions.
// Please report all bugs and problems to <bechet@cadxfem.org>.
//
// Initial design: Frederic Duboeuf (rev.1230)

#include "genGroupOfElements.h"
#include "genFilters.h"
#include "GModel.h"
#include "GEntity.h"
#include "MPoint.h" // use MPoint instead of MElement to access to the number

genGroupOfElements::genGroupOfElements(int dim, int physical)
{
  genFilterElementTrivial filter;
  addPhysical(dim, physical, filter);
}

genGroupOfElements::genGroupOfElements(int dim, std::vector<int> physicals)
{
  genFilterElementTrivial filter;
  addPhysicals(dim, physicals, filter);
}

genGroupOfElements::genGroupOfElements(GFace*gf)
{
  genFilterElementTrivial filter;
  addElementary(gf, filter);
}

genGroupOfElements::genGroupOfElements(GRegion*gr)
{
  genFilterElementTrivial filter;
  addElementary(gr, filter);
}

genGroupOfElements::genGroupOfElements(std::vector<MElement*> &elems, const genFilterElement &filter=genFilterElementTrivial())
{
  std::vector<MElement*>::iterator it;
  for (it = elems.begin(); it != elems.end(); ++it)
  {
    MElement* e = *it;
    if (filter(e)) insert(e);
  }
}

genGroupOfElements::genGroupOfElements(genGroupOfElements* g, const genFilterElement &filter)
{
  elementContainer::iterator it;
  for (it = g->begin(); it != g->end(); ++it)
  {
    MElement* e = *it;
    if (filter(e)) insert(e);
  }
}

genGroupOfElements::genGroupOfElements(elementContainer::const_iterator begin, elementContainer::const_iterator end, const genFilterElement &filter=genFilterElementTrivial())
{
  elementContainer::iterator it;
  for (it = begin; it != end; ++it)
  {
    MElement* e = *it;
    if (filter(e)) insert(e);
  }
}


void genGroupOfElements::addElementary(GEntity* ge, const genFilterElement &filter=genFilterElementTrivial())
{
  for (int i=0; i < ge->getNumMeshElements(); ++i)
  {
    MElement* e = ge->getMeshElement(i);
    if (filter(e)) insert(e);
  }
}

void genGroupOfElements::addPhysical(int dim, int physical, const genFilterElement &filter=genFilterElementTrivial())
{
  std::map<int, std::vector<GEntity*> > groups[4];
  GModel::current()->getPhysicalGroups(groups);

  std::map<int, std::vector<GEntity*> >::iterator ite = groups[dim].find(physical);
  if (ite==groups[dim].end())
  {
    printf("Physical group of dimension %d and physical %d is not already existing.\n", dim, physical);
    return;
  }

  std::vector<GEntity*> &ent = ite->second;
  for (int i = 0; i < ent.size(); ++i)
    addElementary(ent[i], filter);
}

void genGroupOfElements::addPhysicals(int dim, std::vector<int> physicals, const genFilterElement &filter=genFilterElementTrivial())
{
  for (int i=0; i < physicals.size(); ++i)
  {
    addPhysical(dim, physicals[i], filter);
  }
}

void genGroupOfElements::addGroup(genGroupOfElements &g, const genFilterElement &filter=genFilterElementTrivial())
{
  elementContainer::iterator it;
  for (it = g.begin(); it != g.end(); ++it)
  {
    MElement* e = *it;
    if (filter(e)) insert(e);
  }
}

void genGroupOfElements::insert (MElement* e)
{
  elements.insert(e);

  MElement* ep = e->getParent();
  if (ep)
  {
    parents.insert(ep);
    for (int i=0; i < ep->getNumVertices(); ++i)
      vertices.insert(ep->getVertex(i));
  }
  else
  {
    for (int i=0; i < e->getNumVertices(); ++i)
      vertices.insert(e->getVertex(i));
  }
}


genGroupOfElements::elementContainer::const_iterator genGroupOfElements::find(int num) const
{
  MPoint e(0,num);// use MPoint instead of MElement (abstract class) to access to the number
  return find(&e);
}
genGroupOfElements::elementContainer::const_iterator genGroupOfElements::pfind(int pnum) const
{
  MPoint p(0,pnum);// use MPoint instead of MElement (abstract class) to access to the number
  return pfind(&p);
}
genGroupOfElements::vertexContainer::const_iterator genGroupOfElements::vfind(int vnum) const
{
  MVertex v(0,0,0,0,vnum);
  return vfind(&v);
}
  
bool genGroupOfElements::contains (int num) const
{
  MPoint e(0,num);// use MPoint instead of MElement (abstract class) to access to the number
  return contains(&e);
}
bool genGroupOfElements::pcontains(int pnum) const
{
  MPoint p(0,pnum);// use MPoint instead of MElement (abstract class) to access to the number
  return pcontains(&p);
}
bool genGroupOfElements::vcontains(int vnum) const
{
  MVertex v(0,0,0,0,vnum);
  return vcontains(&v);
}
