/*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_DAMAGE_DEALER
#define DEF_DAMAGE_DEALER

#include "Engines/Physics/PhysicsObject.hpp" ///< HitDirection
#include "Tools/Timer.hpp"
#include <list>

class Player;

struct Damage
{
    Damage() : strength(0.f), direction(HitDirection::FromLeft),
    source(nullptr), target(nullptr) {}

    Damage(float hitStrength, HitDirection hitDirection,
           const Player &hitSource, Player &hitTarget) :
           strength(hitStrength), direction(hitDirection),
           source(&hitSource), target(&hitTarget) {}

    float strength;
    HitDirection direction;
    const Player *source;
    Player *target;
};

struct TimedDamage
{
    TimedDamage() = default;

    TimedDamage(const Damage &hitDamage, const Timer::TimePoint &hitTime) :
    damage(hitDamage), time(hitTime) {}

    Damage damage;
    Timer::TimePoint time; ///< Time at which the damage will be applied
};

class DamageTracker
{
    public:
        virtual ~DamageTracker() {};
        virtual void push(const Damage &damage) = 0;
};

/// Tracks the damages applied by physics objects
/// to delay them slightly and deal them after the players have acted.
/// Allows mutual hits and draw games.
class DamageDealer : public DamageTracker
{
    public:
        /// Queue a damage to be applied after a short timeout
        void push(const Damage &damage) override;

        /// Queue a timed damage containing the application time directly
        void push(const TimedDamage &damage);

        /// Deals the queued damage that have been registered
        /// for longer than the timeout
        void deal();

        /// Deals all the damage in the queue immediately,
        /// regardless of their registration time
        void deal_queue();

        /// Clears the queue of incoming damages without applying them
        void clear();

        /// Clears all incoming damages involving \p player
        void clear_player(const Player *player);

        /// Return a reference to the damage queue (useful for serialization)
        const std::list<TimedDamage> &getQueue() const;

    private:
        /// Deals the damage on top of the queue
        void pop_damage();

        /// List of dealt damage to be applied and time of damage
        std::list<TimedDamage> m_damageToDeal;
};

#endif
