// 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_ID_MANAGER_H_
#define _GEN_DELEMENT_ID_MANAGER_H_

#include <map>
#include <iostream>

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

template<class E> class DElementBase;
template<class E> class KeyManagerBase : public Singleton<KeyManagerBase<E> >
{
public :
  typedef std::map<Key,DElementBase<E>*> KeyContainer;
protected :
  KeyContainer DElements;

private :
  friend class Singleton<KeyManagerBase<E> >;
  KeyManagerBase() {}
  ~KeyManagerBase() {clear();}
public :
  void addDElement(const Key &key, DElementBase<E>* de) {DElements[key]=de;}
  int size() const {return DElements.size();}
  void clear()
  {
    DElementBase<E>* de;
    typename KeyContainer::iterator it;
    for (it=DElements.begin(); it!=DElements.end(); ++it)
    {
      de = it->second;
      delete de;
    }
    DElements.clear();
  }
  typename KeyContainer::const_iterator begin() const {return DElements.begin();}
  typename KeyContainer::const_iterator end() const {return DElements.end();}
  typename KeyContainer::const_iterator find(const Key &key) const {return DElements.find(key);}
  typename KeyContainer::iterator begin() {return DElements.begin();}
  typename KeyContainer::iterator end() {return DElements.end();}
  typename KeyContainer::iterator find(const Key &key) {return DElements.find(key);}
};

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




// interface
#ifndef __GXX_EXPERIMENTAL_CXX0X__
template<class E> struct KeyManager
{
  static void getKey(E* e, Key &key);

  static DElementBase<E>* findDElement(E* e, Key &key);
  static DElementBase<E>* findDElement(E* e);

  static DElementBase<E>* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  static DElementBase<E>* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");
  template<class D1>
  static DElement<E,D1,nothing,nothing>* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template<class D1>
  static DElement<E,D1,nothing,nothing>* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");
  template<class D1,class D2>
  static DElement<E,D1,D2,nothing>* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template<class D1,class D2>
  static DElement<E,D1,D2,nothing>* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");
  template<class D1,class D2,class D3>
  static DElement<E,D1,D2,D3>* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template<class D1,class D2,class D3>
  static DElement<E,D1,D2,D3>* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");
  template< template<class DE1> class D1>
  static DElement<E,D1<E>,nothing,nothing>* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template< template<class DE1> class D1>
  static DElement<E,D1<E>,nothing,nothing>* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");
  template< template<class DE1> class D1,
            template<class DE2> class D2>
  static DElement<E,D1<E>,D2<E>,nothing>* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template< template<class DE1> class D1,
            template<class DE2> class D2>
  static DElement<E,D1<E>,D2<E>,nothing>* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");
  template< template<class DE1> class D1,
            template<class DE2> class D2,
            template<class DE3> class D3>
  static DElement<E,D1<E>,D2<E>,D3<E> >* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template< template<class DE1> class D1,
            template<class DE2> class D2,
            template<class DE3> class D3>
  static DElement<E,D1<E>,D2<E>,D3<E> >* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");

  static void clear();

  static void printf();
};
#else // __GXX_EXPERIMENTAL_CXX0X__
template<class E> struct KeyManager
{
  static void getKey(E* e, Key &key);

  static DElementBase<E>* findDElement(E* e, Key &key);
  static DElementBase<E>* findDElement(E* e);

  template<class D1=nothing,class D2=nothing,class D3=nothing>
  static typename DElementTraits<E,D1,D2,D3>::DElementType* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template<class D1=nothing,class D2=nothing,class D3=nothing>
  static typename DElementTraits<E,D1,D2,D3>::DElementType* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");

  template< template<class DE1> class D1,
            template<class DE2> class D2=nothingTemplate,
            template<class DE3> class D3=nothingTemplate >
  static typename DElementTraitsTemplate<E,D1,D2,D3>::DElementType* createDElement(E* e, Key &key, const char* s1="", const char* s2="", const char* s3="");
  template< template<class DE1> class D1,
            template<class DE2> class D2=nothingTemplate,
            template<class DE3> class D3=nothingTemplate >
  static typename DElementTraitsTemplate<E,D1,D2,D3>::DElementType* createDElement(E* e, const char* s1="", const char* s2="", const char* s3="");

  static void clear();

  static void printf();
};
#endif // __GXX_EXPERIMENTAL_CXX0X__

#include "genDElementManager.hpp"

#endif // _GEN_DELEMENT_ID_MANAGER_H_