// genDElement - An abstract data element library
// Copyright (C) 2013-2026 Eric Bechet, Frederic Duboeuf
//
// See the LICENSE file for license information.
// Please report all bugs and problems to <bechet@cadxfem.org> or <duboeuf@outlook.com>.
//
// Initial design: Frederic Duboeuf (rev.1511)


#ifndef _GEN_DELEMENT_POLICIES_H_
#define _GEN_DELEMENT_POLICIES_H_

#include <iostream>

#include "genDElementKey.h"
#include "genDElementTraits.h"

#include "MElement.h"
#include "MVertex.h"
#include "MEdge.h"
#include "MFace.h"

// Policies
template<class E> struct ElementPolicies
{
  static int getDim(const E* e) {std::cout << "ElementPolicies not available for this class" << std::endl; return -1;}
  static int getNum(const E* e) {std::cout << "ElementPolicies not available for this class" << std::endl; return -1;}
  static int getNumVertices(E* e) {std::cout << "ElementPolicies not available for this class" << std::endl; return -1;}
  static int getNumEdges(E* e) {std::cout << "ElementPolicies not available for this class" << std::endl; return -1;}
  static int getNumFaces(E* e) {std::cout << "ElementPolicies not available for this class" << std::endl; return -1;}
  static typename ElementTraits<E>::VertexType* getVertex(E* e, int i) {std::cout << "ElementPolicies not available for this class" << std::endl; return 0;}
  static typename ElementTraits<E>::EdgeType* getEdge(E* e, int i) {std::cout << "ElementPolicies not available for this class" << std::endl; return 0;}
  static typename ElementTraits<E>::FaceType* getFace(E* e, int i) {std::cout << "ElementPolicies not available for this class" << std::endl; return 0;}
  static void getKey(const E* e, Key &key) {std::cout << "ElementPolicies not available for this class" << std::endl;}
};

template<> struct ElementPolicies<MElement>
{
  static int getDim(const MElement* e) {return e->getDim();}
  static int getNum(const MElement* e) {return e->getNum();}
  static int getNumVertices(MElement* e) {return e->getNumVertices();}
  static int getNumEdges(MElement* e) {return e->getNumEdges();}
  static int getNumFaces(MElement* e) {return e->getNumFaces();}
  static ElementTraits<MElement>::VertexType* getVertex(MElement* e, int i) {return e->getVertex(i);}
  static ElementTraits<MElement>::EdgeType* getEdge(MElement* e, int i) {return new ElementTraits<MElement>::EdgeType(e->getEdge(i));}
  static ElementTraits<MElement>::FaceType* getFace(MElement* e, int i) {return new ElementTraits<MElement>::FaceType(e->getFace(i));}
  static void getKey(const MElement* e, Key &key)
  {
    int nV = e->getNumVertices();
    std::set<int> nums;
    for(int i=0; i<nV; ++i)
      nums.insert(e->getVertex(i)->getNum());
    key.set(std::vector<int>(nums.begin(),nums.end()));
  }
};

template<> struct ElementPolicies<MVertex>
{
  static int getDim(const MVertex* v) {return 0;}
  static int getNum(const MVertex* v) {return 0;}
  static int getNumVertices(MVertex* v) {return 1;}
  static int getNumEdges(MVertex* v) {return 0;}
  static int getNumFaces(MVertex* v) {return 0;}
  static ElementTraits<MElement>::VertexType* getVertex(MVertex* v, int i) {return v;}
  static ElementTraits<MElement>::EdgeType* getEdge(MVertex* v, int i) {return 0;}
  static ElementTraits<MElement>::FaceType* getFace(MVertex* v, int i) {return 0;}
  static void getKey(const MVertex* v, Key &key)
  {
    key.set(std::vector<int>(1,v->getNum()));
  }
};

template<> struct ElementPolicies<MEdge>
{
  static int getDim(const MEdge* e) {return 1;}
  static int getNum(const MEdge* e) {return 0;}
  static int getNumVertices(MEdge* e) {return e->getNumVertices();}
  static int getNumEdges(MEdge* e) {return 1;}
  static int getNumFaces(MEdge* e) {return 0;}
  static ElementTraits<MElement>::VertexType* getVertex(MEdge* e, int i) {return e->getVertex(i);}
  static ElementTraits<MElement>::EdgeType* getEdge(MEdge* e, int i) {return e;}
  static ElementTraits<MElement>::FaceType* getFace(MEdge* e, int i) {return 0;}
  static void getKey(const MEdge* e, Key &key)
  {
    int nV = e->getNumVertices();
    std::vector<int> nums;
    nums.reserve(nV);
    for(int i=0; i<nV; ++i)
      nums.push_back(e->getSortedVertex(i)->getNum());
    key.set(nums);
  }
};

template<> struct ElementPolicies<MFace>
{
  static int getDim(const MFace* f) {return 2;}
  static int getNum(const MFace* f) {return 0;}
  static int getNumVertices(MFace* f) {return f->getNumVertices();}
  static int getNumEdges(MFace* f) {return f->getNumVertices();}
  static int getNumFaces(MFace* f) {return 1;}
  static ElementTraits<MElement>::VertexType* getVertex(MFace* f, int i) {return f->getVertex(i);}
  static ElementTraits<MElement>::EdgeType* getEdge(MFace* f, int i) {return new ElementTraits<MElement>::EdgeType(f->getEdge(i));}
  static ElementTraits<MElement>::FaceType* getFace(MFace* f, int i) {return f;}
  static void getKey(const MFace* f, Key &key)
  {
    int nV = f->getNumVertices();
    std::vector<int> nums;
    nums.reserve(nV);
    for(int i=0; i<nV; ++i)
      nums.push_back(f->getSortedVertex(i)->getNum());
    key.set(nums);
  }
};

#endif // _GEN_DELEMENT_POLICIES_H_
