#include "event/ContextEventListenerSet.h"
#include "context/ContextRuntimeException.h"
#include "boost/thread/lock_guard.hpp"

boost::unordered_set<ContextEventListenerPtr> ContextEventListenerSet::getListeners()
{
    boost::lock_guard<boost::recursive_mutex> lock(mutex);
    
    boost::unordered_set<ContextEventListenerPtr> localListeners;

    for (boost::unordered_set<AgObjectPtr>::iterator iterator = listeners.begin(); iterator!=listeners.end(); ++iterator) {

        ContextEventListenerInfoPtr li = getListenerInfo(*iterator);

        if (li == NULL) {
            iterator = listeners.erase( iterator );
            continue;
        }

        localListeners.insert(li->getListener());
    }

    return localListeners;
}

boost::unordered_set<ContextEventListenerInfoPtr> ContextEventListenerSet::getListenersInfo()
{
    boost::lock_guard<boost::recursive_mutex> lock(mutex);

	boost::unordered_set<ContextEventListenerInfoPtr> localListeners;
    for (boost::unordered_set<AgObjectPtr>::iterator iterator = listeners.begin(); iterator!=listeners.end(); ++iterator) {
        ContextEventListenerInfoPtr li = getListenerInfo(*iterator);
        if(li == 0) {
            iterator = listeners.erase( iterator );
            continue;
        }
        localListeners.insert(li);
    }

	return localListeners;
}

bool ContextEventListenerSet::addListener(ContextEventListenerPtr listener, bool weak)
{   
    UNUSED(weak);
    boost::lock_guard<boost::recursive_mutex> lock(mutex);

	if(contains(listener)) {
        return false;
    }
    listeners.insert(boost::dynamic_pointer_cast<AgObject>(listener));

	return true;
}

bool ContextEventListenerSet::removeListener(ContextEventListenerPtr listener)
{
    boost::lock_guard<boost::recursive_mutex> lock(mutex);


    for (boost::unordered_set<AgObjectPtr>::iterator iterator = listeners.begin(); iterator!=listeners.end(); ++iterator) {
        ContextEventListenerInfoPtr li = getListenerInfo(*iterator);
        if (li == 0) {
            iterator = listeners.erase( iterator );
            continue;
        }

        if(li->getListener()->equals(listener.get())) {
            iterator = listeners.erase( iterator );
            return true;
        }
    }

    return false;
}

bool ContextEventListenerSet::contains(ContextEventListenerPtr listener)
{
    boost::lock_guard<boost::recursive_mutex> lock(mutex);

    for (boost::unordered_set<AgObjectPtr>::iterator iterator = listeners.begin(); iterator!=listeners.end(); ++iterator) {
        ContextEventListenerInfoPtr li = getListenerInfo(*iterator);
        if(li == 0) {
            iterator = listeners.erase( iterator );
            continue;
        }

        if(li->getListener() != NULL && li->getListener() == listener) {
            return true;
        }
    }

    return false;
}

void ContextEventListenerSet::clear()
{	
    boost::lock_guard<boost::recursive_mutex> lock(mutex);
    listeners.clear();
}

int ContextEventListenerSet::size()
{
    boost::lock_guard<boost::recursive_mutex> lock(mutex);
    return listeners.size();
}

ContextEventListenerInfoPtr ContextEventListenerSet::getListenerInfo(AgObjectPtr ref)
{
    if (dynamic_cast< ContextEventListener* >(ref.get()) != 0) {

        return ContextEventListenerInfoPtr(
                    new ContextEventListenerInfo(boost::dynamic_pointer_cast<ContextEventListener>(ref), false));
    }else {

        throw ContextRuntimeException("Unexpected reference: " + ref->toString());
    }
}


