/*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_SCENE
#define DEF_CLIENT_FIGHT_SCENE

#include "Player/Control/Local/AIController.hpp"
#include "Player/Control/Local/HumanController.hpp"
#include "Player/Control/Remote/NetClientController.hpp"
#include "Graphics/Drawable/ArenaDrawer.hpp"
#include "Graphics/Drawable/PlayerDrawer.hpp"
#include "Graphics/Drawable/WeaponEtherDrawer.hpp"
#include "FightCameraHandler.hpp"
#include "FightScene.hpp"

class TextureManager;
class SoundInterface;
class PhysicsObjectStatus;
class DamageStatus;
class EtherStatus;
struct Vector;

class ClientFightScene : public FightScene, public PlayerCallbackReceiver
{
    public:
        struct DisplayOptions
        {
            DisplayOptions(FightCameraHandler::CameraMode mode,
                           bool shake, bool hitboxes) :
            cameraMode(mode), cameraShake(shake), showHitboxes(hitboxes) {}

            FightCameraHandler::CameraMode cameraMode;
            bool cameraShake;
            bool showHitboxes;
        };

        ClientFightScene(TextureManager &textureManager,
                         Ambient *ambientPlayer,
                         SoundInterface *soundInterface,
                         const DisplayOptions &displayOptions);

        void uninitialize();
        void reset() override;

        void setArena(const std::string &arenaName) override;

        /// Callback when a player was hit, useful to trigger a camera shake
        void playerHitTriggered() override;
        void playerWasHit(float, HitDirection, const Player*) override;

        void addAIPlayer(const std::string &name);
        void addHumanPlayer(const std::string &name, int deviceID,
                            const PlayerKeys &keys);

        ClientPlayerInterface *addNetClientPlayer(
            const std::string &name,
            PlayerActionSender *actionSender,
            int deviceID, const PlayerKeys &keys,
            const ClientInputState &state);

        void clearPlayers();

        /// For human-controlled players
        void processKeyEvent(const SDL_Event &event);
        void updateKeyState(const SDL_Event &event);

        void draw();

        /// Apply arena updates received from a server
        void applyPlatformStatus(const std::vector<PhysicsObjectStatus> &status);

        /// Apply weapon updates received from a server
        void applyWeaponEtherStatus(const EtherStatus &status);

        /// Apply damage dealer updates received from a server
        void applyDamageStatus(const std::vector<DamageStatus> &status,
                               const Timer::TimePoint &clientTime);

        /// Setup the active camera projection to look at the fight scene
        /// and update the camera projection based on the players' position
        void lookCamera(const Vector &viewSize, float frameTime);

        /// Return the currently displayed subbox of the world
        const Box &getCameraView() const;

    private:
        void updatePlayerControllers() override;

        /// Add a player drawer for the added player and update AIs
        void setupPlayer(Player &player);
        void resetAIs(); ///< Inform AIs about who their enemies are
        void cameraUpdateArena(); ///< Update the camera after an arena change
        void cameraUpdatePlayers(); ///< Update the camera after a player change
        void drawPhysicsBoxes() const;

        TextureManager *m_textureManager;

        FightCameraHandler m_cameraHandler;
        DisplayOptions m_displayOptions;

        std::list<HumanController> m_humansControl;
        std::list<AIController> m_aisControl;
        std::list<NetClientController> m_netControl;

        /// Drawers
        ArenaDrawer m_arenaDrawer;
        std::vector<PlayerDrawer> m_playerDrawers;
        WeaponEtherDrawer m_weaponsDrawer;
};

#endif
