// Bimaterial_xfem - A solver for bimaterial problems using X-FEM
// Copyright (C) 2012-2018 Frederic Duboeuf
//
// See the LICENSE file for license information.
// Please report all bugs and problems to <duboeuf@outlook.com>.

#ifndef _BIMATERIAL_XFEM_DOMAIN_H_
#define _BIMATERIAL_XFEM_DOMAIN_H_

#include <string>
#include <vector>

#include "genSupports.h"
#include "genTerm.h"
#include "genTensors.h"
#include "genDataIO.h"
#include "genMatrix.h"
#include "genFilters.h"
#include "savedGenTerm.h"

#include "genEnrichFunctions.h"

class BimaterialDomain : public genSupport
{
public :
  int tagDomainInt;
  genGroupOfElements* subDomainInt; // SubElements contained in DomainInt, located at the border of the interface
  int tagDomainExt;
  genGroupOfElements* subDomainExt; // SubElements contained in DomainExt, located at the border of the interface

  std::set<long int>* enrichedEntities;
  std::set<int> enrichedComps; // enriched components - unused

  diffTerm<genTensor0<double>,0>::ConstHandle EF; // multiplying function enrichment to enrich the space function

public :
  BimaterialDomain(const genDomain &d, genTerm<genTensor0<double>,0>::ConstHandle distanceFunction) : enrichedEntities(NULL),subDomainExt(NULL),subDomainInt(NULL)
  {
    dim = d.dim;
    tag = d.tag;
    g = new genGroupOfElements(dim, tag);

    tagDomainInt = d.Integers.find("DomainInt")->second;
    tagDomainExt = d.Integers.find("DomainExt")->second;
    assert(tagDomainInt!=tagDomainExt);

    genGroupOfElements* DomainInt = new genGroupOfElements(dim+1, tagDomainInt);
    genGroupOfElements* DomainExt = new genGroupOfElements(dim+1, tagDomainExt);

    // filter the elements whose the parent is also parent in g
    genFilterElementGroupVertex filterElt(g);
    subDomainInt = new genGroupOfElements(DomainInt, filterElt);
    subDomainExt = new genGroupOfElements(DomainExt, filterElt);
    assert(subDomainInt->size());
    assert(subDomainExt->size());

    for (int i=0; i<dim+1; ++i)
      enrichedComps.insert(i);

    EF = diffTerm<genTensor0<double>,0>::Handle(new GradDiscFunction<genTensor0<double> >(distanceFunction));
  }
  diffTerm<genTensor0<double>,0>::ConstHandle EnrichmentFunction();
  std::set<long int>* EnrichedEntities();
  BimaterialDomain() : genSupport() {}
  virtual ~BimaterialDomain() {}
};

inline diffTerm<genTensor0<double>,0>::ConstHandle BimaterialDomain::EnrichmentFunction()
{
  return diffTerm<genTensor0<double>,0>::ConstHandle(EF);
}

inline std::set<long int>* BimaterialDomain::EnrichedEntities()
{
  if (!enrichedEntities)
  {
    // select parent vertices without interface vertices
    std::set<MVertex*> interfaceVertices;
    std::set<MElement*>::iterator it;
    for (it=group()->begin(); it!=group()->end(); ++it)
    {
      MElement* e = *it;
      std::vector<MVertex*> v;
      e->getVertices(v);
      for (int j=0; j<v.size(); ++j)
        interfaceVertices.insert(v[j]);
    }

    enrichedEntities = new std::set<long int>();
    std::set<MVertex*>::iterator itv;
    for (itv=group()->vbegin(); itv!=group()->vend(); ++itv)
    {
      MVertex* v = *itv;
      std::set<MVertex*>::iterator itv2;
      itv2 = interfaceVertices.find(v);
      if (itv2==interfaceVertices.end())
        enrichedEntities->insert(v->getNum());
    }
  }
  return enrichedEntities;
}


#endif// _BIMATERIAL_XFEM_DOMAIN_H_
