#include <mega/file_service/file_event.h>
#include <mega/file_service/file_event_emitter.h>
#include <mega/file_service/file_event_observer_result.h>

#include <cassert>

namespace mega
{
namespace file_service
{

FileEventObserverID FileEventEmitter::addObserver(FileEventObserver observer)
{
    // Make sure no one else is modifying our map of observers.
    std::lock_guard guard(mObserversLock);

    // Add the observer to our map.
    auto [iterator, _] = mObservers.emplace(mNextID++, std::move(observer));

    // Return the observer's ID to our caller.
    return std::make_pair(this, iterator->first);
}

void FileEventEmitter::notify(const FileEvent& event)
{
    // Make sure no threads are modifying our map of observers.
    std::lock_guard guard(mObserversLock);

    // Transmit event to each observer.
    for (auto i = mObservers.begin(); i != mObservers.end();)
    {
        // Just in case the observer removes itself.
        auto j = i++;

        // Transmit event to our observer.
        auto result = j->second(event);

        // Observer wants to be removed.
        if (result == FILE_EVENT_OBSERVER_REMOVE)
            mObservers.erase(j);
    }
}

void FileEventEmitter::removeObserver(FileEventObserverID id)
{
    // Convenience.
    auto* emitter = std::get<FileEventEmitter*>(id);

    // For debugging purposes.
    assert(emitter == this);

    // ID was generated by some other event emitter.
    if (emitter != this)
        return;

    // Make sure no one else is modifying our map of observer.
    std::lock_guard guard(mObserversLock);

    // Remove the the observer from the map.
    mObservers.erase(std::get<std::uint64_t>(id));
}

} // file_service
} // mega
