#include "jinput.h"
#include <SDL2/SDL.h>
#include "jdraw.h"
#include "jfile.h"

namespace input
{
    static const uint8_t *keys = nullptr;
    static uint8_t keypressed = 0;
    static uint8_t keydown = 0;
    static uint8_t btnClicked = 0;
    static int wheel = 0;
    static SDL_GameController *gamepad = NULL;
    static int8_t pad_btn_pressed = SDL_CONTROLLER_BUTTON_INVALID;
    static int8_t pad_btn_down = SDL_CONTROLLER_BUTTON_INVALID;

    void initGamePad()
    {
        int size;
        char *buffer = file::getFileBuffer("gamecontrollerdb.txt", size);
        if (SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(buffer, size), 1) < 0) printf("No s'ha pogut carregar el gamecontrollersdb.txt\n");
        free(buffer);

        const int num_joysticks = SDL_NumJoysticks();
        if (num_joysticks>=1) {
            for (int i=0; i<num_joysticks; ++i) {
                if (SDL_IsGameController(i)) {
                    gamepad = SDL_GameControllerOpen(i);
                    if (SDL_GameControllerGetAttached(gamepad) == SDL_TRUE) {
                        SDL_GameControllerEventState(SDL_ENABLE);
                        return;
                    }
                }
            }
        }
    }

    void init()
    {
        keys = SDL_GetKeyboardState(NULL);
        initGamePad();
    }

    // Determina si la tecla especificada està sent polsada ara mateix
    bool keyDown(const uint8_t key)
    {
        return keys[key];
    }

    // Determina si la tecla especificada ha sigut polsada, pero no tornarà a ser true fins
    bool keyPressed(const uint8_t key)
    {
        return key == keypressed;
    }

    // Determina si hi ha alguna tecla polsada ara mateix
    bool anyKey()
    {
        return keydown != 0;
    }

    // Torna el codi de la tecla que està sent polsada ara mateix
    const uint8_t whichKey()
    {
        return keydown;
    }

    // Torna el codi de la tecla que està sent polsada ara mateix
    const uint8_t getKeyPressed()
    {
        return keypressed;
    }


    // Determina si el botó del pad especificat està sent polsat ara mateix
    bool padBtnDown(const int8_t btn)
    {
        if (!gamepad) return false;
        return SDL_GameControllerGetButton(gamepad, SDL_GameControllerButton(btn)) == 1;
    }

    // Determina si el botó del pad especificat ha sigut polsat, pero no tornarà a ser true fins
    bool padBtnPressed(const int8_t btn)
    {
        return btn == pad_btn_pressed;
    }

    // Determina si hi ha algun botó del pad polsat ara mateix
    bool anyPadBtn()
    {
        return pad_btn_down != SDL_CONTROLLER_BUTTON_INVALID;
    }

    // Torna el codi del botó del pad que està sent polsat ara mateix
    const int8_t whichPadBtn()
    {
        return pad_btn_down;
    }

    // Torna el codi del botó del pad que està sent polsat ara mateix
    const int8_t getPadBtnPressed()
    {
        return pad_btn_pressed;
    }



    // (US INTERN) Actualitza la tecla actualment polsada (keydown) desde jgame
    void updateKey(const uint8_t key)
    {
        keydown = key;
    }

    // (US INTERN) Actualitza la tecla actualment polsada (keypress) desde jgame
    void updateKeypressed(const uint8_t key)
    {
        keypressed = key;
    }

    // (US INTERN) Actualitza el botó del ratolí actualment polsat desde jgame
    void updateClk(const uint8_t btn)
    {
        btnClicked = btn;
    }

    // (US INTERN) Actualitza el valor de la roda del ratolí actual desde jgame
    void updateWheel(const int dy)
    {
        wheel = dy;
    }

    // (US INTERN) Actualitza el botó actualment polsat (keydown) desde jgame
    void updatePadBtn(const int8_t btn)
    {
        pad_btn_down = btn;
    }

    // (US INTERN) Actualitza el botó actualment polsat (keypress) desde jgame
    void updatePadBtnPressed(const int8_t btn)
    {
        pad_btn_pressed = btn;
    }

    // Torna la posició X actual del ratolí
    const int mouseX()
    {
        int x;
        SDL_GetMouseState(&x, NULL);
        return x/draw::getZoom();
    }

    // Torna la posició Y actual del ratolí
    const int mouseY()
    {
        int y;
        SDL_GetMouseState(NULL, &y);
        return y/draw::getZoom();
    }

    // Determina si el botó del ratolí especificat està sent polsada ara mateix
    const bool mouseBtn(const int btn)
    {
        return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(btn));
    }

    // Determina si el botó especificat ha sigut polsat, pero no tornarà a ser true fins
    // que no se solte el botó i se torne a polsar (Equivalent a keypress en tecles).
    const bool mouseClk(const int btn)
    {
        return btnClicked == btn;
    }

    // Obté el valor actual de la rodeta del ratolí
    const int mouseWheel()
    {
        return wheel;
    }
}
