/*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 "MultipleKeyBinder.hpp"
#include "Engines/Resources/TextureManager.hpp"
#include "Engines/Sound/SoundEngine.hpp"
#include "Player/PlayerKeys.hpp"

#include "GUI/Widget/Layout.hpp"
#include "GUI/Widget/TextButton.hpp"
#include "Tools/ScaledPixel.hpp"
#include "Tools/I18n.hpp" ///< _ macro for i18n

MultipleKeyBinder::MultipleKeyBinder() : Tab(), m_deviceID(DEVICE_KEYBOARD) {}

MultipleKeyBinder::MultipleKeyBinder(int deviceID,
                                     const PlayerKeys &initialKeys,
                                     TextureManager &manager,
                                     Font &labelFont,
                                     SoundEngine &soundEngine,
                                     float viewWidth) :
Tab(ScaledPixel{viewWidth}(360.f),
    ScaledPixel{viewWidth}(210.f),
    Color(40, 83, 141)),
m_deviceID(deviceID)
{
    const ScaledPixel sp(viewWidth);

    Sprite chooser_default(manager.getTexture("gfx/ui/ui.png"),
                           Box(0.f, 0.f, 240.f / 512.f, 60.f / 512.f)),
    chooser_hover(manager.getTexture("gfx/ui/ui.png"),
                  Box(0.f, 64.f / 512.f, 240.f / 512.f, 60.f / 512.f));

    chooser_default.setScale(sp(.75f, false), sp(.4f, false));
    chooser_hover.setScale(sp(.75f, false), sp(.4f, false));

    //Labels
    Text labelPunch(_(OptionsControlsPunch), labelFont);
    Text labelKick(_(OptionsControlsKick), labelFont);
    Text labelThrow(_(OptionsControlsThrow), labelFont);
    Text labelJump(_(OptionsControlsJump), labelFont);
    Text labelMoveLeft(_(OptionsControlsMoveLeft), labelFont);
    Text labelMoveRight(_(OptionsControlsMoveRight), labelFont);
    Text labelCrouch(_(OptionsControlsCrouch), labelFont);

    const float labelWidth =
        Layout::largest(labelPunch, labelKick, labelThrow, labelJump,
                        labelMoveLeft, labelMoveRight, labelCrouch) + sp(20.f);

    //Key binders
    const float xBase = (Tab::getWidth() - labelWidth -
        chooser_default.getWidth() * chooser_default.getXScale()) / 2.f;
    const float yBase = sp(12.f);
    const float spacing =
        chooser_default.getHeight() * chooser_default.getYScale() + sp(3.f);

    m_punch =
        KeyLabel(std::move(labelPunch),
                 KeyBinder(initialKeys.getPunchKey(), labelFont),
                 xBase, labelWidth, yBase, chooser_default,
                 chooser_hover, soundEngine, "audio/ui/menuFocus.ogg",
                 "audio/ui/menuClick.ogg");

    m_kick =
        KeyLabel(std::move(labelKick),
                 KeyBinder(initialKeys.getKickKey(), labelFont),
                 xBase, labelWidth, yBase + spacing, chooser_default,
                 chooser_hover, soundEngine, "audio/ui/menuFocus.ogg",
                 "audio/ui/menuClick.ogg");

    m_throwWeapon =
        KeyLabel(std::move(labelThrow),
                 KeyBinder(initialKeys.getThrowWeaponKey(), labelFont),
                 xBase, labelWidth, yBase + spacing * 2.f, chooser_default,
                 chooser_hover, soundEngine, "audio/ui/menuFocus.ogg",
                 "audio/ui/menuClick.ogg");

    m_jump =
        KeyLabel(std::move(labelJump),
                 KeyBinder(initialKeys.getJumpKey(), labelFont),
                 xBase, labelWidth, yBase + spacing * 3.f, chooser_default,
                 chooser_hover, soundEngine, "audio/ui/menuFocus.ogg",
                 "audio/ui/menuClick.ogg");

    m_moveLeft =
        KeyLabel(std::move(labelMoveLeft),
                 KeyBinder(initialKeys.getMoveLeftKey(), labelFont),
                 xBase, labelWidth, yBase + spacing * 4.f, chooser_default,
                 chooser_hover, soundEngine, "audio/ui/menuFocus.ogg",
                 "audio/ui/menuClick.ogg");

    m_moveRight =
        KeyLabel(std::move(labelMoveRight),
                 KeyBinder(initialKeys.getMoveRightKey(), labelFont),
                 xBase, labelWidth, yBase + spacing * 5.f, chooser_default,
                 chooser_hover, soundEngine, "audio/ui/menuFocus.ogg",
                 "audio/ui/menuClick.ogg");

    m_crouch =
        KeyLabel(std::move(labelCrouch),
                 KeyBinder(initialKeys.getCrouchKey(), labelFont),
                 xBase, labelWidth, yBase + spacing * 6.f, chooser_default,
                 chooser_hover, soundEngine, "audio/ui/menuFocus.ogg",
                 "audio/ui/menuClick.ogg");
}

void MultipleKeyBinder::draw()
{
    //Update matrix
    Drawable::pushMatrix();
    Drawable::updateMatrix();

    m_background.draw();

    //Draw binders
    m_punch.draw();
    m_kick.draw();
    m_throwWeapon.draw();
    m_jump.draw();
    m_moveLeft.draw();
    m_moveRight.draw();
    m_crouch.draw();

    Drawable::popMatrix();
}

bool MultipleKeyBinder::mouseRelease(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);

    m_punch.binder.mouseRelease(localMouse);
    m_kick.binder.mouseRelease(localMouse);
    m_throwWeapon.binder.mouseRelease(localMouse);
    m_jump.binder.mouseRelease(localMouse);
    m_moveLeft.binder.mouseRelease(localMouse);
    m_moveRight.binder.mouseRelease(localMouse);
    m_crouch.binder.mouseRelease(localMouse);

    return Widget::contains(localMouse);
}

bool MultipleKeyBinder::mouseClick(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);
    return Widget::contains(localMouse);
}

bool MultipleKeyBinder::mouseMove(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);
    return Widget::contains(localMouse);
}

void MultipleKeyBinder::keyDown(const Key &key, int deviceID)
{
    if ((key.isFromKeyboard() && m_deviceID == DEVICE_KEYBOARD) ||
        (key.isFromJoystick() && m_deviceID == deviceID))
    {
        m_punch.binder.keyDown(key);
        m_kick.binder.keyDown(key);
        m_throwWeapon.binder.keyDown(key);
        m_jump.binder.keyDown(key);
        m_moveLeft.binder.keyDown(key);
        m_moveRight.binder.keyDown(key);
        m_crouch.binder.keyDown(key);
    }
}

void MultipleKeyBinder::setFocus(bool focused)
{
    Widget::setFocus(focused);

    if (!focused)
    {
        m_punch.binder.setFocus(false);
        m_kick.binder.setFocus(false);
        m_throwWeapon.binder.setFocus(false);
        m_jump.binder.setFocus(false);
        m_moveLeft.binder.setFocus(false);
        m_moveRight.binder.setFocus(false);
        m_crouch.binder.setFocus(false);
    }
}

void MultipleKeyBinder::resetKeys(const PlayerKeys &keys)
{
    m_punch.binder.setKey(keys.getPunchKey());
    m_kick.binder.setKey(keys.getKickKey());
    m_throwWeapon.binder.setKey(keys.getThrowWeaponKey());
    m_jump.binder.setKey(keys.getJumpKey());
    m_moveLeft.binder.setKey(keys.getMoveLeftKey());
    m_moveRight.binder.setKey(keys.getMoveRightKey());
    m_crouch.binder.setKey(keys.getCrouchKey());
}

PlayerKeys MultipleKeyBinder::getKeys() const
{
    return PlayerKeys(m_punch.binder.getKey(),
                      m_kick.binder.getKey(),
                      m_throwWeapon.binder.getKey(),
                      m_jump.binder.getKey(),
                      m_moveLeft.binder.getKey(),
                      m_moveRight.binder.getKey(),
                      m_crouch.binder.getKey());
}
