//
// Created by fotyev on 2018-11-23.
//

#ifndef ZENGINE_MENU_HPP
#define ZENGINE_MENU_HPP

#include <string>

#include "components/window.hpp"
#include "components/resources.hpp"
#include "components/input.hpp"

#include "opengl/textrender.hpp"

#include "util/string.hpp"
#include "util/log.hpp"
#include "util/static_resource.hpp"
#include "main.hpp"

/*< register_module(class=>'menu_c',
    scriptexport=>['lock'],
    ctors=>['std::string s, menu_c::callback_t cb, qvm::vec2 pos, float pixelh'], pointer=>1
    ); >*/
class menu_c
{
public:
    using callback_t = std::function<void (unsigned opt, qvm::vec2 pos)>;

private:
    qvm::vec2 pos {0, 0}, // upper left corner
    cursor_pos,
    size;
    std::string menu;
    callback_t callback;
    unsigned int num_options;
    float pixelh;
    float cursor_size;
    uint64_t hash;
    sig::scoped_connection _key_down = g_app->input->button("menu_down", "DOWN").connect([this](bool t){
        if(t && !lock) ++selected;
    });
    sig::scoped_connection _key_up = g_app->input->button("menu_up", "UP").connect([this](bool t){
        if(t && !lock) --selected;
    });
    sig::scoped_connection _key_select = g_app->input->button("menu_select", "ENTER").connect([this](bool t){
        if(t && !lock)
        {
            normalize();
            callback(selected, cursor_pos);
        }
    });
    sig::scoped_connection _d = g_app->window->draw.connect([this](){ draw(); });

public:
    bool lock = false;
    int selected = 0;
NONCOPYABLE/*_BUT_SWAPPABLE*/(menu_c)//, (lock)(selected)(pos)(cursor_pos)(size)(menu)(callback)(num_options)(pixelh)(cursor_size)(hash)) // no connections!11
private:

    void normalize()
    {
        while(selected < 0)
            selected += num_options;
        while((unsigned)selected >= num_options)
            selected -= num_options;
        cursor_pos = pos + qvm::vec2{-cursor_size, -cursor_size * (selected + 1)};
    }


    texture make_text_texture()
    {
        return make_text(g_app->resources->default_font, menu, pixelh);
    }
public:
    menu_c(std::string s, callback_t cb, qvm::vec2 pos = {0, 0}, float pixelh = 18) :
    menu(std::move(s)), callback(std::move(cb)), pixelh(pixelh)
    {
        size = g_app->resources->default_font.get_string_size(menu, pixelh);
        using namespace qvm;
        size = g_app->window->convert_from_pixel_coords_size(X(size), Y(size));
        num_options = (unsigned)string_split_v(menu, "\n").size();
        hash = fnv1a::hash(menu);
        cursor_size = qvm::Y(g_app->window->convert_from_pixel_coords_size(0, g_app->resources->default_font.get_line_skip(pixelh)));
    }
private:
    void draw()
    {
        using namespace qvm;

        //g_app->window->render_text_box()
        auto& text = g_app->resources->textures.get(hash, [this](){
            return make_text_texture();
        });
        //static_resource<renderer_2d>::get(ID("resources/shd/menu.glsl")).copy(text, pos, size);
        g_app->window->text_render.copy(text, pos - _0Y(size), size);

        // cursor
        if(lock || (int)(glfwGetTime() * 5) % 2)
        {
            normalize();
            g_app->window->render_text_box(cursor_pos, qvm::vec2{cursor_size, cursor_size}, "⇛");
        }
    }
};

#endif //ZENGINE_MENU_HPP
