#ifndef AgentH
#define AgentH

#include "AgentContext.h"
#include "AgentImplementationController.h"

#include "context/DefaultContextManager.h"
#include "protocol/RemoteServer.h"
#include "util/Pointers.h"

#include <boost/foreach.hpp>

class Agent
{

public:

    static const int DEFAULT_PORT = 6480;

    Agent(RemoteServerPtr server, AgString name, bool eventConfirmation);

    Agent(AgentContext *context);

    virtual ~Agent(){}

    ContextEventListenerPtr getContextEventListener();

    void connect();

    void disconnect();

    void reconnect();

    void run();

    RemoteServerPtr getServer();

    AgentContext* getContext();

    int getMaxEventQueueLength();

    void setMaxEventQueueLength(int maxEventQueueLength);

    bool isConnected();

private:

    int maxEventQueueLength;

    RemoteServerPtr server;

    AgentContext *context;

    ContextManagerPtr contextManager;

    AgentImplementationControllerPtr controller;

    BlockingChannelPtr dataChannel;
};

class AgentContextVisitor : public ContextVisitor
{

private:

    boost::function<ContextEventListenerPtr()> controller;

public:

    AgentContextVisitor(Agent* agent)
    {
        controller = boost::bind(&Agent::getContextEventListener, agent);
    }

    virtual bool shouldVisit(Context* /*context*/)
    {
        return true;
    }

    virtual void visit(Context* context)
    {
        std::list<EventDefinitionPtr> eventDefinitions = context->getEventDefinitions();

        BOOST_FOREACH(boost::shared_ptr<EventDefinition> ed, eventDefinitions)
        {
            if (!ed->getGroup().empty())
            {
                context->addEventListener(ed->getName(), controller(), true);
            }
        }
    }
};

#endif
