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

#include "DamageDealer.hpp"
#include "Player/Player.hpp"

namespace
{
    /// Functor to find any timed damage involving a specific player
    struct FindPlayerDamage
    {
        explicit FindPlayerDamage(const Player *involvedPlayer) :
        player(involvedPlayer) {}

        bool operator() (const TimedDamage &damage) const
        {
            return (damage.damage.source == player ||
                    damage.damage.target == player);
        }

        const Player *player;
    };
}

void DamageDealer::push(const Damage &damage)
{
    //Delay between the damage pushing and its dealing
    constexpr std::chrono::milliseconds delay(10);

    if (damage.source != nullptr && damage.target != nullptr)
        m_damageToDeal.emplace_back(damage, Timer::getTime() + delay);
}

void DamageDealer::push(const TimedDamage &damage)
{
    if (damage.damage.source != nullptr && damage.damage.target != nullptr)
        m_damageToDeal.push_back(damage);
}

void DamageDealer::pop_damage()
{
    //Assumes m_damageToDeal is not empty
    const Damage &damage = m_damageToDeal.front().damage;
    damage.target->takeAHit(damage.strength, damage.direction, damage.source);

    m_damageToDeal.pop_front();
}

void DamageDealer::deal()
{
    while (!m_damageToDeal.empty() &&
           Timer::getTime() > m_damageToDeal.front().time)
        pop_damage();
}

void DamageDealer::deal_queue()
{
    while (!m_damageToDeal.empty())
        pop_damage();
}

void DamageDealer::clear()
{
    m_damageToDeal.clear();
}

void DamageDealer::clear_player(const Player *player)
{
    m_damageToDeal.remove_if(FindPlayerDamage(player));
}

const std::list<TimedDamage> &DamageDealer::getQueue() const
{
    return m_damageToDeal;
}
