/**
 *
 * @file src/render/opengl/Render_opengl.hpp
 *
 * @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 Mathieu Faverge
 * @author Thibault Soucarre
 * @author Kevin Coulomb
 * @author Lucas Guedon
 * @author Olivier Lagrasse
 * @author Augustin Degomme
 *
 * @date 2024-07-17
 */
/*!
 *\file Render_opengl.hpp
 */

#ifndef RENDER_OPENGL_HPP
#define RENDER_OPENGL_HPP

#include <stack>
#include <cmath>
#include <sstream>
/* -- */
#include <QObject>
#include <QGLWidget>
#include <QLabel>
#include <QPainter>
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
/* -- */
#include "interface/Interface_graphic.hpp"
/* -- */
#include "render/Geometry.hpp"
#include "render/Hook_event.hpp"
#include "render/Render.hpp"
#include "render/Minimap.hpp"
#include "render/Ruler.hpp"
#include "render/GanttDiagram.hpp"

#include "render/Render_windowed.hpp"
/*!
 * \brief This class redefined the OpenGL widget - QGLWidget - to display the trace.
 */
class Render_opengl : /*public QGLWidget,*/ public Hook_event
{
    Q_OBJECT

private:
    bool _draw_container;
    bool _draw_state;
    bool _draw_ruler;
    bool _draw_arrow;
    bool _draw_event;

protected:
    /*!
     * \brief The waiting screen display list.
     */
    GLuint _wait_list;

    /*!
     * \brief The minimap.
     */
    Minimap _minimap;

    /*!
     * \brief The container GLu list.
     */
    GLuint _list_containers;

    /*!
     * \brief The state GLu list.
     */
    GLuint _list_states;

    /*!
     * \brief The counter GLu list.
     */
    GLuint _list_counters;

    /*!
     * \brief The arrows GLu list.
     */
    GLuint _list_arrows;

    /*!
     * \brief The wait GLu list.
     */
    //  GLuint _wait_list;

    float _red, _green, _blue;

    std::vector<Container_text_> _texts;
    std::map<long int, Variable_text_> _variable_texts;
    std::vector<Arrow_> _arrows;
    std::vector<Event_> _circles;

    /***********************************
     *
     * The wait screen drawing.
     *
     **********************************/

    /***********************************
     * The wait list Attributes.
     **********************************/

    /*!
     * \brief Rotation angle for the wait.
     */
    float _wait_angle;

    /*!
     * \brief Time in ms between two frames for the waiting screen.
     */
    static const int DRAWING_TIMER_DEFAULT;

    /*!
     * \brief Wait animation seconds per frame.
     */
    int _wait_spf;

    /*!
     * \brief Offset of the vertical helper line
     */
    Element_pos vertical_line;

    /*!
     * \brief Timer to animate the wait.
     */
    QTimer *_wait_timer;

    /*!
     * \brief QLabel to display minimap.
     */
    //  QLabel* _minimap_widget;

    /*!
     * \brief QImage to store the trace thumbnail.
     */
    // QImage* _minimap_image;

    /*!
     * \brief Create a minimap from the current render.
     * \param width The desired width for the image.
     * \param height The desired height for the image.
     */
    // void create_minimap(const int width, const int height);

    /*!
     * \brief Update the minimap according to the current viewport.
     */
    //   void update_minimap();

    /*!
     * \brief Release data for minimap.
     */
    //  void release_minimap();

public:
    /***********************************
     *
     * Constructor and destructor.
     *
     **********************************/

    /*!
     * \brief The default constructor
     */
    Render_opengl(Interface_graphic *interface_graphic, const QGLFormat &format);

    /*!
     * \brief The destructor (~Render_opengl will never be called, so use another method to release memory)
     */
    void release() override;

    QWidget *get_render_widget() override;

    QImage grab_frame_buffer() override;

    /**
     * Functions inherited from Render.hpp
     */
    void start_draw() override;
    void end_draw() override;

    void start_draw_containers() override;
    void end_draw_containers() override;

    void start_draw_states() override;
    void draw_state(const Element_pos,
                    const Element_pos,
                    const Element_pos,
                    const Element_pos,
                    const Element_pos,
                    EntityValue *) override;
    void end_draw_states() override;

    void start_draw_arrows() override;
    void draw_arrow(const Element_pos,
                    const Element_pos,
                    const Element_pos,
                    const Element_pos,
                    const Element_col,
                    const Element_col,
                    const Element_col,
                    EntityValue *) override;
    void end_draw_arrows() override;

    void start_draw_counter() override;
    void end_draw_counter() override;

    void start_draw_events() override;
    void draw_event(const Element_pos,
                    const Element_pos,
                    const Element_pos,
                    EntityValue *) override;
    void end_draw_events() override;

    void start_ruler() override;
    void end_ruler() override;

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

    void set_color(float r, float g, float b) override;
    void draw_text(const Element_pos x,
                   const Element_pos y,
                   const Element_pos z,
                   const std::string &s) override;
    void draw_text_value(long int id,
                         double text,
                         double y) override;
    void draw_quad(Element_pos x,
                   Element_pos y,
                   Element_pos z,
                   Element_pos w,
                   Element_pos h) override;
    void draw_triangle(Element_pos x,
                       Element_pos y,
                       Element_pos size,
                       Element_pos r) override;
    void draw_line(Element_pos x1,
                   Element_pos y1,
                   Element_pos x2,
                   Element_pos y2,
                   Element_pos z) override;
    void draw_circle(Element_pos x,
                     Element_pos y,
                     Element_pos z,
                     Element_pos r) override;

    void set_vertical_line(Element_pos l) override;
    void draw_vertical_line() override;

    void call_ruler() override;

    /***********************************
     *
     * Default QGLWidget functions.
     *
     **********************************/

    /*!
     * \brief Call by the system to initialize the OpenGL render area.
     */
    void initializeGL() override;

    /*!
     * \brief Call by the system when the render area was resized (occurs during a window resizement).
     * \param width : the new width of the render area.
     * \param height : the new height of the render area.
     */
    void resizeGL(int width, int height) override;

    /*!
     * \brief Call by the system each time the render area need to be updated.
     */
    void paintGL() override;

    // void paintEvent(QPaintEvent *event);

    /* void initializeOverlayGL();
     void resizeOverlayGL(int width, int height);
     void paintOverlayGL();*/

    /*!
     * \brief Draw a container according to the parameters
     * \param x the x position of the container
     * \param y the y position of the container
     * \param w the width of the container
     * \param h the height of the container
     */
    void draw_container(const Element_pos x, const Element_pos y, const Element_pos w, const Element_pos h);

    /*!
     * \brief Draw the text of a container.
     * \param x the x position of the text.
     * \param y the y position of the text.
     * \param value the string value of the text.
     *
     * This function stores text in a list. This list will be display each time the render area need to be updated.
     */
    void draw_container_text(const Element_pos x, const Element_pos y, const std::string &value);

    /*!
     * \brief Draw a point of the counter.
     * \param x x position of the point.
     * \param y y position of the point.
     *
     * Each time counter is increased, this function is called with the coordinates of the new point.
     */
    void draw_counter(const Element_pos x, const Element_pos y);

    template <int N>
    void cos_table_builder(double table[]);
    template <int N>
    void sin_table_builder(double table[]);

    /***********************************
     *
     * Render OpenGL drawing functions.
     *
     **********************************/

    /*!
     * \brief Display a wait on the screen if there is no file opened.
     * \return Asset value of the wait.
     */
    GLuint draw_wait();

    /* Temporary methods. Use to draw stored arrows and circles. It is to
     prevent scaling */
    void draw_stored_arrows();
    void draw_stored_circles();

    void draw_stored_texts();

    /*!
     * \brief Show the minimap.
     */
    void show_minimap() override;

    /*! Function that only delete the arrows of the screen */
    void clear_arrow();
    /*! Function that only delete the text of the screen */
    void clear_text();

    /*!
     * \brief returns the offset of the vertical helper line
     */
    Element_pos get_vertical_line();

    /**
     * Building functions.
     */

    /*!
     * \brief This function draws the trace.
     */
    bool build() override;

    /*!
     * \brief This function releases the trace.
     */
    bool unbuild() override;

    /**
     * Functions specifics to OpenGL render.
     */

    /*!
     * \brief Set Statistics and Information about input trace
     */
    void set_total_width(Element_pos) { }

    /*!
     * \brief Set Statistics and Information about input trace
     */
    void set_total_time(Times) { }

    /*!
     * \brief display the scale
     */
    void display_time_scale() { }

    //    void set_vertical_line(int l){}
    //  void draw_vertical_line();

public Q_SLOTS:
    /*!
     * \brief slot connected to the simple click event
     */
    void update_vertical_line() override;
};

#endif
