#include "context/DefaultContextManager.h"
#include "event/EventUtils.h"
#include "event/ContextEventListener.h"
#include "event/ContextEventListenerSet.h"
#include "context/ContextException.h"
#include "context/UncheckedCallerController.h"
#include "AggreGateException.h"
#include "IllegalStateException.h"
#include <limits.h>
#include <iterator>


DefaultContextManager::DefaultContextManager(bool async)
{
    init(async, INT_MAX);
}

DefaultContextManager::DefaultContextManager(bool async, int /*eventQueueLength*/)
{
    init(async, INT_MAX);
}

DefaultContextManager::DefaultContextManager(Context* rootContext, bool async)
{
    init(async, INT_MAX);
    setRoot(rootContext);
    start();
}

DefaultContextManager::~DefaultContextManager()
{
    SAFE_DELETE(rootContext);
}

void DefaultContextManager::init(bool async, int /*eventQueueLength*/)
{
    rootContext = NULL;
    if (async)
    {
        throw AggreGateException("Async mode is not currently supported in DefaultContextManager");
    }

    this->async = async;
    callerController = CallerControllerPtr(new UncheckedCallerController());
    started = false;
}


void DefaultContextManager::start()
{
    if (rootContext != NULL)
    {
        rootContext->start();
    }
    started = true;
}

void DefaultContextManager::stop()
{
    started = false;
    if(rootContext != NULL)
    {
        rootContext->stop();
    }
}

void DefaultContextManager::restart()
{
    stop();
    start();
}

Context* DefaultContextManager::getRoot()
{
    return rootContext;
}

void DefaultContextManager::setRoot(Context* newRoot)
{
    SAFE_DELETE(rootContext);

    rootContext = newRoot;
    rootContext->setup(this);
    contextAdded(newRoot);
}

Context* DefaultContextManager::get(const AgString & contextName, CallerControllerPtr caller)
{
    Context* root = getRoot();

    return root != 0 ? (root->get(contextName, caller)) : NULL;
}

Context* DefaultContextManager::get(const AgString & contextName)
{
    Context* root = getRoot();

    return root != 0 ? (root->get(contextName)) : NULL;
}

void DefaultContextManager::addEventListener(const AgString & context, const AgString & event, ContextEventListenerPtr listener, bool mask, bool weak)
{
    Context* con = get(context, listener->getCallerController());
    if(con != 0)
    {
        std::list<EventDefinitionPtr> events = EventUtils::getEvents(con, event, listener->getCallerController());
        for (std::list<EventDefinitionPtr>::iterator it = events.begin(); it!=events.end(); ++it)
        {
            addListenerToContext(con, (*it)->getName(), listener, mask, weak);
        }
    }
    else
    {
        if (!mask)
        {
            ContextEventListenerSetPtr eel = getListeners(context, event);
            if(!eel->contains(listener))
            {
                eel->addListener(listener, weak);
            }
        }
    }
}

void DefaultContextManager::addListenerToContext(Context* con, const AgString & event, ContextEventListenerPtr listener,
                                                 bool /*mask*/, bool weak)
{
    EventDefinitionPtr ed = con->getEventDefinition(event, listener->getCallerController());
    if (ed != 0)
    {
        con->addEventListener(event, listener, weak);
    }
}

void DefaultContextManager::removeEventListener(const AgString & context, const AgString & event,
                                                ContextEventListenerPtr listener, bool mask)
{
    Context* con = get(context, listener->getCallerController());
    if (con != 0) {
        if (con->getEventDefinition(event) != 0) {
            removeListenerFromContext(con, event, listener, mask);
        }
    } else {
        if(!mask) {
            ContextEventListenerSetPtr eel = getListeners(context, event);
            if(eel != 0) {
                eel->removeListener(listener);
            }
        }
    }
}

void DefaultContextManager::removeListenerFromContext(Context* con, const AgString & event, ContextEventListenerPtr listener, bool /*mask*/)
{
    con->removeEventListener(event, listener);
}

void DefaultContextManager::addMaskEventListener(const AgString & mask, const AgString & event, ContextEventListenerPtr listener)
{
    addMaskEventListener(mask, event, listener, false);
}

void DefaultContextManager::addMaskEventListener(const AgString & mask, const AgString & event,
                                                 ContextEventListenerPtr listener, bool weak)
{
    std::list<AgString> contexts = ContextUtils::expandMaskToPaths(mask, this, listener->getCallerController());
    for (std::list<AgString>::iterator it = contexts.begin(); it != contexts.end(); ++it) {
        addEventListener(*it, event, listener, true, weak);
    }
    ContextEventListenerSetPtr listeners = getMaskListeners(mask, event);
    listeners->addListener(listener, weak);
}

void DefaultContextManager::removeMaskEventListener(const AgString & mask, const AgString & event, ContextEventListenerPtr listener)
{
    std::list<Context*> contexts = ContextUtils::expandMaskToContexts(mask, this, listener->getCallerController());

    for (std::list<Context*>::iterator it = contexts.begin(); it!=contexts.end(); ++it) {
        if (!(*it)->isInitializedEvents()) {
            continue;
        }

        std::list<EventDefinitionPtr> events = EventUtils::getEvents((*it), event, listener->getCallerController());

        for (std::list<EventDefinitionPtr>::iterator itEvent = events.begin(); itEvent!=events.end(); ++itEvent) {
            removeEventListener((*it)->getPath(), (*itEvent)->getName(), listener, true);
        }
    }

    ContextEventListenerSetPtr listeners = getMaskListeners(mask, event);

    listeners->removeListener(listener);
}

ContextEventListenerSetPtr DefaultContextManager::getListeners(const AgString & context, const AgString & event)
{
    std::map<AgString, ContextEventListenerSetPtr> cel = getContextListeners(context);

    ContextEventListenerSetPtr cels;
    if (cel.find(event) == cel.end())
    {
        cels = ContextEventListenerSetPtr(new ContextEventListenerSet());
        cel[event] = cels;
    }
    else
    {
        cels = cel[event];
    }

    return cels;
}

void DefaultContextManager::queue(EventDataPtr ed, EventPtr ev)
{
    if (async && !ed->getDefinition()->isSynchronous())
    {
        throw AggreGateException("Async mode is not currently supported in DefaultContextManager");
    }
    if (!async || ed->getDefinition()->isSynchronous())
        ed->dispatch(ev);
}

std::map<AgString, ContextEventListenerSetPtr> DefaultContextManager::getContextListeners(const AgString & context)
{
    std::map<AgString, ContextEventListenerSetPtr> cel;

    eventListenersLock.lock();
    if (cel.find(context) == cel.end())
    {
        eventListeners[context] = cel;
    }
    else
    {
        cel = eventListeners[context];
    }
    eventListenersLock.unlock();

    return cel;
}

ContextEventListenerSetPtr DefaultContextManager::getMaskListeners(const AgString & mask, const AgString & event)
{
    std::map<AgString, ContextEventListenerSetPtr> cel = getContextMaskListeners(mask);

    ContextEventListenerSetPtr eel;

    if (cel.find(event) == cel.end())
    {
        eel = ContextEventListenerSetPtr(new ContextEventListenerSet());
        cel[event] = eel;
    }
    else
    {
        eel = cel[event];
    }

    return eel;
}

std::map<AgString, ContextEventListenerSetPtr> DefaultContextManager::getContextMaskListeners(const AgString & mask)
{
    std::map<AgString, ContextEventListenerSetPtr> cel;
    {
        boost::lock_guard<boost::recursive_mutex> lock(maskListenersLock);
        std::map< AgString, std::map<AgString, ContextEventListenerSetPtr> >::iterator it = maskListeners.find(mask);
        if (it != maskListeners.end())
        {
            cel = it->second;
        }
    }

    if (cel.size() == 0)
    {
        boost::lock_guard<boost::recursive_mutex> lock2(maskListenersLock);
        maskListeners[mask] = cel;
    }

    return cel;
}

void DefaultContextManager::contextAdded(Context* con)
{
    std::map< AgString, std::map<AgString, ContextEventListenerSetPtr> >::iterator itcel;
    eventListenersLock.lock();
    itcel = eventListeners.find(con->getPath());
    bool bFound = itcel != eventListeners.end();
    eventListenersLock.unlock();

    if (bFound)
    {
        std::map<AgString, ContextEventListenerSetPtr> cel = itcel->second;

        for (std::map<AgString, ContextEventListenerSetPtr>::iterator it = cel.begin(); it!=cel.end(); ++it )
        {
            ContextEventListenerSetPtr cels = cel[it->first];
            cels->lock();

            boost::unordered_set<ContextEventListenerInfoPtr> celi = (it->second)->getListenersInfo();
            for (boost::unordered_set<ContextEventListenerInfoPtr>::iterator itCeli = celi.begin(); itCeli!=celi.end(); ++it)
            {
                if (con->getEventData(it->first) != 0)
                {
                    con->addEventListener(it->first, (*itCeli)->getListener(), (*itCeli)->isWeak());
                }

            }

            cels->unlock();
        }
    }

    {
        boost::lock_guard<boost::recursive_mutex> lock(maskListenersLock);

        typedef std::map<AgString, std::map<AgString, ContextEventListenerSetPtr> > maskListenerType;
        for (maskListenerType::iterator it = maskListeners.begin(); it != maskListeners.end(); ++it)
        {
            if (ContextUtils::matchesToMask(it->first, con->getPath()))
            {

                std::map<AgString, ContextEventListenerSetPtr> mcel = getContextMaskListeners(it->first);
                for (std::map<AgString, ContextEventListenerSetPtr>::iterator itMcel = mcel.begin(); itMcel != mcel.end(); ++itMcel)
                {

                    ContextEventListenerSetPtr elistener = itMcel->second;

                    elistener->lock();
                    boost::unordered_set<ContextEventListenerInfoPtr> li = elistener->getListenersInfo();
                    for (boost::unordered_set<ContextEventListenerInfoPtr>::iterator itLi = li.begin(); itLi!=li.end(); ++itLi)
                    {
                        std::list<EventDefinitionPtr> events = EventUtils::getEvents(con, itMcel->first, (*itLi)->getListener()->getCallerController());

                        for (std::list<EventDefinitionPtr>::iterator ed_it = events.begin(); ed_it!=events.end(); ++ed_it)
                        {
                            addListenerToContext(con, (*ed_it)->getName(), (*itLi)->getListener(), true, (*itLi)->isWeak());
                        }
                    }
                    elistener->unlock();
                }
            }
        }
    }
}

void DefaultContextManager::contextRemoved(Context* con)
{
    try
    {
        con->accept(ContextVisitorPtr(new CustomDefaultContextVisitor1(*this)));
        con->accept(ContextVisitorPtr(new CustomDefaultContextVisitor2(*this)));
    }
    catch (ContextException ex)
    {
        throw IllegalStateException(ex.getMessage(), ex.getDetails());
    }
}

void DefaultContextManager::contextInfoChanged(Context* /*con*/)
{
}

void DefaultContextManager::variableAdded(Context* /*con*/, VariableDefinitionPtr vd)
{
    UNUSED(vd);
}

void DefaultContextManager::variableRemoved(Context* /*con*/, VariableDefinitionPtr vd)
{
    UNUSED(vd);
}

void DefaultContextManager::functionAdded(Context* /*con*/, FunctionDefinitionPtr fd)
{
    UNUSED(fd);
}

void DefaultContextManager::functionRemoved(Context* /*con*/, FunctionDefinitionPtr fd)
{
    UNUSED(fd);
}

void DefaultContextManager::eventAdded(Context* con, EventDefinitionPtr ed)
{
    boost::lock_guard<boost::recursive_mutex> lock(maskListenersLock);
    {
        typedef std::map<AgString, std::map<AgString, ContextEventListenerSetPtr> > maskListenerType;
        for (maskListenerType::iterator it = maskListeners.begin(); it != maskListeners.end(); ++it)
        {
            if (ContextUtils::matchesToMask(it->first, con->getPath()))
            {
                std::map<AgString, ContextEventListenerSetPtr> cel = getContextMaskListeners(it->first);
                for (std::map<AgString, ContextEventListenerSetPtr>::iterator itcel = cel.begin(); itcel != cel.end(); ++itcel)
                {
                    if (EventUtils::matchesToMask(itcel->first, ed))
                    {
                        ContextEventListenerSetPtr listeners = cel[itcel->first];

                        listeners->lock();
                        boost::unordered_set<ContextEventListenerInfoPtr> listenersInfo = listeners->getListenersInfo();
                        for (boost::unordered_set<ContextEventListenerInfoPtr>::iterator li = listenersInfo.begin(); li != listenersInfo.end(); ++li)
                        {
                            addListenerToContext(con, ed->getName(), (*li)->getListener(), true, (*li)->isWeak());
                        }
                        listeners->lock();
                    }
                }
            }
        }
    }
}

void DefaultContextManager::eventRemoved(Context* /*con*/, EventDefinitionPtr ed)
{
    UNUSED(ed);
}

void DefaultContextManager::setExecutorService(ThreadPoolCachedExPtr executorService)
{
    this->executorService = executorService;
}

ThreadPoolCachedExPtr DefaultContextManager::getExecutorService()
{
    return executorService;
}

CallerControllerPtr DefaultContextManager::getCallerController()
{
    return callerController;
}

bool DefaultContextManager::isStarted()
{
    return started;
}


void DefaultContextManager::CustomDefaultContextVisitor1::visit(Context* vc)
{
   boost::lock_guard<boost::recursive_mutex> lock(contextManager.maskListenersLock);

   for (std::map< AgString, std::map<AgString, ContextEventListenerSetPtr> >::iterator itmask = contextManager.maskListeners.begin();
                                                                                       itmask != contextManager.maskListeners.end(); ++itmask)
   {
       AgString mask = itmask->first;
       if (ContextUtils::matchesToMask(mask, vc->getPath()))
       {
           std::map<AgString, ContextEventListenerSetPtr> contextMaskListeners = contextManager.getContextMaskListeners(mask);

           for (std::map<AgString, ContextEventListenerSetPtr>::iterator it = contextMaskListeners.begin(); it != contextMaskListeners.end(); ++it)
           {
                AgString event = it->first;
                ContextEventListenerSetPtr cels = contextManager.getMaskListeners(mask, event);
                boost::unordered_set<ContextEventListenerInfoPtr> listenersInfo = cels->getListenersInfo();

                for (boost::unordered_set<ContextEventListenerInfoPtr>::iterator li = listenersInfo.begin(); li != listenersInfo.end(); ++li)
                {
                    std::list<EventDefinitionPtr> events = EventUtils::getEvents(vc, event, (*li)->getListener()->getCallerController());

                    for (std::list<EventDefinitionPtr>::iterator ed = events.begin(); ed != events.end(); ++ed)
                    {
                        vc->removeEventListener((*ed)->getName(), (*li)->getListener());
                    }
                }
           }
       }
   }
}


void DefaultContextManager::CustomDefaultContextVisitor2::visit(Context* vc)
{
    std::map<AgString, ContextEventListenerSetPtr> cel = contextManager.getContextListeners(vc->getPath());
    std::list<EventDefinitionPtr> eventDefinitions = vc->getEventDefinitions(contextManager.callerController);
    for (std::list<EventDefinitionPtr>::iterator ed = eventDefinitions.begin(); ed != eventDefinitions.end(); ++ed)
    {
        EventDataPtr edata = vc->getEventData((*ed)->getName());

        std::map<AgString, ContextEventListenerSetPtr>::iterator it = cel.find((*ed)->getName());
        if (it != cel.end())
        {
            ContextEventListenerSetPtr listeners = it->second;
            listeners->lock();

            boost::unordered_set<ContextEventListenerInfoPtr> listenersInfo =  edata->getListenersInfo();
            for (boost::unordered_set<ContextEventListenerInfoPtr>::iterator celi = listenersInfo.begin(); celi != listenersInfo.end(); ++celi)
            {
                listeners->addListener((*celi)->getListener(), (*celi)->isWeak());
            }
            listeners->unlock();
        }
    }
}
