/*
** This file is part of the ViTE project.
**
** This software is governed by the CeCILL-A license under French law
** and abiding by the rules of distribution of free software. You can
** use, modify and/or redistribute the software under the terms of the
** CeCILL-A license as circulated by CEA, CNRS and INRIA at the following
** URL: "http://www.cecill.info".
**
** As a counterpart to the access to the source code and rights to copy,
** modify and redistribute granted by the license, users are provided
** only with a limited warranty and the software's author, the holder of
** the economic rights, and the successive licensors have only limited
** liability.
**
** In this respect, the user's attention is drawn to the risks associated
** with loading, using, modifying and/or developing or reproducing the
** software by the user in light of its specific status of free software,
** that may mean that it is complicated to manipulate, and that also
** therefore means that it is reserved for developers and experienced
** professionals having in-depth computer knowledge. Users are therefore
** encouraged to load and test the software's suitability as regards
** their requirements in conditions enabling the security of their
** systems and/or data to be ensured and, more generally, to use and
** operate it in the same conditions as regards security.
**
** The fact that you are presently reading this means that you have had
** knowledge of the CeCILL-A license and that you accept its terms.
**
**
** ViTE developers are (for version 0.* to 1.0):
**
**        - COULOMB Kevin
**        - FAVERGE Mathieu
**        - JAZEIX Johnny
**        - LAGRASSE Olivier
**        - MARCOUEILLE Jule
**        - NOISETTE Pascal
**        - REDONDY Arthur
**        - VUCHENER Clément
**
*/
/*!
 *\file render_stats_opengl.hpp
 */

#ifndef RENDER_STATS_OPENGL_HPP
#define RENDER_STATS_OPENGL_HPP

/* Needed for moc compilation */
#include <stack>
#include <iostream>
/* -- */
#include <QObject>
#include <QGLWidget>
/* -- */
#include "common/common.hpp"
/* -- */
#include "render/Geometry.hpp"
#include "render/Hook_event.hpp"
#include "render/render_stats.hpp"

/*!
 * \brief This class redefined the OpenGL widget - QGLWidget - to display the trace.
 */
class Render_stats_opengl : public QGLWidget, public Render_stats {
    Q_OBJECT

private:

    /*!
     * \brief Contains container text coordinates.
     */
    std::list<Element_pos> _text_pos;

    /*!
     * \brief Contains container strings.
     */
    std::list<std::string> _text_value;

    GLuint _rect_list;

    double _translated_y;

    double _translated_x;

    bool _stats_beginned_drawed;

public:

    /*!
     * \brief The default constructor
     */
    Render_stats_opengl(QWidget *parent);

    /*!
     * \brief The destructor
     */
    ~Render_stats_opengl() override;

    /*!
     * \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;

    /*!
     * \brief Proceeds with the initialization of draw functions.
     */

    void start_draw() override;

    /*!
     * \fn draw_text(const Element_pos x, const Element_pos y, const std::string value)
     * \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.
     */
    void draw_text(const Element_pos x, const Element_pos y, const std::string value) override;

    /*!
     * \fn draw_line(const Element_pos x, const Element_pos y, const Element_pos x2, const Element_pos y2)
     * \brief Draw a line.
     * \param x the x position of the origin.
     * \param y the y position of the origin.
     * \param x2 the x position of the other point.
     * \param y2 the y position of the other point.
     */
    void draw_line(const Element_pos x, const Element_pos y, const Element_pos x2, const Element_pos y2);

    /*!
     * \fn draw_horizontal_line(const Element_pos x, const Element_pos y, const Element_pos size_x)
     * \brief Draw a line.
     * \param x the x position of the origin.
     * \param y the y position of the origin.
     * \param size_x the length of the line.
     */
    void draw_horizontal_line(const Element_pos x, const Element_pos y, const Element_pos size_x);

    /*!
     * \fn draw_vertical_line(const Element_pos x, const Element_pos y, const Element_pos size_y)
     * \brief Draw a line.
     * \param x the x position of the origin.
     * \param y the y position of the origin.
     * \param size_y the length of the line.
     */
    void draw_vertical_line(const Element_pos x, const Element_pos y, const Element_pos size_y);

    /*!
     * \fn draw_axis(const Element_pos x, const Element_pos y, const Element_pos size_x, const Element_pos size_y)
     * \brief Draw axis.
     * \param x the x position of the origin.
     * \param y the y position of the origin.
     * \param size_x the length for the horizontal axis.
     * \param size_y the length for the vertical axis.
     */
    void draw_axis(const Element_pos x, const Element_pos y, const Element_pos size_x, const Element_pos size_y);
    /*!
     * \brief Draw a rectangle.
     * \param x the x position of the rectangle.
     * \param y the y position of the rectangle.
     * \param w the width of the rectangle.
     * \param h the height position of the rectangle.
     * \param r the red component color of the rectangle.
     * \param g the green component color of the rectangle.
     * \param b the blue component color of the rectangle.
     */
    void draw_rect(const Element_pos x, const Element_pos y, const Element_pos w, const Element_pos h, const Element_pos r, const Element_pos g, const Element_pos b);
    /*!
     * \fn end_draw()
     * \brief Proceeds with the end of draw functions.
     */
    void end_draw() override;

    /*!
     * \fn translate_y(int value)
     * \brief Translate the window on the vertical axis.
     * \param value the new value of the scroll bar.
     */
    void translate_y(int value);
    /*!
     * \fn translate_x(int value)
     * \brief Translate the window on the horizontal axis.
     * \param value the new value of the scroll bar.
     */
    void translate_x(int value);

    /*!
     * \fn set_total_height(Element_pos h)
     * \brief Set the height of the render area.
     * \param h the new height.
     */
    void set_total_height(Element_pos h) override;

    /*!
     * \fn set_total_width(Element_pos w)
     * \brief Set the width of the render area.
     * \param w the new width.
     */
    void set_total_width(Element_pos w);

    /*!
     * \brief Set the height for one container.
     */
    void set_height_for_one_container(Element_pos h) override;

    /*!
     * \fn clear()
     * \brief Reinitialize the render.
     */
    void clear();
};


inline void Render_stats_opengl::start_draw(){
    _text_pos.clear();
    _text_value.clear();
    //  makeCurrent();
    _stats_beginned_drawed = true;
    _rect_list = glGenLists(1);
    if(_rect_list == 0) {
        std::cerr << "error while initialising _rect_list for stats\n" << std::endl;
    }
    glNewList(_rect_list, GL_COMPILE);
}

inline void Render_stats_opengl::draw_text(const Element_pos x, const Element_pos y, const std::string value) {

    _text_pos.push_back(x);
    _text_pos.push_back(y);
    _text_value.push_back(value);
}

inline void Render_stats_opengl::draw_line(const Element_pos x, const Element_pos y, const Element_pos x2, const Element_pos y2) {
    glBegin(GL_LINES);
    {
        glColor3ub(0, 0, 0);
        glVertex2d(x, y);
        glVertex2d(x2, y2);
    }
    glEnd();
}

inline void Render_stats_opengl::draw_horizontal_line(const Element_pos x, const Element_pos y, const Element_pos size_x){
    glBegin(GL_LINES);
    {
        glColor3ub(0, 0, 0);
        glVertex2d(x, y);
        glVertex2d(x+size_x, y);
    }
    glEnd();
}

inline void Render_stats_opengl::draw_vertical_line(const Element_pos x, const Element_pos y, const Element_pos size_y){
    glBegin(GL_LINES);
    {
        glColor3ub(0, 0, 0);
        glVertex2d(x, y);
        glVertex2d(x, y+size_y);
    }
    glEnd();
}

inline void Render_stats_opengl::draw_axis(const Element_pos x, const Element_pos y, const Element_pos size_x, const Element_pos size_y){
    glBegin(GL_LINES);
    {
        glColor3ub(0, 0, 0);
        glVertex2d(x, y);
        glVertex2d(x+size_x, y);
        glVertex2d(x, y);
        glVertex2d(x, y+size_y);
    }
    glEnd();

    glBegin(GL_TRIANGLES);/* create an arrow */
    {
        glColor3d(0, 0, 0);
        glVertex2d(x-5, y+size_y-5);
        glVertex2d(x, y+size_y);
        glVertex2d(x+5, y+size_y-5);
    }
    glEnd();

    glBegin(GL_TRIANGLES);/* create an arrow */
    {
        glColor3d(0, 0, 0);
        glVertex2d(x+size_x-5, y+5);
        glVertex2d(x+size_x, y);
        glVertex2d(x+size_x-5, y-5);
    }
    glEnd();
}

inline void Render_stats_opengl::draw_rect(const Element_pos x, const Element_pos y, const Element_pos w, const Element_pos h, const Element_pos r, const Element_pos g, const Element_pos b) {
    glBegin(GL_QUADS);
    {
        glColor3d(r, g, b); glVertex2d(x, y);
        glColor3d(r/1.5, g/1.5, b/1.5); glVertex2d(x, y+h);
        glColor3d(r, g, b); glVertex2d(x+w, y+h);
        glColor3d(r/1.5, g/1.5, b/1.5); glVertex2d(x+w, y);
    }
    glEnd();
}

inline void Render_stats_opengl::end_draw(){
    glEndList();
    paintGL();
    //  doneCurrent();
}

#endif
