#include <tjutils/tjlist.h>
#include <tjutils/tjlog.h>

#ifdef HAVE_TYPEINFO
#include <typeinfo>
#endif


template<class I>
  ListItem<I>::~ListItem() {
    Log<ListComponent> odinlog("ListItem","~ListItem");
#ifdef HAVE_TYPEINFO
    ODINLOG(odinlog,normalDebug) << "deleting object of type >" << typeid(I).name() << "<" << STD_endl;
#endif

    for(STD_list<ListBase*>::iterator it=objhandlers.begin(); it!=objhandlers.end(); ++it) {
      (*it)->objlist_remove(this);
    }
  }

template<class I>
  const ListItemBase& ListItem<I>::append_objhandler(ListBase& objhandler) const {
    Log<ListComponent> odinlog("ListItem","append_objhandler");
    objhandlers.push_back(&objhandler);
    return *this;
  }

template<class I>
  const ListItemBase& ListItem<I>::remove_objhandler(ListBase& objhandler) const {
    Log<ListComponent> odinlog("ListItem","remove_objhandler");
    objhandlers.remove(&objhandler);
    return *this;
  }

///////////////////////////////////////////////////////////////////////////////////////////


template<class I,class P,class R>
  List<I,P,R>::List() {
    Log<ListComponent> odinlog("List","List()");
#ifdef HAVE_TYPEINFO
    ODINLOG(odinlog,normalDebug) << "constructing list of >" << typeid(I).name() << "<" << STD_endl;
#endif
  }

template<class I,class P,class R>
  List<I,P,R>::~List() {
    Log<ListComponent> odinlog("List","~List()");
#ifdef HAVE_TYPEINFO
    ODINLOG(odinlog,normalDebug) << "destructing list of >" << typeid(I).name() << "<" << STD_endl;
#endif
    clear();
  }

template<class I,class P,class R>
  List<I,P,R>& List<I,P,R>::operator = (const List<I,P,R>& l) {
    clear();
    for(typename STD_list<P>::const_iterator it=l.objlist.begin(); it!=l.objlist.end(); ++it) {
      append(**it);
    }
    return *this;
  }

template<class I,class P,class R>
  List<I,P,R>& List<I,P,R>::clear() {
    Log<ListComponent> odinlog("List","clear");
#ifdef HAVE_TYPEINFO
    ODINLOG(odinlog,normalDebug) << "Clearing list of type >" << typeid(I).name() << "<" << STD_endl;
#endif
    for(typename STD_list<P>::iterator it=objlist.begin(); it!=objlist.end(); ++it) {
      ODINLOG(odinlog,normalDebug) << "Unlinking " << (*it) << STD_endl;

      unlink_item(*it);

      ODINLOG(odinlog,normalDebug) << "Unlinking done" << STD_endl;
    }
    objlist.erase(objlist.begin(),objlist.end());
    return *this;
  }

template<class I,class P,class R>
  List<I,P,R>& List<I,P,R>::append(R item) {
    Log<ListComponent> odinlog("List","append");
#ifdef HAVE_TYPEINFO
    ODINLOG(odinlog,normalDebug) << "appending object of type >" << typeid(I).name() << "<" << STD_endl;
#endif
    link_item(&item);
    objlist.push_back(&item);
    return *this;
  }

template<class I,class P,class R>
  List<I,P,R>& List<I,P,R>::remove(R item) {
    Log<ListComponent> odinlog("List","remove");
#ifdef HAVE_TYPEINFO
    ODINLOG(odinlog,normalDebug) << "removing object of type >" << typeid(I).name() << "<" << STD_endl;
#endif
    unlink_item(&item);
    objlist.remove(&item);
    return *this;
  }

template<class I,class P,class R>
  void List<I,P,R>::objlist_remove(ListItemBase* item) {
    Log<ListComponent> odinlog("List","objlist_remove");
#ifdef HAVE_TYPEINFO
    ODINLOG(odinlog,normalDebug) << "deleting object of type >" << typeid(I).name() << "<" << STD_endl;
#endif
    P itemItype=static_cast<P>(item);
    if(itemItype) {
      objlist.remove(itemItype);
    } else {
      ODINLOG(odinlog,errorLog) << "static_cast failed" << STD_endl;
    }
  }


template<class I,class P,class R>
  void List<I,P,R>::link_item(P ptr) {
    Log<ListComponent> odinlog("List","link_item");
    const ListItem<I>* item=static_cast<const ListItem<I>*>(ptr);
    if(item) {
      item->append_objhandler(*this);
    } else {
      ODINLOG(odinlog,errorLog) << "static_cast failed" << STD_endl;
    }
  }

template<class I,class P,class R>
  void List<I,P,R>::unlink_item(P ptr) {
    Log<ListComponent> odinlog("List","unlink_item");
    const ListItem<I>* item=static_cast<const ListItem<I>*>(ptr);
    if(item) {
      item->remove_objhandler(*this);
    } else {
      ODINLOG(odinlog,errorLog) << "static_cast failed" << STD_endl;
    }
  }



