#include "input.h"
#include <GLFW/glfw3.h>
#include <window.h>
#include <cstring>

Input::Input()
{
    this->gamepads = new control::Gamepad*[GLFW_JOYSTICK_LAST];
    this->gamepadsConnected = new uint8_t[GLFW_JOYSTICK_LAST];

    for(uint32_t i = 0; i < GLFW_JOYSTICK_LAST; i++) {
        this->gamepads[i] = new control::Gamepad(i);
    }

    this->buttonsState = new uint8_t[GLFW_KEY_LAST + 1];
    this->oldButtonsState = new uint8_t[GLFW_KEY_LAST + 1];

    memset(this->buttonsState, 0, GLFW_KEY_LAST + 1);
    memset(this->oldButtonsState, 0, GLFW_KEY_LAST + 1);

    memset(this->controlState, 0, 2);
    memset(this->oldControlState, 0, 2);
}

Input::~Input()
{
    for(uint32_t i = 0; i < GLFW_JOYSTICK_LAST; i++) {
        delete this->gamepads[i];
    }
    delete [] this->gamepads;
    delete [] this->gamepadsConnected;
    delete [] this->buttonsState;
    delete [] this->oldButtonsState;
}

void Input::Update()
{
    memcpy(this->oldButtonsState, this->buttonsState, GLFW_KEY_LAST + 1);
    memcpy(this->oldControlState, this->controlState, 2);
    memset(this->controlState, 0, 2);

    for(uint32_t i = 0; i < GLFW_JOYSTICK_LAST; i++) {

        this->gamepadsConnected[i] = glfwJoystickPresent(i);

        if(this->gamepadsConnected[i]) {
            this->gamepads[i]->Update();
        }
    }

    GLFWwindow *handler = window::getHandler();

    for (int i = GLFW_KEY_SPACE; i < GLFW_KEY_LAST; i++) {
        this->buttonsState[i] = glfwGetKey(handler, i);
    }

    for (int i = 0; i < GLFW_MOUSE_BUTTON_LAST; i++) {
        this->buttonsState[i] = glfwGetMouseButton(handler, i);
    }

    int keyboardButtons[2] = {GLFW_KEY_ESCAPE, GLFW_KEY_ESCAPE};

    int gamepagButtons[2] = {GLFW_GAMEPAD_BUTTON_START, GLFW_GAMEPAD_BUTTON_CIRCLE};

    for (int i = 0; i < 2; i++) {
        if (this->buttonsState[keyboardButtons[i]]) {
            this->controlState[i] = 1;
        }
    }

    for(uint32_t g = 0; g < GLFW_JOYSTICK_LAST; g++) {

        if (this->gamepadsConnected[g]) {

            for (int i = 0; i < 2; i++) {
                if (this->gamepads[g]->IsButtonPressed(gamepagButtons[i])) {
                    this->controlState[i] = 1;
                }
            }
        }
    }

    glfwGetCursorPos(handler, &this->cursor.x, &this->cursor.y);
}

bool Input::IsGamepadPresent(uint32_t number) const noexcept
{
    if (number >= GLFW_JOYSTICK_LAST) {
        return false;
    }

    return this->gamepadsConnected[number];
}

const control::Gamepad *Input::GetGamepad(uint32_t number) const noexcept
{
    if (!this->IsGamepadPresent(number)) {
        return nullptr;
    }

    return this->gamepads[number];
}

bool Input::IsControlPressed(uint32_t button) const noexcept
{
    if (button >= 7) {
        return false;
    }

    return this->controlState[button];
}

bool Input::IsControlJustPressed(uint32_t button) const noexcept
{
    if (button >= 7) {
        return false;
    }

    return this->controlState[button] && !this->oldControlState[button];
}

bool Input::IsButtonPressed(uint32_t button) const noexcept
{
    return this->buttonsState[button];
}

bool Input::IsButtonJustPressed(uint32_t button) const noexcept
{
    return this->buttonsState[button] && !this->oldButtonsState[button];
}

bool Input::IsButtonJustReleased(uint32_t button) const noexcept
{
    return !this->buttonsState[button] && this->oldButtonsState[button];
}

