/*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 "JoyAxisKey.hpp"

#include "Tools/Format.hpp"
#include "Tools/I18n.hpp" ///< _ macro for i18n
#include <sstream>

namespace
{
    constexpr Sint16 AXIS_THRESHOLD_POS = 10923;
    constexpr Sint16 AXIS_THRESHOLD_NEG = -10923;
}

JoyAxisKey::JoyAxisKey() : JoyAxisKey(0, JoyAxisMove::Negative) {}

JoyAxisKey::JoyAxisKey(Uint8 axisID, JoyAxisMove axisMove) :
m_axisID(axisID), m_axisMove(axisMove)
{

}

bool JoyAxisKey::keyPressed(const SDL_Event &event, Uint8 deviceID,
    const std::map<Uint8, AxisState> &previousAxisStates) const
{
    if (event.type == SDL_JOYAXISMOTION && deviceID == event.jaxis.which &&
        m_axisID == event.jaxis.axis)
    {
        AxisState previousState = AxisState::Centered;
        const std::map<Uint8, AxisState>::const_iterator it =
            previousAxisStates.find(m_axisID);
        if (it != previousAxisStates.end())
            previousState = it->second;

        const AxisState newState =
            JoyAxisKey::axisStateFromSDLCode(event.jaxis.value);

        if (previousState == newState)
            return false;
        else
            return ((newState == AxisState::Negative &&
                     m_axisMove == JoyAxisMove::Negative) ||
                    (newState == AxisState::Positive &&
                     m_axisMove == JoyAxisMove::Positive));
    }

    return false;
}

bool JoyAxisKey::keyReleased(const SDL_Event &event, Uint8 deviceID,
    const std::map<Uint8, AxisState> &previousAxisStates) const
{
    if (event.type == SDL_JOYAXISMOTION && deviceID == event.jaxis.which &&
        m_axisID == event.jaxis.axis)
    {
        AxisState previousState = AxisState::Centered;
        const std::map<Uint8, AxisState>::const_iterator it =
            previousAxisStates.find(m_axisID);
        if (it != previousAxisStates.end())
            previousState = it->second;

        const AxisState newState =
            JoyAxisKey::axisStateFromSDLCode(event.jaxis.value);

        return ((previousState == AxisState::Negative &&
                 m_axisMove == JoyAxisMove::Negative) ||
                (previousState == AxisState::Positive &&
                 m_axisMove == JoyAxisMove::Positive)) &&
               (newState != previousState);
    }

    return false;
}

std::string JoyAxisKey::getName() const
{
    const int axisNumber = m_axisID + 1;
    if (m_axisMove == JoyAxisMove::Negative)
        return _f(KeyJoyAxisNegative, std::make_pair("axis_id", axisNumber));

    return _f(KeyJoyAxisPositive, std::make_pair("axis_id", axisNumber));
}

std::string JoyAxisKey::getKeyCode() const
{
    std::ostringstream code;
    code << "ja" << static_cast<short>(m_axisID)
                 << axisMoveStringCode(m_axisMove);
    return code.str();
}

AxisState JoyAxisKey::axisStateFromSDLCode(Sint16 sdlValue)
{
    if (sdlValue >= AXIS_THRESHOLD_POS)
        return AxisState::Positive;
    else if (sdlValue <= AXIS_THRESHOLD_NEG)
        return AxisState::Negative;

    return AxisState::Centered;
}

JoyAxisMove JoyAxisKey::axisMoveFromStringCode(const std::string &stringCode)
{
    return (stringCode == "n") ? JoyAxisMove::Negative : JoyAxisMove::Positive;
}

std::string JoyAxisKey::axisMoveStringCode(const JoyAxisMove &code)
{
    return (code == JoyAxisMove::Negative) ? "n" : "p";
}
