#include "input/Buttons.h"

Buttons::Axis::Axis()
    : less(0.0f), greater(0.0f), lessButton(nullptr), greaterButton(nullptr) {
}

Buttons::Buttons()
    : lastMouseX(0), lastMouseY(0), mouseX(0), mouseY(0), activeController(-1),
      gamepadToButton(nullptr) {
}

void Buttons::add(Button& button) {
    buttons.add(button.key, &button);
}

void Buttons::addMouse(Button& button) {
    mouseButtons.add(button.key, &button);
}

void Buttons::mapGamepadButton(Button& button, int mapping) {
    gamepadToButton[mapping] = &button;
}

void Buttons::mapGamepadAxis(Button& button, float value, int index) {
    if(value > 0.0f) {
        gamepadAxisToButton[index].greater = value;
        gamepadAxisToButton[index].greaterButton = &button;
    } else {
        gamepadAxisToButton[index].less = value;
        gamepadAxisToButton[index].lessButton = &button;
    }
}

void Buttons::tick() {
    if(searchForGamepad()) {
        checkGamepad();
    }
    for(auto& e : buttons) {
        e.value->tick();
    }
    for(auto& e : mouseButtons) {
        e.value->tick();
    }
    lastMouseX = mouseX;
    lastMouseY = mouseY;
}

double Buttons::getLastMouseX() const {
    return lastMouseX;
}

double Buttons::getLastMouseY() const {
    return lastMouseY;
}

double Buttons::getMouseX() const {
    return mouseX;
}

double Buttons::getMouseY() const {
    return mouseY;
}

void Buttons::onButton(HashMap<int, Button*>& map, int key, int action) {
    Button** b = map.search(key);
    if(b != nullptr) {
        if(action == GLFW_RELEASE) {
            (*b)->keyboardUp++;
        } else if(action == GLFW_PRESS) {
            (*b)->keyboardDown++;
        }
    }
}

void Buttons::onKey(int key, int, int action, int) {
    onButton(buttons, key, action);
}

void Buttons::onMouse(int button, int action, int) {
    onButton(mouseButtons, button, action);
}

void Buttons::onMouseMove(double x, double y) {
    mouseX = x;
    mouseY = y;
}

bool Buttons::searchForGamepad() {
    if(activeController != -1) {
        return true;
    }
    for(int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; i++) {
        if(glfwJoystickIsGamepad(i)) {
            activeController = i;
            return true;
        }
    }
    return false;
}

void Buttons::checkGamepad() {
    GLFWgamepadstate state;
    if(!glfwGetGamepadState(activeController, &state)) {
        return;
    }
    for(int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) {
        if(gamepadToButton[i] != nullptr) {
            gamepadToButton[i]->controllerDown = state.buttons[i];
        }
    }
    for(int i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) {
        if(gamepadAxisToButton[i].greaterButton != nullptr) {
            gamepadAxisToButton[i].greaterButton->controllerDown =
                (state.axes[i] > gamepadAxisToButton[i].greater);
        }
        if(gamepadAxisToButton[i].lessButton != nullptr) {
            gamepadAxisToButton[i].lessButton->controllerDown =
                (state.axes[i] < gamepadAxisToButton[i].less);
        }
    }
}