/**
 *
 * @file src/render/vulkan/Render_vulkan.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Nolan Bredel
 * @author Lucas Guedon
 * @author Augustin Gauchet
 *
 * @date 2024-07-17
 */

#include "common/common.hpp"
#include "common/Info.hpp"
#include "trace/EntityValue.hpp"
#include "render/vulkan/Render_vulkan.hpp"

Render_vulkan::Render_vulkan(Interface_graphic *interface_graphic) :
    Render_abstract(interface_graphic), _window(interface_graphic, this) {

    _container = QWidget::createWindowContainer(&_window, interface_graphic);

    Info::Screen::width = 100;
    Info::Screen::height = 100;
}

void Render_vulkan::set_window_renderer(Vulkan_window_renderer *wr) {
    _window_renderer = wr;
}

QWidget *Render_vulkan::get_render_widget() {
    return _container;
}

QImage Render_vulkan::grab_frame_buffer() {
    return _window.grab();
}

void Render_vulkan::start_draw() {
    _container_vertices.clear();
    _state_vertices.clear();
    _ruler.clear();
    _counters.clear();
    _draw_container = false;
    _draw_states = false;
    _draw_ruler = false;
    _draw_counter = false;
}

void Render_vulkan::end_draw() {
    _window_renderer->buf_container_vertex.set_data(_container_vertices);
    _window_renderer->buf_state_vertex.set_data(_state_vertices);
    _window_renderer->buf_ruler.set_data(_ruler);
    _window_renderer->buf_counter.set_data(_counters);
    _container_vertices.clear();
    _state_vertices.clear();
    _ruler.clear();
    _counters.clear();
    _window.requestUpdate();
}

void Render_vulkan::start_draw_containers() {
    _draw_container = true;
}

void Render_vulkan::end_draw_containers() {
    _draw_container = false;
}

void Render_vulkan::start_draw_states() {
    _draw_states = true;
}

void Render_vulkan::draw_state(const Element_pos x,
                               const Element_pos y,
                               const Element_pos z,
                               const Element_pos w,
                               const Element_pos h,
                               EntityValue *v) {
    if (v == nullptr || v->get_visible()) {
        draw_quad(x, y, z, w, h);
    }
}

void Render_vulkan::end_draw_states() {
    _draw_states = false;
}

void Render_vulkan::start_draw_arrows() { }

void Render_vulkan::draw_arrow(const Element_pos,
                               const Element_pos,
                               const Element_pos,
                               const Element_pos,
                               const Element_col,
                               const Element_col,
                               const Element_col,
                               EntityValue *) { }

void Render_vulkan::end_draw_arrows() { }

void Render_vulkan::start_draw_counter() {
    _draw_counter = true;
}

void Render_vulkan::end_draw_counter() {
    _draw_counter = false;
}

void Render_vulkan::start_draw_events() { }

void Render_vulkan::draw_event(const Element_pos,
                               const Element_pos,
                               const Element_pos,
                               EntityValue *) { }

void Render_vulkan::end_draw_events() { }

void Render_vulkan::start_ruler() {
    _draw_ruler = true;
}

void Render_vulkan::end_ruler() {
    _draw_ruler = false;
}

/***********************************
 *
 * Displaying functions.
 *
 **********************************/

void Render_vulkan::set_color(float r, float g, float b) {
    _r = r;
    _g = g;
    _b = b;
}

void Render_vulkan::draw_text(const Element_pos x,
                              const Element_pos y,
                              const Element_pos z,
                              const std::string &s) { }

void Render_vulkan::draw_text_value(long int id,
                                    double text,
                                    double y) { }

void Render_vulkan::draw_quad(Element_pos x,
                              Element_pos y,
                              Element_pos z,
                              Element_pos w,
                              Element_pos h) {
    Element_pos offset_x = 0;
    Element_pos offset_y = -_ruler_y - _ruler_height;
    Element_col rl = 0.0;
    Element_col gl = 0.0;
    Element_col bl = 1.0;
    Element_col rr = 0.0;
    Element_col gr = 0.0;
    Element_col br = 1.0;
    std::vector<Vertex> *vertices;

    if (_draw_container) {
        rl = _r;
        gl = _g;
        bl = _b;
        rr = _r;
        gr = _g;
        br = _b;
        vertices = &_container_vertices;
    }
    else if (_draw_states) {
        rl = _r;
        gl = _g;
        bl = _b;
        rr = _r * 0.5f;
        gr = _g * 0.5f;
        br = _b * 0.5f;
        // TODO alpha = 0.5
        offset_x = -_default_entity_x_translate;
        vertices = &_state_vertices;
    }
    else {
        return;
    }

    vertices->emplace_back(x + offset_x, y + offset_y, rl, gl, bl);
    vertices->emplace_back(x + offset_x + w, y + offset_y, rr, gr, br);
    vertices->emplace_back(x + offset_x + w, y + offset_y + h, rr, gr, br);
    vertices->emplace_back(x + offset_x + w, y + offset_y + h, rr, gr, br);
    vertices->emplace_back(x + offset_x, y + offset_y + h, rl, gl, bl);
    vertices->emplace_back(x + offset_x, y + offset_y, rl, gl, bl);
    (void)z;
}

void Render_vulkan::draw_triangle(Element_pos x,
                                  Element_pos y,
                                  Element_pos size,
                                  Element_pos r) { }

void Render_vulkan::draw_line(Element_pos x1,
                              Element_pos y1,
                              Element_pos x2,
                              Element_pos y2,
                              Element_pos z) {
    const Element_pos offset_x = -_default_entity_x_translate;
    const Element_pos offset_y = -_ruler_y - _ruler_height;

    if (_draw_counter) {
        _counters.emplace_back(x1 + offset_x, y1 + offset_y, 1.0f, 1.0f, 1.0f);
        _counters.emplace_back(x2 + offset_x, y2 + offset_y, 1.0f, 1.0f, 1.0f);
    }
    else if (_draw_ruler) {
        _ruler.emplace_back(x1 + offset_x, y1, _r, _g, _b);
        _ruler.emplace_back(x2 + offset_x, y2, _r, _g, _b);
    }
    (void)z;
}

void Render_vulkan::draw_circle(Element_pos x,
                                Element_pos y,
                                Element_pos z,
                                Element_pos r) { }

void Render_vulkan::set_vertical_line(Element_pos l) { }

void Render_vulkan::draw_vertical_line() { }

void Render_vulkan::call_ruler() { }

void Render_vulkan::update_vertical_line() { }

bool Render_vulkan::build() {
    replace_scale_x(1); /* for states scaling */
    init_geometry();
    update_render();
    return true;
}

bool Render_vulkan::unbuild() {
    _container_vertices.clear();
    _state_vertices.clear();
    _ruler.clear();
    _counters.clear();
    _window_renderer->buf_container_vertex.set_data(_container_vertices);
    _window_renderer->buf_state_vertex.set_data(_state_vertices);
    _window_renderer->buf_ruler.set_data(_ruler);
    _window_renderer->buf_counter.set_data(_counters);
    return true;
}

void Render_vulkan::release() { }

void Render_vulkan::show_minimap() { }

void Render_vulkan::update_render() {

    _window_renderer->container_model_view.setToIdentity();
    _window_renderer->container_model_view.translate(0.0f, _ruler_y + _ruler_height - _y_state_translate, _z_container);
    _window_renderer->container_model_view.scale(_x_scale_container_state / 0.20f, _y_state_scale, 1.0f);

    _window_renderer->state_model_view.setToIdentity();
    _window_renderer->state_model_view.translate(_default_entity_x_translate - _x_state_translate, _ruler_y + _ruler_height - _y_state_translate, _z_state);
    _window_renderer->state_model_view.scale(_x_state_scale, _y_state_scale, 1);
    _window.requestUpdate();
}
