/***********************************************************
 * God Mode On, Und[0]ne Devs < http://undonedevs.tk >
 * 2013 Pepe Romero < wizardpepe@gmail.com >
 * < https://bitbucket.org/undone_devs/god-mode-on >
 ***********************************************************/

#define RESOLUTIONH 1280
#define RESOLUTIONV 720

#include <Ogre.h>

#include "GameManager.h"
#include "GameState.h"

template<> GameManager* Ogre::Singleton<GameManager>::msSingleton = 0;

GameManager::GameManager()
{
    _root = 0;
}

GameManager::~GameManager()
{
    while (!_states.empty()) {
        _states.top()->exit();
        _states.pop();
    }

    if (_root)
        delete _root;
}

void GameManager::start(GameState* state)
{
    // Creación del objeto Ogre::Root.
    _root = new Ogre::Root("", "game.cfg", "game.log");

    // Carga de recursos
    loadResources();

    // Configuración
    if (!configure())
        return;

    _inputMgr = new InputManager;
    _inputMgr->initialise(_renderWindow);

    // Registro como key y mouse listener...
    _inputMgr->addKeyListener(this, "GameManager");
    _inputMgr->addMouseListener(this, "GameManager");

    // El GameManager es un FrameListener.
    _root->addFrameListener(this);

    // Transición al estado inicial.
    changeState(state);

    // Bucle de rendering.
    _root->startRendering();
}

void GameManager::changeState(GameState* state)
{
    // Limpieza del estado actual.
    if (!_states.empty()) {
        // exit() sobre el último estado.
        _states.top()->exit();
        // Elimina el último estado.
        _states.pop();
    }

    // Transición al nuevo estado.
    _states.push(state);
    // enter() sobre el nuevo estado.
    _states.top()->enter();
}

void GameManager::pushState(GameState* state)
{
    // Pausa del estado actual.
    if (!_states.empty())
        _states.top()->pause();

    // Transición al nuevo estado.
    _states.push(state);
    // enter() sobre el nuevo estado.
    _states.top()->enter();
}

void GameManager::popState()
{
    // Limpieza del estado actual.
    if (!_states.empty()) {
        _states.top()->exit();
        _states.pop();
    }

    // Vuelta al estado anterior.
    if (!_states.empty())
        _states.top()->resume();
}

void GameManager::loadResources()
{
    // Carga de plugins
    Ogre::String ruta = "./lib/OGRE/Plugins/";
	_root->loadPlugin(ruta + "RenderSystem_GL");
	_root->loadPlugin(ruta + "Plugin_ParticleFX");
	_root->loadPlugin(ruta + "Plugin_BSPSceneManager");
	_root->loadPlugin(ruta + "Plugin_PCZSceneManager");
	_root->loadPlugin(ruta + "Plugin_OctreeZone");
	_root->loadPlugin(ruta + "Plugin_OctreeSceneManager");

}

bool GameManager::configure()
{
    // Carga de configuración si no existe
    if (!_root->restoreConfig()) {
        if (!_root->showConfigDialog()) { return false; }
    }

    // Obliga al uso de no fullscreen y resolución determinada
    _root->getRenderSystem()->setConfigOption("Full Screen", "No");
    _root->getRenderSystem()->setConfigOption("Video Mode", Ogre::StringConverter::toString(RESOLUTIONH) + " x " + \
                                                            Ogre::StringConverter::toString(RESOLUTIONV) + " @ 32-bit colour");

    _renderWindow = _root->initialise(true, "God Mode On");

    return true;
}

GameManager* GameManager::getSingletonPtr()
{
    return msSingleton;
}

GameManager& GameManager::getSingleton()
{
    assert(msSingleton);
    return *msSingleton;
}

// Las siguientes funciones miembro delegan el evento en el estado actual.
bool GameManager::frameStarted(const Ogre::FrameEvent& evt)
{
    _inputMgr->capture();
    return _states.top()->frameStarted(evt);
}

bool GameManager::frameEnded(const Ogre::FrameEvent& evt)
{
    return _states.top()->frameEnded(evt);
}

bool GameManager::keyPressed(const OIS::KeyEvent &e)
{
    _states.top()->keyPressed(e);
    return true;
}

bool GameManager::keyReleased(const OIS::KeyEvent &e)
{
    _states.top()->keyReleased(e);
    return true;
}

bool GameManager::mouseMoved(const OIS::MouseEvent &e)
{
    _states.top()->mouseMoved(e);
    return true;
}

bool GameManager::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
    _states.top()->mousePressed(e, id);
    return true;
}

bool GameManager::mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
    _states.top()->mouseReleased(e, id);
    return true;
}
