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


#include "genDElementManager.h"
#include "genDElementPolicies.h"
#include <assert.h>


template<class E> std::ostream & operator<<(std::ostream &os, const KeyManagerBase<E> &manager)
{
  os << "Number of Keys : " << manager.size() << std::endl;
  typename KeyManagerBase<E>::KeyContainer::const_iterator it;
  for (it=manager.begin(); it!=manager.end(); ++it)
  {
    os.width(2);
    os << *(it->second);
  }
  os << "\n";
  return os;
}


template<class E> void KeyManager<E>::getKey(E* e, Key &key)
{
  ElementPolicies<E>::getKey(e,key);
}

template<class E> DElementBase<E>* KeyManager<E>::findDElement(E* e, Key &key)
{
  KeyManagerBase<E>* keyManager = KeyManagerBase<E>::getInstance();
  typename KeyManagerBase<E>::KeyContainer::const_iterator it;
  it = keyManager->find(key);
  if (it==keyManager->end())
    return 0;
  if (it->second->get())
    assert(it->second->get()==e);
  else
    it->second->set(e);
  return it->second;
}

template<class E> DElementBase<E>* KeyManager<E>::findDElement(E* e)
{
  Key key;
  ElementPolicies<E>::getKey(e,key);
  return findDElement(e, key);
}

#ifndef __GXX_EXPERIMENTAL_CXX0X__
template<class E> template<class D1,class D2,class D3>
DElement<E,D1,D2,D3>* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{
  typedef typename DElementTraits<E,D1,D2,D3>::DElementType DElementType;
  DElementType* ce = new DElementType(e,key,s1,s2,s3); // automatic addition to manager
  return ce;
}
template<class E> template<class D1,class D2,class D3>
DElement<E,D1,D2,D3>* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{
  Key key;
  ElementPolicies<E>::getKey(e,key);
  return createDElement<D1,D2,D3>(e,key,s1,s2,s3);
}

template<class E> template< template<class DE1> class D1,
                            template<class DE2> class D2,
                            template<class DE3> class D3 >
DElement<E,D1<E>,D2<E>,D3<E> >* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{
  typedef DElement<E,D1<E>,D2<E>,D3<E> > DElementType;
  DElementType* ce = new DElementType(e,key,s1,s2,s3); // automatic addition to manager
  return ce;
}
template<class E> template< template<class DE1> class D1,
                            template<class DE2> class D2,
                            template<class DE3> class D3 >
DElement<E,D1<E>,D2<E>,D3<E> >* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{
  Key key;
  ElementPolicies<E>::getKey(e,key);
  return createDElement<D1,D2,D3>(e,key,s1,s2,s3);
}

template<class E>
DElementBase<E>* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<nothing,nothing,nothing>(e,key,s1,s2,s3);}
template<class E>
DElementBase<E>* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<nothing,nothing,nothing>(e,s1,s2,s3);}
template<class E> template<class D1>
DElement<E,D1,nothing,nothing>* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1,nothing,nothing>(e,key,s1,s2,s3);}
template<class E> template<class D1>
DElement<E,D1,nothing,nothing>* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1,nothing,nothing>(e,s1,s2,s3);}
template<class E> template<class D1,class D2>
DElement<E,D1,D2,nothing>* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1,D2,nothing>(e,key,s1,s2,s3);}
template<class E> template<class D1,class D2>
DElement<E,D1,D2,nothing>* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1,D2,nothing>(e,s1,s2,s3);}
template<class E> template< template<class DE1> class D1>
DElement<E,D1<E>,nothing,nothing>* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1<E>,nothing,nothing>(e,key,s1,s2,s3);}
template<class E> template< template<class DE1> class D1>
DElement<E,D1<E>,nothing,nothing>* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1<E>,nothing,nothing>(e,s1,s2,s3);}
template<class E> template< template<class DE1> class D1,
                            template<class DE2> class D2>
DElement<E,D1<E>,D2<E>,nothing>* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1<E>,D2<E>,nothing>(e,key,s1,s2,s3);}
template<class E> template< template<class DE1> class D1,
                            template<class DE2> class D2>
DElement<E,D1<E>,D2<E>,nothing>* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{return KeyManager<E>::createDElement<D1<E>,D2<E>,nothing>(e,s1,s2,s3);}



#else // __GXX_EXPERIMENTAL_CXX0X__

template<class E> template<class D1,class D2,class D3>
typename DElementTraits<E,D1,D2,D3>::DElementType* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{
  typedef typename DElementTraits<E,D1,D2,D3>::DElementType DElementType;
  DElementType* ce = new DElementType(e,key,s1,s2,s3); // automatic addition to manager
  return ce;
}
template<class E> template<class D1,class D2,class D3>
typename DElementTraits<E,D1,D2,D3>::DElementType* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{
  Key key;
  ElementPolicies<E>::getKey(e,key);
  return createDElement<D1,D2,D3>(e,key,s1,s2,s3);
}

template<class E> template< template<class DE1> class D1,
                            template<class DE2> class D2,
                            template<class DE3> class D3 >
typename DElementTraitsTemplate<E,D1,D2,D3>::DElementType* KeyManager<E>::createDElement(E* e, Key &key, const char* s1, const char* s2, const char* s3)
{
  typedef typename DElementTraitsTemplate<E,D1,D2,D3>::DElementType DElementType;
  DElementType* ce = new DElementType(e,key,s1,s2,s3); // automatic addition to manager
  return ce;
}
template<class E> template< template<class DE1> class D1,
                            template<class DE2> class D2,
                            template<class DE3> class D3 >
typename DElementTraitsTemplate<E,D1,D2,D3>::DElementType* KeyManager<E>::createDElement(E* e, const char* s1, const char* s2, const char* s3)
{
  Key key;
  ElementPolicies<E>::getKey(e,key);
  return createDElement<D1,D2,D3>(e,key,s1,s2,s3);
}
#endif // __GXX_EXPERIMENTAL_CXX0X__


template<class E> void KeyManager<E>::clear()
{
  KeyManagerBase<E>* keyManager = KeyManagerBase<E>::getInstance();
  keyManager->clear();
}

template<class E> void KeyManager<E>::printf()
{
  KeyManagerBase<E>* keyManager = KeyManagerBase<E>::getInstance();
  std:: cout << *keyManager;
}
