/*Copyright (C) 2010-2012 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "Fight.hpp"
#include "Engines/GameEngine.hpp"

Fight::Fight(GameEngine *gameEngine) :
m_gameEngine(gameEngine), m_window(gameEngine->getWindow()),
m_configuration(gameEngine->getConfiguration())
{
    
}

void Fight::setArena(const std::string &arenaName)
{
    m_arenaPath = arenaName;
}

void Fight::addPlayer(const std::string &playerName, int playerType)
{
    m_playersDataList.push_back( make_pair(playerType, playerName) );
}

void Fight::clearPlayers()
{
    m_playersDataList.clear();
}

void Fight::run()
{
    //Init variables
    TextureManager textureManager;
    FontManager fontManager;
    SoundBufferManager soundBufferManager;
    
        //View
    Vector viewSize = Vector(m_window->getViewWidth(), m_window->getViewHeight());
    
        //Interface
    FightInterface interface;
    interface.setFonts(*fontManager.getFont("data/gfx/fonts/default.ttf", 30), *fontManager.getFont("data/gfx/fonts/default.ttf", 10));
    interface.setXPosition(100);
    interface.setYPosition(20);
    
    Text fpsText;
    fpsText.setFont(*fontManager.getFont("data/gfx/fonts/default.ttf", 45));
    fpsText.setXPosition(viewSize.x - 100);
    fpsText.setColor(Color(0, 0, 0));
    
        //Engines
    PhysicsEngine physicsEngine;
    
    SoundEngine soundEngine;
    soundEngine.setManager(soundBufferManager);
    soundEngine.setVolume(m_configuration->getSoundVolume());
    
        //Arena
    Arena arena = Arena::loadFromXML(m_arenaPath, "data/cfg/arenas.xml", textureManager);
    arena.applyToPhysics(physicsEngine);
    arena.subscribeObjects(physicsEngine);
    
        //Players
    std::list<Human> humansList;
    std::list<AI> aisList;
    
    std::vector<Player*> players;
    
    for (unsigned int i = 0; i < m_playersDataList.size(); i++)
    {
        Player *player;
        
        int playerType = m_playersDataList[i].first;
        std::string playerName = m_playersDataList[i].second;
        
        if (playerType == 0) //Human
        {
            Human human = Human::loadFromXML(playerName, "data/cfg/characters.xml");
            
            PlayerKeys keys;
            if (m_configuration->getPlayerKeys(humansList.size(), keys))
                human.setKeys(keys);
            
            humansList.push_back(human);
            player = &humansList.back();
        }
        else if (playerType == 1) //AI
        {
            AI ai = AI::loadFromXML(playerName, "data/cfg/characters.xml");
            
            aisList.push_back(ai);
            player = &aisList.back();
        }
        
        player->setPhysicsEngine(physicsEngine);
        player->setSoundEngine(soundEngine);
        
        player->loadGraphics(textureManager);
        
        Vector playerSpawn(i * 300 + 200, 0);
        arena.getPlayerSpawn(i, playerSpawn);
        
        player->setXPosition(playerSpawn.x);
        player->setYPosition(playerSpawn.y);
        
        players.push_back(player);
        
        //Subscribe to engines
        physicsEngine.addObject(players.back());
        interface.addPlayer(*players.back());
    }
    
    //Camera
    Camera gameCamera(Box(0, 0, arena.getWidth(), arena.getHeight()));
    Camera interfaceCamera(Box(0, 0, viewSize.x, viewSize.y));
    
    //Start screen loop
    Timer time;
    
    Timer endTimer;
    bool finished = false;
    
    float frameTime;
    int fps = 0;
    
    SDL_Event event;
    while (1)
    {
        //Manage time
        frameTime = time.getTime();
        
        if (frameTime > 0) //Frame time could be 0
            fps = 1000 / frameTime;
        
        time.reset();
        
        //Manage events
        m_window->pollEvent(event);
        
        switch(event.type)
        {
            case SDL_QUIT:
                m_gameEngine->exit();
                return;
            break;
            
            case SDL_VIDEORESIZE:
                m_window->resize(event.resize.w, event.resize.h, false);
            break;
            
            case SDL_KEYDOWN:
                if (event.key.keysym.sym == SDLK_k)
                    m_window->setFrameRate(10);
                else if (event.key.keysym.sym == SDLK_l)
                    m_window->setFrameRate(60);
                else if (event.key.keysym.sym == SDLK_m)
                    m_window->setFrameRate(0);
            break;
        }
        
        //End of fight
        if (!finished)
        {
            int alive = 0;
            for (unsigned int i = 0; i < players.size(); i++)
            {
                if (players[i]->getHealth() > 0)
                    alive++;
            }
            
            if (alive <= 1)
            {
                finished = true;
                endTimer.reset();
            }
        }
        
        if (finished && endTimer.getTime() >= 5000)
        {
            m_gameEngine->initMainMenu();
            return;
        }
        
        //Update physics
        physicsEngine.update(frameTime);
        
        //Update sounds
        soundEngine.update();
        
        //Update players
        for (unsigned int i = 0; i < players.size(); i++)
        {
            players[i]->act(frameTime);
            players[i]->update();
        }
        
        interface.update();
        
        std::ostringstream convertFramerate;
        convertFramerate << fps;
        fpsText.setText(convertFramerate.str());
        
        //Display
            //Clear
        m_window->clear();
        
            //Graphic part
        gameCamera.look(viewSize.x, viewSize.y);
        
        arena.draw();
        for (unsigned int i = 0; i < players.size(); i++)
        {
            players[i]->draw();
            players[i]->updateGraphics(frameTime);
        }
        
            //Interface part
        interfaceCamera.look(viewSize.x, viewSize.y);
        
        interface.draw();
        fpsText.draw();
        
            //Render
        m_window->flush();
    }
}
