// Copyright (c) 2023 Dominic Masters
// 
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

#pragma once
#include "assert/assert.hpp"

namespace Dawn {
  class StateOwner;

  template<typename...A>
  class StateEvent;

  template<typename...A>
  struct StateEventListener {
    uint32_t id;
    StateOwner *owner;
    std::function<void(A...)> listener;
    std::function<void(StateEventListener<A...>)> unsubWithParams;
    std::function<void()> unsub;
    StateEvent<A...> *event;
  };

  class IStateEvent {
    protected:
      /**
       * Received notification from a state owner to let this state event know
       * that it wishes to unsubscribe all the event listeners that it may have
       * attached to this event.
       * 
       * @param owner State owner that is being disposed.
       */
      virtual void _stateOwnerDestroyed(StateOwner *owner) = 0;

      friend class StateOwner;
  };

  template<typename...A>
  class StateEvent : public IStateEvent {
    protected:
      uint32_t stateEventId = 0;

      void _stateOwnerDestroyed(StateOwner *owner) override {
        auto it = this->_eventListeners.begin();
        while(it != this->_eventListeners.end()) {
          if(it->owner == owner) {
            it = this->_eventListeners.erase(it);
          } else {
            ++it;
          }
        }
      }

    public:
      std::vector<StateEventListener<A...>> _eventListeners;

      /**
       * Invokes the event and emits to all of the listeners.
       * 
       * @param args Arguments for this event to pass to the listeners.
       */
      void invoke(A... args) {
        auto it = this->_eventListeners.begin();
        while(it != this->_eventListeners.end()) {
          it->listener(args...);
          ++it;
        }
        // auto itListeners = this->_eventListeners.begin();
        // while(itListeners != this->_eventListeners.end()) {
        //   auto itLists = itListeners->second.begin();
        //   while(itLists != itListeners->second.end()) {
        //     (*itLists)(args...);
        //     ++itLists;
        //   }
        //   ++itListeners;
        // }
      }

      friend class StateOwner;
  };
}