/*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_REFEREE
#define DEF_REFEREE

#include "FightRules.hpp"
#include "FightState.hpp"
#include "Tools/Timer.hpp"
#include <map>
#include <cstdint>

class Player;
class FightScene;

/// A set of callback received to follow the
/// instructions of the fight game referee
class RefereeListener
{
    public:
        virtual ~RefereeListener() = default;

        /// Players should be set in their starting position
        /// and prepare for the fight round to start
        virtual void readyRound(unsigned int roundId) = 0;

        /// The fight starts, players can start moving
        /// from their starting position
        virtual void startRound() = 0;

        /// The round is completed, with a winner (not a draw game)
        virtual void roundOver(std::size_t winnerIx, const Player &winner,
                    std::uint8_t wonRounds /**< Overall number of rounds won
                    in the game by the winner of this round */) = 0;

        /// The round has completed in a draw
        virtual void roundOverDraw() = 0;

        /// The game (set of potentially multiple rounds) is completed,
        /// the winner is the winner of the last reported round
        virtual void gameOver() = 0;
};

class Referee
{
    public:
        explicit Referee(const FightRules &rules = FightRules());

        /// Sets the RefereeRuled instance which will
        /// receive instructions from the referee
        void instruct(RefereeListener *receiver);

        /// Starts refeereeing the game, in practice
        /// readies and starts the first round
        void ready();

        /// Judges the fight scene and potentially emits instructions
        /// to the ruled receiver, e.g., if the round has ended
        void observe(const FightScene &fightScene);

        /// Give a red card to \p playerIx (the player is removed from the game)
        /// The number of players in the fight rules is maintained, so that
        /// it is reverted at the next ready game
        void playerWasErased(std::size_t playerIx);

        /// Change the rules, only works when the game is finished
        /// Useful to reset the rules to normal after the number of player
        /// was reduced as a player disconnected in a networked game
        void changeRules(const FightRules &newRules);

        /// Ask the referee directly for the current state of the game
        const FightState &getFightState() const;

        /// Ask the referee directly for the rules of the game
        const FightRules &getRules() const;

    private:
        FightRules m_rules; ///< Rules of the game (number of rounds, ...)

        /// Current game state: phase and winner statistics
        FightState m_fightState;
        Timer m_watch; ///< The referee's watch, time tracking

        RefereeListener *m_receiver; ///< Receives instructions from the referee
};

#endif
