/*********************************************************************************
** Copyright (c) 1992-2026 MAK Technologies, Inc.
** All rights reserved.
*********************************************************************************/

#pragma once

//! \file publisherList.h
//! \ingroup managedInterface
//! \brief Defines a template for maintaining a list of VR-Link Publisher objects

#include "managedInterface/delegate.h"

#include <map>

//! \brief Defines the DtPublisherList template.  The parameter is the VR-Link Publisher object class type
template <typename Publisher>
class DtPublisherList
{
public:
   //! \brief Defines a delegate that has a Publisher object pointer as a parameter and returns a void type
   typedef DtDelegate<void, Publisher*> DtPublisherListDelegate;

   //! \brief constructor
   DtPublisherList()
   {

   }

   //! \brief destructor
   ~DtPublisherList()
   {
      clear();
   }

   //! \brief Ticks all of the publishers
   void tick()
   {
      typename std::map<std::string, Publisher*>::iterator iter=myPublishers.begin();
      for(iter; iter!=myPublishers.end(); ++iter)
      {
         iter->second->tick();
      }
   }

   //! \brief add a publisher to the list
   void add(Publisher* pub)
   {
      myPublishers[pub->globalId().string()] = pub;
      typename std::list<DtPublisherListDelegate*>::iterator iter=myAddedDelegates.begin();
      for(iter; iter!=myAddedDelegates.end(); ++iter)
      {
         (*(*iter))(pub);
      }
   }
   //! \brief add a publisher to the list with a specific identifier
   void add(Publisher* pub, const std::string& id)
   {
      myPublishers[id] = pub;
      typename std::list<DtPublisherListDelegate*>::iterator iter = myAddedDelegates.begin();
      for (iter; iter != myAddedDelegates.end(); ++iter)
      {
         (*(*iter))(pub);
      }
   }

   //! \brief remove the publisher from the list
   void remove(Publisher* pub)
   {
      myPublishers.erase(pub->globalId().string());
      typename std::list<DtPublisherListDelegate*>::iterator iter=myRemovedDelegates.begin();
      for(iter; iter!=myRemovedDelegates.end(); ++iter)
      {
         DtPublisherListDelegate* del=(*iter);
         (*del)(pub);
      }
   }

   //! \brief remove the publisher from the list
   void remove(const std::string& id)
   {
      Publisher* pub = myPublishers[id];
      myPublishers.erase(id);
      typename std::list<DtPublisherListDelegate*>::iterator iter = myRemovedDelegates.begin();
      for (iter; iter != myRemovedDelegates.end(); ++iter)
      {
         DtPublisherListDelegate* del = (*iter);
         (*del)(pub);
      }
   }

   //! \brief find a particular object publisher in the list
   Publisher* find(std::string id)
   {
      Publisher* result = NULL;
      typename std::map<std::string, Publisher*>::iterator pubIter;
      pubIter = myPublishers.find(id);
      if (pubIter != myPublishers.end())
      {
         result = myPublishers[id];
      }
      return result;
   }

   //! \brief add a callback for when a publisher is added to the list
   void addPublisherAddedDelegate(DtPublisherListDelegate* del)
   {
      myAddedDelegates.push_back(del);
   }

   //! \brief remove a callback for when a publisher is added to the list
   void removePublisherAddedDelegate(DtPublisherListDelegate* del)
   {
      myAddedDelegates.remove(del);
   }

   //! \brief add a callback for when a publisher is removed from the list
   void addPublisherRemovedDelegate(DtPublisherListDelegate* del)
   {
      myRemovedDelegates.push_back(del);
   }

   //! \brief remove a callback for when a publisher is removed from the list
   void removePublisherRemovedDelegate(DtPublisherListDelegate* del)
   {
      myRemovedDelegates.remove(del);
   }

   //! \brief Get the beginning of the list for iteration
   typename std::map< std::string, Publisher* >::iterator begin()
   {
      return myPublishers.begin();
   }
   
   //! \brief Get the end of the list for iteration
   typename std::map< std::string, Publisher*>::iterator end()
   {
      return myPublishers.end();
   }

   //! \brief Clears the list and all delegates.  This will release the memory used by the delegates or object publishers
   void clear()
   {
      typename std::map<std::string, Publisher*>::iterator iter=myPublishers.begin();
      for(iter; iter!=myPublishers.end(); ++iter)
      {
         delete (iter->second);
      }
      myPublishers.clear();

      typename std::list<DtPublisherListDelegate*>::iterator iter2=myAddedDelegates.begin();
      for(iter2; iter2!=myAddedDelegates.end(); ++iter2)
      {
         delete (*iter2);
      }
      myAddedDelegates.clear();

      typename std::list<DtPublisherListDelegate*>::iterator iter3=myRemovedDelegates.begin();
      for(iter3; iter3!=myRemovedDelegates.end(); ++iter3)
      {
         delete (*iter3);
      }
      myRemovedDelegates.clear();
   }

protected:
   typename std::map< std::string, Publisher*> myPublishers;
   std::list<DtPublisherListDelegate*> myAddedDelegates;
   std::list<DtPublisherListDelegate*> myRemovedDelegates;
};
