#pragma once

#include <functional>
#include <hack/patterns/singleton.hpp>
#include <hack/logger/logger.hpp>
#include <hack/security/uuid.hpp>

#include "event.hpp"

namespace VE
{
  struct event_manager : public hack::patterns::singleton<event_manager>
  {
    void emit(event e)
    {
      try
      {
        for(auto& f : m_funcs) f.func(e);
      }
      catch(const std::exception& ex)
      {
        hack::error()(ex.what());
        hack::log()("size funcs", m_funcs.size());
      }
      catch(...)
      {
        hack::error()("ooops...");
      }
    }

    struct EventHandler 
    {
      std::function<void(event)> func;
      void* obj;
    };

    std::vector<EventHandler> m_funcs;

    template<typename T>
    void connect(T* obj, void (T::*method)(event)) 
    {
      m_funcs.push_back({
        std::bind(method, obj, std::placeholders::_1),
        static_cast<void*>(obj)
      });
    }

    template<typename T>
    void disconnect(T* obj, void (T::*method)(event)) 
    {
      m_funcs.erase(
        std::remove_if(m_funcs.begin(), m_funcs.end(),
          [obj](const auto& handler) {
            return handler.obj == obj;
          }),
        m_funcs.end()
      );
    }
  };
}
