/*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_FIGHT_SCENE
#define DEF_FIGHT_SCENE

#include "Engines/Physics/PhysicsWorld.hpp"
#include "Engines/Sound/Ambient.hpp"
#include "DamageDealer.hpp"
#include "Arena/Arena.hpp"
#include "Weapon/WeaponEther.hpp"
#include "VersusController.hpp" ///< FightModeControl
#include "FightRules.hpp"
#include <vector>
#include <string>

class Player;
class SoundInterface;

class FightScene
{
    public:
        FightScene(Ambient *ambient, SoundInterface *soundInterface);
        FightScene(const FightScene &copied) = delete;
        FightScene &operator=(const FightScene &copied) = delete;
        virtual ~FightScene();

        /// Allocates and binds a fight mode controller
        /// (e.g., to keep two players looking at each other in versus mode)
        void addFightModeController(FightRules::Mode mode);

        /// Changes the arena of the fight scene,
        /// maintains players and clears damages/weapons
        virtual void setArena(const std::string &arenaName);

        /// Reset the fight scene to its starting position and
        /// block player movements until start()
        virtual void reset();

        /// Start the fight allowing players to move
        void start();

        void update(float frameTime);

        std::vector<const Player*> getPlayers() const;

        bool isFinished(int *winnerIxDst = nullptr,
                        const Player **winnerDst = nullptr) const;
        enum : int { DrawGame = -1 };

    protected:
        Player *addPlayer(const std::string &characterName);
        void deletePlayer(Player *player);

        /// Clear the players in the fight sene
        void clearPlayersCore();

        /// Clear the fight scene state (players, weapons, arena, damages, ...)
        void uninitializeCore();

        virtual void updatePlayerControllers() = 0;

        /// Fight scene objects
        std::vector<Player*> m_players;
        PhysicsWorld m_physicsWorld;
        Arena m_arena;
        WeaponEther m_weapons;

        /// Damage can be applied immediately to
        /// check for draw games in isFinished()
        mutable DamageDealer m_damageDealer;

        bool m_started; ///< Whether the fight has started

    private:
        void respawnPlayer(Player &player, std::size_t spawnIx);

        Ambient *m_ambient; ///< Ambient arena music
        SoundInterface *m_soundInterface;
        FightModeControl::Controller *m_modeController;
};

#endif
