/*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 "Attack.hpp"
#include "Player.hpp"

namespace
{
    bool LAG_MITIGATION = false;
}

namespace AttackLag
{
    void enableLagMitigation()
    {
        LAG_MITIGATION = true;
    }

    void disableLagMitigation()
    {
        LAG_MITIGATION = false;
    }
}

Attack::Attack() : m_player(nullptr), m_furthestTime(0.f)
{

}

void Attack::update(float frameTime)
{
    m_animation.goForward(frameTime / 1000.f);
    const float updatedTime = m_animation.getCurrentTime();

    const float timeStep = (updatedTime >= m_furthestTime)
        ? updatedTime - m_furthestTime
        : m_animation.getDuration() - m_furthestTime + updatedTime;

    if (m_player != nullptr &&
        (!LAG_MITIGATION || timeStep < m_animation.getDuration() / 4.f))
    {
        for (const HitBox &hitBox : m_hitBoxes)
        {
            //Time reached
            if (m_furthestTime <= hitBox.time && hitBox.time < updatedTime)
                m_player->hit(hitBox); //Hit Callback
        }

        playSoundEffects(m_furthestTime, updatedTime);
        m_furthestTime = updatedTime;
    }

    //Attack is ready
    if (m_animation.atEndedState())
        reset();
}

void Attack::forceTime(float time)
{
    m_animation.forceTime(time);
}

void Attack::reset()
{
    m_animation.reset();
    m_furthestTime = 0.f;
}

bool Attack::ready()
{
    return m_animation.atInitialState();
}

void Attack::setPlayer(Player &player)
{
    m_player = &player;
}

void Attack::addHitBox(const HitBox &hitBox)
{
    m_hitBoxes.push_back(hitBox);
}

void Attack::scaleHitBoxes(float scale)
{
    for (HitBox &hitBox : m_hitBoxes)
    {
        hitBox.box.top *= scale;
        hitBox.box.left *= scale;
        hitBox.box.width *= scale;
        hitBox.box.height *= scale;
    }
}

void Attack::addSoundEffect(float time, const std::string &soundEffect)
{
    m_soundEffects.push_back( std::make_pair(time, soundEffect) );
}

void Attack::playSoundEffects(float timeBegin, float timeUpdated)
{
    if (m_player == nullptr)
        return;

    std::vector< std::pair<float, std::string> >::const_iterator it;
    for (it = m_soundEffects.begin(); it != m_soundEffects.end(); ++it)
    {
        //Time reached
        if (timeBegin <= it->first && it->first < timeUpdated)
            m_player->playSoundEffect(it->second); //Callback
    }
}

void Attack::setAnimation(const CallbackAnimation &animation)
{
    m_animation = animation;
}

const CallbackAnimation &Attack::getAnimation() const
{
    return m_animation;
}

float Attack::getCurrentTime() const
{
    return m_animation.getCurrentTime();
}

std::vector<HitBox> Attack::getHitBoxes() const
{
    return m_hitBoxes;
}
