#include "define_buttons.h"
#include "lang.h"    // for getText
#include "options.h" // for options
#include "param.h"   // for param
#include "section.h" // for name, name_e, options, options_e
#include "text.h"    // for Text
#include "utils.h"   // for OptionsController, Options, Param, ParamGame

// Constructor
DefineButtons::DefineButtons(std::unique_ptr<Text> text)
    : text(std::move(text))
{
    // Copia punteros a los objetos
    input = Input::get();

    // Inicializa variables
    enabled = false;
    x = param.game.width / 2;
    y = param.title.press_start_position;
    indexController = 0;
    indexButton = 0;

    buttons.clear();
    db_button_t button;

    button.label = lang::getText(95);
    button.input = input_fire_left;
    button.button = SDL_CONTROLLER_BUTTON_X;
    buttons.push_back(button);

    button.label = lang::getText(96);
    button.input = input_fire_center;
    button.button = SDL_CONTROLLER_BUTTON_Y;
    buttons.push_back(button);

    button.label = lang::getText(97);
    button.input = input_fire_right;
    button.button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
    buttons.push_back(button);

    button.label = lang::getText(98);
    button.input = input_start;
    button.button = SDL_CONTROLLER_BUTTON_START;
    buttons.push_back(button);

    button.label = lang::getText(99);
    button.input = input_exit;
    button.button = SDL_CONTROLLER_BUTTON_BACK;
    buttons.push_back(button);

    for (int i = 0; i < input->getNumControllers(); ++i)
    {
        controllerNames.push_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.controller[indexController].player_id));
        text->writeCentered(x, y, controllerNames[indexController]);
        text->writeCentered(x, y + 10, buttons[indexButton].label);
    }
}

// Comprueba el botón que se ha pulsado
void DefineButtons::doControllerButtonDown(SDL_ControllerButtonEvent *event)
{
    int i = input->getJoyIndex(event->which);

    // Solo pillamos botones del mando que toca
    if (i != indexController)
    {
        return;
    }

    buttons[indexButton].button = (SDL_GameControllerButton)event->button;
    incIndexButton();
}

// Asigna los botones definidos al input
void DefineButtons::bindButtons()
{
    for (int i = 0; i < (int)buttons.size(); ++i)
    {
        input->bindGameControllerButton(indexController, buttons[i].input, buttons[i].button);
    }
}

// Comprueba las entradas
void DefineButtons::checkInput()
{
    if (enabled)
    {
        SDL_Event event;

        // Comprueba los eventos que hay en la cola
        while (SDL_PollEvent(&event))
        {
            // Evento de salida de la aplicación
            if (event.type == SDL_QUIT)
            {
                section::name = section::NAME_QUIT;
                section::options = section::OPTIONS_QUIT_NORMAL;
                break;
            }

            if (event.type == SDL_CONTROLLERBUTTONDOWN)
            {
                doControllerButtonDown(&event.cbutton);
            }
        }
    }
}

// Habilita el objeto
bool DefineButtons::enable(int index)
{
    if (index < input->getNumControllers())
    {
        enabled = true;
        indexController = index;
        indexButton = 0;
        return true;
    }

    return false;
}

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

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

    // Comprueba si ha finalizado
    if (indexButton == (int)buttons.size())
    {
        // Asigna los botones definidos al input
        bindButtons();

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

        input->allActive(indexController);

        // Reinicia variables
        indexButton = 0;
        indexController = 0;
        enabled = false;
    }
}

// Guarda los cambios en las opciones
void DefineButtons::saveBindingsToOptions()
{
    // Modifica las opciones para colocar los valores asignados
    options.controller[indexController].name = input->getControllerName(indexController);
    for (int j = 0; j < (int)options.controller[indexController].inputs.size(); ++j)
    {
        options.controller[indexController].buttons[j] = input->getControllerBinding(indexController, options.controller[indexController].inputs[j]);
    }
}

// Intercambia los jugadores asignados a los dos primeros mandos
void DefineButtons::swapControllers()
{
    const int temp = options.controller[0].player_id;
    options.controller[0].player_id = options.controller[1].player_id;
    options.controller[1].player_id = temp;
}