/*
* Author:          Patrick-Christopher Mattulat
* Co-Author:       Claude Sonnet 4.6 (LLM)
* Company:         Lynar Studios
* E-Mail:          webmaster@lynarstudios.com
* Created:         2024-05-16
* Changed:         2026-06-23
*
* */

#ifndef LS_STD_EVENT_MANAGER_HPP
#define LS_STD_EVENT_MANAGER_HPP

#include "Event.hpp"
#include "EventListener.hpp"
#include "EventParameter.hpp"

#include <list>
#include <ls-std/core/Class.hpp>
#include <ls-std/event/type/EventTypes.hpp>
#include <ls-std/os/dynamic-goal.hpp>
#include <memory>
#include <unordered_map>

namespace ls::standard::event::type
{
  using event_listeners = ::std::list<::std::pair<::std::shared_ptr<ls::standard::event::EventListener>, ls::standard::event::type::event_action>>;
  using event_observability_inventory = ::std::unordered_map<::std::string, ls::standard::event::type::event_listeners>;
}

/*
 * @doc: class(name: 'EventManager', package: 'event')
 * @doc: event.EventManager.description('This class can invoke all events known by subscribed listeners.')
 * */

namespace ls::standard::event
{
  class LS_STD_DYNAMIC_GOAL EventManager : public ls::standard::core::Class
  {
    public:

      explicit EventManager();
      ~EventManager() noexcept override;

      [[nodiscard]] ls::standard::event::type::listener_id getNextProvisionId() const;
      [[nodiscard]] bool holdsListenerForEvent(ls::standard::event::type::listener_id _id, const ls::standard::event::Event &_event);
      void invoke(const ls::standard::event::Event &_event);
      void invoke(const ls::standard::event::Event &_event, const ls::standard::event::EventParameter &_parameter);
      [[nodiscard]] ls::standard::event::type::listener_id requestListenerId();
      void subscribeListenerForEvent(::std::shared_ptr<ls::standard::event::EventListener> _listener, const ls::standard::event::Event &_event, ls::standard::event::type::event_action _action);
      void unsubscribeListenerForEvent(const ::std::shared_ptr<ls::standard::event::EventListener> &_listener, const ls::standard::event::Event &_event);

    private:

      ls::standard::event::type::event_observability_inventory inventory{};
      ls::standard::event::type::listener_id provisionId = 1;

      static void _giveListenersParameter(const ls::standard::event::type::event_listeners &_listeners, const ls::standard::event::EventParameter &_parameter);
      static void _notifyListeners(const ls::standard::event::type::event_listeners &_listeners);
      bool _observesEvent(const ls::standard::event::Event &_event) const;
  };
}

#endif
