#pragma once
/*
 * Created by Brett on 15/12/23.
 * Licensed under GNU General Public License V3.0
 * See LICENSE file for license detail
 */

#ifndef BLT_WITH_GRAPHICS_TEMPLATE_INPUT_H
#define BLT_WITH_GRAPHICS_TEMPLATE_INPUT_H

#include <cstdint>
#include <algorithm>
#include <cstring>

namespace blt::gfx
{
    enum class KEY_STATE : std::uint8_t
    {
        RELEASE = 0, PRESS = 1, REPEAT = 2
    };
    
    enum class MOUSE_STATE : std::uint8_t
    {
        RELEASE = 0, PRESS = 1
    };
    
    class input_manager
    {
        public:
            double mouseX = 0, mouseY = 0;
            double mouseLastX = 0, mouseLastY = 0;
            double deltaX = 0, deltaY = 0;
            double scroll = 0;
            bool mouse_moved = false;
            bool key_pressed = false;
            bool key_released = false;
            bool mouse_pressed = false;
            bool mouse_released = false;
        private:
            KEY_STATE* key_state;
            MOUSE_STATE* mouse_state;
            std::size_t key_size = 256;
            std::size_t mouse_size = 16;
            
            void expand_keys(std::size_t min)
            {
                auto new_size = std::max(key_size + 256, min);
                auto* new_key = new KEY_STATE[new_size];
                std::memset(new_key, 0, new_size * sizeof(KEY_STATE));
                std::memcpy(new_key, key_state, key_size * sizeof(KEY_STATE));
                delete[] key_state;
                key_state = new_key;
                key_size = new_size;
            }
            
            void expand_mouse(std::size_t min)
            {
                auto new_size = std::max(mouse_size + 16, min);
                auto* new_mouse = new MOUSE_STATE[new_size];
                std::memset(new_mouse, 0, new_size * sizeof(MOUSE_STATE));
                std::memcpy(new_mouse, mouse_state, mouse_size * sizeof(MOUSE_STATE));
                delete[] mouse_state;
                mouse_state = new_mouse;
                mouse_size = new_size;
            }
        
        public:
            input_manager()
            {
                key_state = new KEY_STATE[key_size];
                mouse_state = new MOUSE_STATE[mouse_size];
                std::memset(key_state, 0, key_size * sizeof(KEY_STATE));
                std::memset(mouse_state, 0, mouse_size * sizeof(MOUSE_STATE));
            }
            
            KEY_STATE& key(std::size_t key)
            {
                if (key >= key_size)
                    expand_keys(key);
                return key_state[key];
            }
            
            void clear()
            {
                key_pressed = false;
                key_released = false;
                mouse_moved = false;
                mouse_pressed = false;
                mouse_released = false;
            }
            
            bool isKeyPressed(std::size_t key)
            {
                if (key >= key_size)
                    expand_keys(key);
                return key_state[key] != KEY_STATE::RELEASE;
            }
            
            MOUSE_STATE& mouse(std::size_t mouse)
            {
                if (mouse >= mouse_size)
                    expand_mouse(mouse);
                return mouse_state[mouse];
            }
            
            bool isMousePressed(std::size_t mouse)
            {
                if (mouse >= mouse_size)
                    expand_mouse(mouse);
                return mouse_state[mouse] != MOUSE_STATE::RELEASE;
            }
            
            void updateMousePos(double x, double y)
            {
                mouseLastX = mouseX;
                mouseLastY = mouseY;
                mouseX = x;
                mouseY = y;
                deltaX = mouseX - mouseLastX;
                deltaY = mouseY - mouseLastY;
            }
            
            void updateScroll(double s)
            {
                scroll = s;
            }
            
            ~input_manager()
            {
                delete[] key_state;
                delete[] mouse_state;
            }
    };
}

#endif //BLT_WITH_GRAPHICS_TEMPLATE_INPUT_H
