#include "EventBus.hpp"

EventBus &EventBus::getInstance()
{
	static EventBus instance;
	return instance;
}

EventBus::ListenerId EventBus::subscribe(const Ogre::String &eventName,
					 Callback cb)
{
	ListenerId id = m_nextId++;
	m_listeners[eventName].push_back({ id, std::move(cb) });
	m_idToEvent[id] = eventName;
	return id;
}

void EventBus::unsubscribe(ListenerId id)
{
	auto it = m_idToEvent.find(id);
	if (it == m_idToEvent.end())
		return;

	const Ogre::String &eventName = it->second;
	auto lit = m_listeners.find(eventName);
	if (lit != m_listeners.end()) {
		auto &vec = lit->second;
		for (auto vit = vec.begin(); vit != vec.end(); ++vit) {
			if (vit->id == id) {
				vec.erase(vit);
				break;
			}
		}
		if (vec.empty())
			m_listeners.erase(lit);
	}
	m_idToEvent.erase(it);
}

void EventBus::send(const Ogre::String &eventName,
		    const editScene::EventParams &params)
{
	auto lit = m_listeners.find(eventName);
	if (lit == m_listeners.end())
		return;

	// Copy the listener list in case a callback mutates subscriptions
	auto listeners = lit->second;
	for (const auto &listener : listeners) {
		if (listener.callback)
			listener.callback(eventName, params);
	}
}

void EventBus::send(const Ogre::String &eventName,
		    const Ogre::String &paramName, const Ogre::String &value)
{
	editScene::EventParams params;
	params.setString(paramName, value);
	send(eventName, params);
}

void EventBus::send(const Ogre::String &eventName,
		    const Ogre::String &paramName, int64_t value)
{
	editScene::EventParams params;
	params.setInt(paramName, value);
	send(eventName, params);
}

void EventBus::send(const Ogre::String &eventName,
		    const Ogre::String &paramName, float value)
{
	editScene::EventParams params;
	params.setFloat(paramName, value);
	send(eventName, params);
}

void EventBus::send(const Ogre::String &eventName,
		    const Ogre::String &paramName, double value)
{
	editScene::EventParams params;
	params.setDouble(paramName, value);
	send(eventName, params);
}

void EventBus::send(const Ogre::String &eventName,
		    const Ogre::String &paramName, uint64_t entityId)
{
	editScene::EventParams params;
	params.setEntityId(paramName, entityId);
	send(eventName, params);
}
