/*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/>.
*/

#ifndef DEF_CLIENT_FIGHT_CONTROLLER
#define DEF_CLIENT_FIGHT_CONTROLLER

#include "Fight/ClientFightScene.hpp"
#include "Fight/FightRules.hpp" ///< FightRules::Mode
#include "Network/Serialization/PeerData.hpp" ///< PeerData and PeerRole
#include "Tools/Timer.hpp"
#include <vector>
#include <string>
#include <cstddef>

class JoystickManager;
class TextureManager;
class AmbientPlayer;
class SoundEngine;

class PlayerStatus;
class PhysicsObjectStatus;
class DamageStatus;
class EtherStatus;
class PlayerActionSender;
class FightInterface;
class Configuration;

/// Stores the player data of each currently
/// connected player known by the client
struct ClientPlayerData
{
    ClientPlayerData(ClientPlayerInterface &controlInterface,
                     const PeerData &peerData) :
    control(&controlInterface), peer(peerData) {}

    ClientPlayerInterface *control;
    PeerData peer;
};

/// Handles a fight shown by a client, with a fight scene.
/// Receives updates from the server and sends player actions
/// if the fight is not spectated by the client
class ClientFightController
{
    public:
        ClientFightController(PlayerActionSender &actionSender,
                              JoystickManager &joystickManager,
                              TextureManager &textureManager,
                              AmbientPlayer &ambientPlayer,
                              SoundEngine &soundEngine,
                              FightInterface &fightInterface,
                              const ClientFightScene::DisplayOptions &options,
                              const Configuration &configuration);

        void initialize(); ///< Start the fight scene
        void uninitialize(); ///< Reset the fight scene after a disconnection

        void setFightMode(FightRules::Mode mode);
        bool setArena(const std::string &arena);
        bool setPlayers(const std::vector<PeerData> &players,
                        const PeerRole &peerRole);

        /// Apply a fight scene status received from the server.
        /// Update the players, platforms, damage dealer, and weapons with,
        /// respectively, \p players, \p platforms, \p damages, and \p weapons.
        /// Then push the simulation forward by \p leapDuration,
        /// to compensate for network jitter
        void applyStatus(const Timer::TimePoint &clientTime,
                         const Timer::duration_uint64_us &leapDuration,
                         const std::vector<PlayerStatus> &players,
                         const std::vector<PhysicsObjectStatus> &platforms,
                         const std::vector<DamageStatus> &damages,
                         const EtherStatus &weapons);

        void keyEvent(const SDL_Event &event);
        void update(float frameTime);
        void draw(float frameTime, const Vector &viewSize);

        const Box &getCameraView() const;

        bool getPeerData(std::size_t playerIx, PeerData &dst) const;
        std::vector<const Player*> getPlayers() const;

    private:
        /// Returns whether \p players differs from the known list
        /// of player peer data in m_playersData
        bool playersHaveChanged(const std::vector<PeerData> &players) const;

        /// Outputs the current set of input device/keys
        /// for the local client player
        void getActiveKeys(int &deviceID, PlayerKeys &keys) const;

        ClientFightScene m_fightScene;
        std::vector<ClientPlayerData> m_playersData;

        JoystickManager *m_joystickManager;
        TextureManager *m_textureManager;

        PlayerActionSender *m_playerActionSender;
        FightInterface *m_fightInterface;

        const Configuration *m_configuration;

        PeerRole m_currentRole;
        std::string m_currentArena;
        const std::vector<std::string> m_validArenas, m_validCharacters;
};

#endif
