#ifndef DefaultContextManagerH
#define DefaultContextManagerH

#include "context/Context.h"
#include "context/EventData.h"
#include "context/EventDefinition.h"
#include "context/DefaultContextVisitor.h"
#include <boost/thread.hpp>

class DefaultContextManager : public ContextManager
{
private:
    void init(bool async, int eventQueueLength);
    void addEventListener(const AgString & context, const AgString & event, ContextEventListenerPtr listener, bool mask, bool weak);
    void removeEventListener(const AgString & context, const AgString & event, ContextEventListenerPtr listener, bool mask);
    std::map<AgString, ContextEventListenerSetPtr> getContextListeners(const AgString & context);
    ContextEventListenerSetPtr getMaskListeners(const AgString & mask, const AgString & event);
    std::map<AgString, ContextEventListenerSetPtr> getContextMaskListeners(const AgString & mask);

    bool async;
    Context* rootContext;
    CallerControllerPtr callerController;
    std::map< AgString, std::map<AgString, ContextEventListenerSetPtr> > eventListeners;
    boost::mutex eventListenersLock;
    std::map< AgString, std::map<AgString, ContextEventListenerSetPtr> > maskListeners;
    boost::recursive_mutex maskListenersLock;
    ThreadPoolCachedExPtr executorService;
    bool started;

public:

    virtual void start();
    virtual void stop();
    virtual void restart();


    Context* getRoot();
    void setRoot(Context* newRoot);
    Context* get(const AgString & contextName, CallerControllerPtr caller);
    Context* get(const AgString & contextName);
    void addListenerToContext(Context* con, const AgString & event, ContextEventListenerPtr listener, bool mask, bool weak);


    void removeListenerFromContext(Context* con, const AgString & event, ContextEventListenerPtr listener, bool mask);

    void addMaskEventListener(const AgString & mask, const AgString & event, ContextEventListenerPtr listener);
    void addMaskEventListener(const AgString & mask, const AgString & event, ContextEventListenerPtr listener, bool weak);
    void removeMaskEventListener(const AgString & mask, const AgString & event, ContextEventListenerPtr listener);

    ContextEventListenerSetPtr getListeners(const AgString & context, const AgString & event);

    void queue(EventDataPtr ed, EventPtr ev);

    void contextAdded(Context* con);
    void contextRemoved(Context* con);
    void contextInfoChanged(Context* con);
    void variableAdded(Context* con, VariableDefinitionPtr vd);
    void variableRemoved(Context* con, VariableDefinitionPtr vd);
    void functionAdded(Context* con, FunctionDefinitionPtr fd);
    void functionRemoved(Context* con, FunctionDefinitionPtr fd);
    virtual void eventAdded(Context* con, EventDefinitionPtr ed);
    void eventRemoved(Context* con, EventDefinitionPtr ed);

    void setExecutorService(ThreadPoolCachedExPtr executorService);

    ThreadPoolCachedExPtr getExecutorService();
    CallerControllerPtr getCallerController();
    bool isStarted();

	DefaultContextManager(bool async);
    DefaultContextManager(bool async, int eventQueueLength);
    DefaultContextManager(Context* rootContext, bool async);
    virtual ~DefaultContextManager();

    class CustomDefaultContextVisitor1 : public DefaultContextVisitor
    {
    private:
        DefaultContextManager &contextManager;
    public:
        CustomDefaultContextVisitor1(DefaultContextManager &defaultContextManager) : contextManager(defaultContextManager) {}
        virtual void visit(Context* vc);
    };

    class CustomDefaultContextVisitor2 : public DefaultContextVisitor
    {
    private:
        DefaultContextManager &contextManager;
    public:
        CustomDefaultContextVisitor2(DefaultContextManager &defaultContextManager) : contextManager(defaultContextManager) {}
        virtual void visit(Context* vc);
    };
};
#endif
