#include "Base.h"
#include "AIStateMachine.h"
#include "AIAgent.h"
#include "AIMessage.h"
#include "Game.h"

namespace gameplay
{

AIStateMachine::AIStateMachine(AIAgent* agent)
    : _agent(agent)
{
    GP_ASSERT(agent);
    if (AIState::_empty)
        AIState::_empty->addRef();
    else
        AIState::_empty = new AIState("");
    _currentState = AIState::_empty;
}

AIStateMachine::~AIStateMachine()
{
    // Release all states
    for (std::list<AIState*>::iterator itr = _states.begin(); itr != _states.end(); ++itr)
    {
        (*itr)->release();
    }

    if (AIState::_empty)
    {
        if (AIState::_empty->getRefCount() == 1)
        {
            SAFE_RELEASE(AIState::_empty);
        }
        else
        {
            AIState::_empty->release();
        }
    }
}

AIAgent* AIStateMachine::getAgent() const
{
    return _agent;
}

AIState* AIStateMachine::addState(const char* id)
{
    AIState* state = AIState::create(id);
    _states.push_back(state);
    return state;
}

void AIStateMachine::addState(AIState* state)
{
    state->addRef();
    _states.push_back(state);
}

void AIStateMachine::removeState(AIState* state)
{
    std::list<AIState*>::iterator itr = std::find(_states.begin(), _states.end(), state);
    if (itr != _states.end())
    {
        _states.erase(itr);
        state->release();
    }
}

AIState* AIStateMachine::getState(const char* id) const
{
    GP_ASSERT(id);

    for (std::list<AIState*>::const_iterator itr = _states.begin(); itr != _states.end(); ++itr)
    {
        AIState* state = (*itr);

        if (strcmp(id, state->getId()) == 0)
            return state;
    }

    return NULL;
}

AIState* AIStateMachine::getActiveState() const
{
    return _currentState;
}

bool AIStateMachine::hasState(AIState* state) const
{
    GP_ASSERT(state);

    return (std::find(_states.begin(), _states.end(), state) != _states.end());
}

AIState* AIStateMachine::setState(const char* id)
{
    AIState* state = getState(id);
    if (state)
        sendChangeStateMessage(state);
    return state;
}

bool AIStateMachine::setState(AIState* state)
{
    if (hasState(state))
    {
        sendChangeStateMessage(state);
        return true;
    }

    return false;
}

void AIStateMachine::sendChangeStateMessage(AIState* newState)
{
    AIMessage* message = AIMessage::create(0, _agent->getId(), _agent->getId(), 1);
    message->_messageType = AIMessage::MESSAGE_TYPE_STATE_CHANGE;
    message->setString(0, newState->getId());
    Game::getInstance()->getAIController()->sendMessage(message);
}

void AIStateMachine::setStateInternal(AIState* state)
{
    GP_ASSERT(hasState(state));

    // Fire the exit event for the current state
    _currentState->exit(this);

    // Set the new state
    _currentState = state;

    // Fire the enter event for the new state
    _currentState->enter(this);
}

void AIStateMachine::update(float elapsedTime)
{
    _currentState->update(this, elapsedTime);
}

}
