#include "Input.h"


// Constructor
Input::Input()
        : m_x(0), m_y(0), m_xRel(0), m_yRel(0),
          m_finished(false), m_relativeMouse(false), m_window(0), m_windowHalfHeight(0), m_windowHalfWidth(0) {
    // Initialisation du tableau m_keys[]
    for (int i(0); i < SDL_NUM_SCANCODES; i++)
        m_keys[i] = false;

    // Initialisation du tableau m_mouseKeys[]
    for (int i(0); i < 8; i++)
        m_mouseKeys[i] = false;
}

// Destructor
Input::~Input() {}


// Methods
void Input::updateEvents() {
    // Reset relative coordinates
    m_xRel = 0;
    m_yRel = 0;

    // Clear instant keys
    m_instantKeys.clear();

    // Event loop
    while (SDL_PollEvent(&m_event)) {
        if (catchKeyBoardEvents(m_event))
            continue;
        else if (catchMouseEvents(m_event))
            continue;
        else
            catchWindowEvents(m_event);
    }

    // Keeping mouse in window
    if (m_relativeMouse)
        SDL_WarpMouseInWindow(m_window, m_windowHalfWidth, m_windowHalfHeight);
}

bool Input::catchKeyBoardEvents(const SDL_Event &event) {
    switch (event.type) {
        case SDL_KEYDOWN:
            m_keys[event.key.keysym.scancode] = true;
            m_instantKeys.insert(event.key.keysym.scancode);
            return true;
        case SDL_KEYUP:
            m_keys[event.key.keysym.scancode] = false;
            return true;
        default:
            return false;
    }
}

bool Input::catchMouseEvents(const SDL_Event &event) {
    switch (event.type) {
        case SDL_MOUSEBUTTONDOWN:
            m_mouseKeys[event.button.button] = true;
            return true;
        case SDL_MOUSEBUTTONUP:
            m_mouseKeys[event.button.button] = false;
            return true;
        case SDL_MOUSEMOTION:
            if (m_relativeMouse) {
                m_xRel = event.motion.x - m_windowHalfWidth;
                m_yRel = event.motion.y - m_windowHalfHeight;
            } else {
                m_x = event.motion.x;
                m_y = event.motion.y;
                m_xRel = event.motion.xrel;
                m_yRel = event.motion.yrel;
            }
            return true;
        default:
            return false;
    }
}

bool Input::catchWindowEvents(const SDL_Event &event) {
    switch (event.type) {
        case SDL_WINDOWEVENT:
            if (event.window.event == SDL_WINDOWEVENT_CLOSE)
                m_finished = true;
            return true;
        default:
            return false;
    }
}

bool Input::isFinished() const {
    return m_finished;
}


void Input::showCursor(bool flag) const {
    if (flag)
        SDL_ShowCursor(SDL_ENABLE);
    else
        SDL_ShowCursor(SDL_DISABLE);
}


void Input::capPtr(bool flag) {
    m_relativeMouse = flag;
}


// Getters
bool Input::getKey(const SDL_Scancode key) const {
    return m_keys[key];
}

bool Input::getInstantKey(const SDL_Scancode key) const {
    return m_instantKeys.find(key) != m_instantKeys.end();
}

bool Input::getMouseKey(const Uint8 key) const {
    return m_mouseKeys[key];
}


bool Input::isMouseMoving() const {
    return !(m_xRel == 0 && m_yRel == 0);
}


// Getters upon cursor position
int Input::getX() const {
    return m_x;
}

int Input::getY() const {
    return m_y;
}

int Input::getXFromCenter() {
    return m_x - m_windowHalfWidth;
}

int Input::getYFromCenter() {
    return m_y - m_windowHalfHeight;
}

int Input::getXRel() const {
    return m_xRel;
}

int Input::getYRel() const {
    return m_yRel;
}

void Input::setWindow(SDL_Window *activWindow) {
    // Direct relation
    m_window = activWindow;

    // Middle computation
    SDL_GetWindowSize(activWindow, &m_windowHalfWidth, &m_windowHalfHeight);
    m_windowHalfWidth /= 2;
    m_windowHalfHeight /= 2;
}