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


#ifndef _GEN_DELEMENT_H_
#define _GEN_DELEMENT_H_

#include <iostream>

#include "genDataGroup.h"
#include "genDElementTraits.h"
#include "genDElementPolicies.h"
#include "genDataPolicies.h"
class Key;


template<class E> class DElementBase
{
protected :
  E* e;
  mutable genDataGroup* datas;
public :
  typedef E ElementType;

protected :
  virtual void addToManager(const Key &key);
public :
  DElementBase(E* e_, const char* s1="", const char* s2="", const char* s3="") : e(e_), datas(0)
  {
    Key key;
    getKey(key);
    addToManager(key);
  }
  DElementBase(E* e_, const Key &key, const char* s1="", const char* s2="", const char* s3="") : e(e_), datas(0)
  {
    addToManager(key);
  }
  DElementBase() : e(0), datas(0) {}
  virtual ~DElementBase() {clearDatas();}
  virtual E* get() const {return e;}
  virtual void set(E* e_) {e=e_;}
  virtual int getDim() const {return ElementPolicies<E>::getDim(e);}
  virtual int getNum() const {return ElementPolicies<E>::getNum(e);}
  virtual int getNumVertices() {return ElementPolicies<E>::getNumVertices(e);}
  virtual int getNumEdges() {return ElementPolicies<E>::getNumEdges(e);}
  virtual int getNumFaces() {return ElementPolicies<E>::getNumFaces(e);}
  virtual typename ElementTraits<E>::VertexType* getVertex(int i) {return ElementPolicies<E>::getVertex(e,i);}
  virtual typename ElementTraits<E>::EdgeType* getEdge(int i) {return ElementPolicies<E>::getEdge(e,i);}
  virtual typename ElementTraits<E>::FaceType* getFace(int i) {return ElementPolicies<E>::getFace(e,i);}
  virtual genDataGroup* getDatas() const {if (!datas) datas=new genDataGroup(); return datas;}
  virtual void clearDatas() {if (datas) {delete datas; datas=NULL;}}
  virtual void getKey(Key &key) const {if(e) ElementPolicies<E>::getKey(e,key);}
};

template<class E> std::ostream & operator<<(std::ostream &os, const DElementBase<E> &de);

template<class E,class D1=nothing,class D2=nothing,class D3=nothing> class DElement : public DElementBase<E>
{
public :
  typedef E ElementType;

protected :
  virtual void addToManager(const Key &key) {DElementBase<E>::addToManager(key);}
public :
  DElement(E* e_, const char* s1="", const char* s2="", const char* s3="") : DElementBase<E>()
  {
    set(e_);
    Key key;
    getKey(key);
    addToManager(key);
    DataPolicies<E,D1>::addData(getDatas(), s1, this);
    DataPolicies<E,D2>::addData(getDatas(), s2, this);
    DataPolicies<E,D3>::addData(getDatas(), s3, this);
  }
  DElement(E* e_, const Key &key, const char* s1="", const char* s2="", const char* s3="") : DElementBase<E>()
  {
    set(e_);
    addToManager(key);
    DataPolicies<E,D1>::addData(getDatas(), s1, this);
    DataPolicies<E,D2>::addData(getDatas(), s2, this);
    DataPolicies<E,D3>::addData(getDatas(), s3, this);
  }
  DElement() : DElementBase<E>() {}
  virtual ~DElement() {}
  virtual E* get() const {return DElementBase<E>::get();}
  virtual void set(E* e_) {DElementBase<E>::set(e_);}
  virtual int getDim() const {return DElementBase<E>::getDim();}
  virtual int getNum() const {return DElementBase<E>::getNum();}
  virtual int getNumVertices() {return DElementBase<E>::getNumVertices();}
  virtual int getNumEdges() {return DElementBase<E>::getNumEdges();}
  virtual int getNumFaces() {return DElementBase<E>::getNumFaces();}
  virtual typename ElementTraits<E>::VertexType* getVertex(int i) {return DElementBase<E>::getVertex(i);}
  virtual typename ElementTraits<E>::EdgeType* getEdge(int i) {return DElementBase<E>::getEdge(i);}
  virtual typename ElementTraits<E>::FaceType* getFace(int i) {return DElementBase<E>::getFace(i);}
  virtual genDataGroup* getDatas() const {return DElementBase<E>::getDatas();}
  virtual void clearDatas() {DElementBase<E>::clearDatas();}
  virtual void getKey(Key &key) const {DElementBase<E>::getKey(key);}
};

#include "genDElement.hpp"

#endif // _GEN_DELEMENT_H_
