/*Copyright (C) 2010-2023 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 "ServerFightScene.hpp"
#include "Network/Serialization/PhysicsObjectStatus.hpp"
#include "Network/Serialization/EtherStatus.hpp"
#ifdef HNMSERVER_DRAW
    #include "Engines/Resources/TextureManager.hpp"
#endif

#include "Player/Player.hpp"
#include <cassert>

#ifdef HNMSERVER_DRAW
    ServerFightScene::ServerFightScene(TextureManager &textureManager) :
    FightScene(nullptr, nullptr), m_textureManager(&textureManager)
    {
        m_weaponsDrawer.attachTo(m_weapons, textureManager);
    }

    void ServerFightScene::draw()
    {
        m_arenaDrawer.draw();

        for (PlayerDrawer &playerDrawer : m_playerDrawers)
            playerDrawer.draw();

        m_weaponsDrawer.draw();
    }
#else
    ServerFightScene::ServerFightScene() :
    FightScene(nullptr, nullptr) //No audio interfaces
    {

    }
#endif

void ServerFightScene::setArena(const std::string &arenaName)
{
    FightScene::setArena(arenaName);

    #ifdef HNMSERVER_DRAW
        if (m_textureManager != nullptr)
            m_arenaDrawer.attachTo(m_arena, (*m_textureManager));
    #endif
}

ServerPlayerInterface *ServerFightScene::addNetServerPlayer(const std::string &name)
{
    if (Player *netServer = FightScene::addPlayer(name))
    {
        #ifdef HNMSERVER_DRAW
            PlayerDrawer drawer;
            drawer.attachTo((*netServer), (*m_textureManager), true);
            m_playerDrawers.push_back(drawer);
        #endif

        m_netControl.emplace_back();
        m_netControl.back().attach((*netServer));
        return &(m_netControl.back());
    }

    return nullptr;
}

bool ServerFightScene::removePlayer(std::size_t playerIx)
{
    if (playerIx < m_players.size())
    {
        assert(m_players.size() == m_netControl.size());

        #ifdef HNMSERVER_DRAW
            assert(m_players.size() == m_playerDrawers.size());

            m_playerDrawers.erase(std::next(m_playerDrawers.begin(),
                static_cast<std::vector<PlayerDrawer>::difference_type>(playerIx)));
        #endif

        deletePlayer(m_players[playerIx]);

        m_players.erase(std::next(m_players.begin(),
            static_cast<std::vector<Player*>::difference_type>(playerIx)));

        m_netControl.erase(std::next(m_netControl.begin(),
            static_cast<std::list<NetServerController>::difference_type>(playerIx)));

        return true;
    }

    return false;
}

void ServerFightScene::revivePlayers()
{
    for (Player *player : m_players)
    {
        if (player->getState() == StateIndex::KO)
        {
            //Reset, only maintain looking direction and position
            const bool looksLeft = player->looksLeft();
            player->reset(true); //Reset maintaining position
            player->setLooksLeft(looksLeft);
        }
    }
}

void ServerFightScene::updatePlayerControllers()
{
    for (NetServerController &netServer : m_netControl)
        netServer.act();
}

std::vector<PhysicsObjectStatus> ServerFightScene::getPlatformStatus() const
{
    return m_arena.getPlatformStatus();
}

const std::list<TimedDamage> &ServerFightScene::getQueuedDamages() const
{
    return m_damageDealer.getQueue();
}

EtherStatus ServerFightScene::getWeaponEtherStatus() const
{
    return m_weapons.getStatus();
}
