#include "define_buttons.h"
#include "input.h"    // Para Input, InputAction
#include "lang.h"     // Para getText
#include "options.h"  // Para OptionsController, Options, options
#include "param.h"    // Para Param, param, ParamGame, ParamTitle
#include "resource.h" // Para Resource
#include "text.h"     // Para Text

// Constructor
DefineButtons::DefineButtons()
    : input_(Input::get()),
      text_(Resource::get()->getText("8bithud"))
{
    // Inicializa variables
    x_ = param.game.width / 2;
    y_ = param.title.press_start_position;

    clearButtons();

    for (int i = 0; i < input_->getNumControllers(); ++i)
    {
        controller_names_.emplace_back(input_->getControllerName(i));
    }
}

// Dibuja el objeto en pantalla
void DefineButtons::render()
{
    if (enabled_)
    {
        text_->writeCentered(x_, y_ - 10, lang::getText(100) + std::to_string(options.controllers.at(index_controller_).player_id));
        text_->writeCentered(x_, y_, controller_names_.at(index_controller_));
        text_->writeCentered(x_, y_ + 10, buttons_.at(index_button_).label);
    }
}

// Comprueba el botón que se ha pulsado
void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event)
{
    // Solo pilla botones del mando que toca
    if (input_->getJoyIndex(event.which) != static_cast<int>(index_controller_))
    {
        return;
    }

    const auto button = static_cast<SDL_GamepadButton>(event.button);
    if (checkButtonNotInUse(button))
    {
        buttons_.at(index_button_).button = button;
        incIndexButton();
    }
}

// Asigna los botones definidos al input_
void DefineButtons::bindButtons()
{
    for (const auto &button : buttons_)
    {
        input_->bindGameControllerButton(index_controller_, button.input, button.button);
    }
}

// Comprueba los eventos
void DefineButtons::checkEvents(const SDL_Event &event)
{
    if (enabled_ && event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN)
    {
        doControllerButtonDown(event.gbutton);
    }
}

// Habilita el objeto
bool DefineButtons::enable(int index)
{
    if (index < input_->getNumControllers())
    {
        enabled_ = true;
        index_controller_ = index;
        index_button_ = 0;
        clearButtons();
        return true;
    }

    return false;
}

// Comprueba si está habilitado
bool DefineButtons::isEnabled() const { return enabled_; }

// Incrementa el indice de los botones
void DefineButtons::incIndexButton()
{
    ++index_button_;

    // Comprueba si ha finalizado
    if (index_button_ == buttons_.size())
    {
        // Asigna los botones definidos al input_
        bindButtons();

        // Guarda los cambios en las opciones
        saveBindingsToOptions();

        // Deshabilita
        enabled_ = false;
    }
}

// Guarda los cambios en las opciones
void DefineButtons::saveBindingsToOptions()
{
    // Modifica las opciones para colocar los valores asignados
    auto &controller = options.controllers.at(index_controller_);
    controller.name = input_->getControllerName(index_controller_);
    for (size_t j = 0; j < controller.inputs.size(); ++j)
    {
        controller.buttons.at(j) = input_->getControllerBinding(index_controller_, controller.inputs.at(j));
    }
}

// Comprueba que un botón no esté ya asignado
bool DefineButtons::checkButtonNotInUse(SDL_GamepadButton button)
{
    for (const auto &b : buttons_)
    {
        if (b.button == button)
        {
            return false;
        }
    }
    return true;
}

// Limpia la asignación de botones
void DefineButtons::clearButtons()
{
    buttons_.clear();
    buttons_.emplace_back(lang::getText(95), InputAction::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID);
    buttons_.emplace_back(lang::getText(96), InputAction::FIRE_CENTER, SDL_GAMEPAD_BUTTON_INVALID);
    buttons_.emplace_back(lang::getText(97), InputAction::FIRE_RIGHT, SDL_GAMEPAD_BUTTON_INVALID);
    buttons_.emplace_back(lang::getText(98), InputAction::START, SDL_GAMEPAD_BUTTON_INVALID);
    buttons_.emplace_back(lang::getText(99), InputAction::SERVICE, SDL_GAMEPAD_BUTTON_INVALID);
}