/*
 ** 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_alternate.cpp
 */
#include <assert.h>
#include "common/common.hpp"
#include "common/Info.hpp"
#include "common/Message.hpp"
/* -- */

#include <map>
#include <GL/glew.h>
/* -- */
#include <QFile> // For loading the wait image
#include <QDate>
#include <QTimer>
#include <QImage>
#include <QEventLoop>
/* -- */
#include "interface/resource.hpp"
#include "interface/Interface.hpp"
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
#include "common/Message.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/tree/Interval.hpp"
#include "trace/tree/Node.hpp"
#include "trace/tree/BinaryTree.hpp"
#include "trace/EntityValue.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "render/Ruler.hpp"
#include "render/Render_alternate.hpp"
#include "render/GanttDiagram.hpp"
#include "render/Shader.hpp"
#include "render/vbo.hpp"
/* -- */
#include "core/Core.hpp"
#include <iostream>

#define PI 3.14159265
#define NB_STEPS 20

using namespace std;

extern "C" {
#if !defined(NDEBUG)
    static inline void checkGlError(){
        int rc = glGetError();
        assert( rc == GL_NO_ERROR );
    }
#else
    static inline void checkGlError(){
    }
#endif
}


#define message *Message::get_instance() << "(" << __FILE__ << " l." << __LINE__ << "): "

static bool _draw_container;
static bool _draw_states;
static bool _draw_ruler;
static bool _draw_arrow;
static bool _draw_event;
static bool _draw_counter;
//const int Render_alternate::DRAWING_TIMER_DEFAULT = 10;

/***********************************
 *
 *
 *
 * Constructor and destructor.
 *
 *
 *
 **********************************/

Render_alternate::Render_alternate(Core* core, QWidget *parent, const QGLFormat& format)
    : Hook_event(this, core, parent, format),
      _glsl(0),
      _container_height(_DRAWING_CONTAINER_HEIGHT_DEFAULT),
      _modelview(glm::mat4(1.0)), _projection(glm::mat4(1.0)),
      _containers(nullptr),
      _arrows3(nullptr),
      _counters(nullptr),
      _ruler(nullptr),
      _wait(nullptr),
      _selection(nullptr),
      _time_line(nullptr)
{
    _texts.clear();
    _variable_texts.clear();
    _links.clear();
    vertical_line = 0;
    /*int error = FT_Init_FreeType(&library);
     if(error != 0)
     std::cout << "an error occured during freetype initialization" << std::endl;*/
}


Render_alternate::~Render_alternate(){
    delete _wait;
    delete _shader;
}

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

void  Render_alternate::initializeGL() {
    glewExperimental = GL_TRUE;
    GLenum err = glewInit();
    if(err!=GLEW_OK){
        std::cout << "ERROR : GlewInit failed" << std::endl;
    }
#ifdef USE_QT5
    // Reset the error code set to GL_INVALID_ENUM by glewInit()
    glGetError();
#endif

    checkGlError();
    glClearColor(0.5f, 0.5f, 0.55f, 0.0f);
    glEnable(GL_DEPTH_TEST);
    checkGlError();
    glClearStencil(0);
    checkGlError();

    // Check for OpenGL version support
    const GLubyte * version = glGetString(GL_SHADING_LANGUAGE_VERSION);
    checkGlError();
    if ( version == nullptr ) {
        std::cout << "ERROR : could not detect your GLSL version" << std::endl;
        return;
    }

    std::cout << "Version GLSL : " << version << std::endl;
    _glsl = (version[0]-'0')*100 + (version[2]-'0')*10 + version[3]-'0';

    _shader = new Shader(_glsl);
    _shader->charger();
    draw_wait();
    setAutoFillBackground(false);
    _core->waitGUIInit->quit();
    _modelview = glm::scale(_modelview, glm::vec3(1,-1,1));
    _modelview = glm::translate(_modelview, glm::vec3(0,-Info::Render::height, 0));

    // code from test on freetype library
    // see http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02
    // face = FT_New_Face(library,
    //                    "/usr/share/fonts/truetype/freefont/FreeSerif.ttf",
    //                    0,
    //                    &face);

    // if(error)
    //     std::cout << "an error occured when loading font" << std::endl;

    // error = FT_Set_Char_Size(face,
    //                          0,
    //                          16*64,
    //                          1920,
    //                          1080);

    // if(error)
    //     std::cout << "an error occured when changing character size" << std::endl;

    // FT_Glyphslot g = face->glyph;
    // int w=0, h=0;
    // for(int i = 32; i < 128; i++) {
    //     if(FT_Load_Char(face, i, FT_LOAD_RENDER)) {
    //         fprintf(stderr, "Loading character %c failed!\n", i);
    //         continue;
    //     }

    //     w += g->bitmap.width;
    //     h = std::max(h, g->bitmap.rows);
    //     char_info[*p].ax = g->advance.x >> 6;
    //     char_info[*p].ay = g->advance.y >> 6;
    //     char_info[*p].bw = g->bitmap.width;
    //     char_info[*p].bh = g->bitmap.rows;
    //     char_info[*p].bl = g->bitmap_left;
    //     char_info[*p].bt = g->bitmap_top;
    //     char_info[*p].tx = (float)x / w;

    //     // you might as well save this value as it is needed later on
    // }
    // atlas_width = w;
    // GLuint tex;
    // glActiveTexture(GL_TEXTURE0);
    // glGenTextures(1, &tex);
    // glBindTexture(GL_TEXTURE_2D, tex);
    // glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    // glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
    // int x = 0;
    // for(int i = 32; i < 128; i++) {
    //     if(FT_Load_Char(face, i, FT_LOAD_RENDER))
    //         continue;
    //     glTexSubImage2D(GL_TEXTURE_2D, 0, x, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
    //     x += g->bitmap.width;
    // }
}

void Render_alternate::render_text(const QString &text, float x, float y, float w, float h){
    /* Code trying to create text on QImage and create a texture from this. Then render the text thanks to this texture. Not working yet, the texture seems to be empty*/
    GLuint texture;
    checkGlError();
    glGenTextures(2, &texture);
    checkGlError();
    glBindTexture(GL_TEXTURE_2D, texture);
    checkGlError();
    QImage   *image = new QImage(512, 512, QImage::Format_RGB32);
    image->fill( Qt::transparent );
    QPainter *p = new QPainter(image);
    //p.beginNativePainting();
    p->drawText(0, 0, 512, 512, Qt::AlignHCenter|Qt::AlignVCenter, text);
    delete p;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512, 512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
    checkGlError();
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 512, 512, GL_ALPHA, GL_UNSIGNED_BYTE, image->bits());
    checkGlError();
    glBindTexture(GL_TEXTURE_2D, 0);
    //p.endNativePainting();
    Vbo v(nullptr);
    v.add(x  , y,   0, 1);
    v.add(x+w, y,   1, 1);
    v.add(x+w, y+h, 1, 0);
    v.add(x  , y,   0, 1);
    v.add(x  , y+h, 0, 0);
    v.add(x+w, y+h, 1, 0);
    v.config(_glsl);
    glUseProgram(_wait->get_shader()->getProgramID());
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    v.lock();
    glBindTexture(GL_TEXTURE_2D, texture);
    glDrawArrays(GL_TRIANGLES, 0, v.getNbVertex());
    glDisable(GL_BLEND);
    glBindTexture(GL_TEXTURE_2D, 0);
    v.unlock();
    glUseProgram(0);
    delete image;
    /*trying freetype*/
    // int n=0;
    // for(char*p = text; *p; p++){
    //     float x2 =  x + c[*p].bl * sx;
    //     float y2 = -y - c[*p].bt * sy;
    //     float w = c[*p].bw * sx;
    //     float h = c[*p].bh * sy;
    //     /* Advance the cursor to the start of the next character */
    //     x += c[*p].ax * sx;
    //     y += c[*p].ay * sy;

    //     /* Skip glyphs that have no pixels */
    //     if(!w || !h)
    //         continue;
    //     _text.add(x2, y2, c[*p].tx, 0);
    //     _text.add(x2+w, -y2, c[*p].tx + c[*p].bw / atlas_width, 0);
    //     _text.add(x2, -y2 - h, c[*p].tx, c[*p].bh / atlas_height); //remember: each glyph occupies a different amount of vertical space
    //     _text.add(x2 + w, -y2    , c[*p].tx + c[*p].bw / atlas_width,   0);
    //     _text.add(x2,     -y2 - h, c[*p].tx,                                          c[*p].bh / atlas_height);
    //     _text.add(x2 + w, -y2 - h, c[*p].tx + c[*p].bw / atlas_width, c[*p].bh / atlas_height);
    // }
}

void  Render_alternate::resizeGL(int width, int height) {
    glViewport(0, 0, width, height);
    checkGlError();

    /* update informations about widget size */
    Info::Screen::width  = width;
    Info::Screen::height = height;
    if(_state == DRAWING_STATE_WAITING)
        _projection = glm::ortho(-50, 50, -50, 50);//, 0, 1);
    else if(_state == DRAWING_STATE_DRAWING)
        _projection = glm::ortho(0.f, Info::Render::width, 0.f, Info::Render::height, 0.f, 100.f);
    else{
        message << tr("Undefined value for the drawing state attribute - Render area").toStdString() << Message::ende;
    }

}


void  Render_alternate::paintGL(){
    glGetError();
    checkGlError();
    glClearDepth(1.0);
    checkGlError();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    checkGlError();

    /*Draw the home screen*/
    if(DRAWING_STATE_WAITING == _state){
        glUseProgram(_wait->get_shader()->getProgramID());
        checkGlError();

        glEnable(GL_BLEND);
        checkGlError();

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        checkGlError();

        _wait->lock();

        glBindTexture(GL_TEXTURE_2D, _textureID);
        checkGlError();

        // GL_QUADS is deprecated for Opengl greater than 3., so an invalide enum is returned by glGetError and needs to be reset
        // TODO: fix that by replacing by GL_TRIANGLES
        glDrawArrays(GL_TRIANGLES, 0, _wait->getNbVertex()); /*glGetError();*/
        checkGlError();
        glBindTexture(GL_TEXTURE_2D, 0);
        checkGlError();
        _wait->unlock();
        glUseProgram(0);
        checkGlError();
        return;
    }
    /*Else, draw the trace*/

    resizeGL(Render_alternate::QGLWidget::width(), Render_alternate::QGLWidget::height());
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    checkGlError();

    //select shader program
    glUseProgram(_shader->getProgramID());
    checkGlError();
    glm::mat4 tmp  = _modelview;
    glm::mat4 tmp2 = _modelview;
    glm::mat4 mvp;
    start_ruler();
    call_ruler();
    end_ruler();
    _ruler.config(_glsl);
    _ruler.lock();
    _modelview = glm::translate(_modelview, glm::vec3(0.0, 0.0, _z_ruler));
    mvp = _projection * _modelview;
    glUniformMatrix4fv(glGetUniformLocation(_shader->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
    checkGlError();
    /*The first 8 elements of the vbo are the coordinates of the quads, others elements are coordinates of the graduation*/
    glDrawArrays(GL_TRIANGLES, 0, 12);  /*glGetError();*/
    checkGlError();
    _modelview = tmp;
    _modelview = glm::translate(_modelview, glm::vec3(0.0, 0.0, _z_ruler_over));
    mvp = _projection * _modelview;
    glUniformMatrix4fv(glGetUniformLocation(_shader->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
    checkGlError();
    glDrawArrays(GL_LINES, 12, _ruler.getNbVertex()-12);
    checkGlError();
    _ruler.unlock();
    _modelview = tmp;

    /* drawing containers*/
    Shader*s = _containers.get_shader();
    glUseProgram(s->getProgramID());
    _containers.lock();
    _modelview = glm::translate(_modelview, glm::vec3(0.0, _ruler_y + _ruler_height - _y_state_translate, _z_container));
    _modelview = glm::scale(_modelview, glm::vec3(_x_scale_container_state/0.20, _y_state_scale, 1.0));
    mvp = _projection * _modelview;
    glUniformMatrix4fv(glGetUniformLocation(_shader->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
    glDrawArrays(GL_TRIANGLES, 0, _containers.getNbVertex());  /*glGetError();*/
    checkGlError();
    _containers.unlock();
    _modelview = tmp;
    glUseProgram(0);
    /*drawing states*/
    _modelview = glm::translate(_modelview, glm::vec3(_default_entity_x_translate - _x_state_translate, _ruler_y + _ruler_height - _y_state_translate, _z_state));
    _modelview = glm::scale(_modelview, glm::vec3(_x_state_scale, _y_state_scale, 1));
    mvp = _projection * _modelview;
    std::map<EntityValue*, Vbo*>::iterator it_state;
    it_state = _states.begin();
    while(it_state!=_states.end()){
        Shader *s = it_state->second->get_shader();
        glUseProgram(s->getProgramID());
        it_state->second->lock();
        glUniformMatrix4fv(glGetUniformLocation(s->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
        if(it_state->first==nullptr || it_state->first->get_visible()) {
            glDrawArrays(GL_TRIANGLES, 0, it_state->second->getNbVertex());  /*glGetError();*/
            checkGlError();
        }
        it_state->second->unlock();
        it_state++;
    }
    checkGlError();

    /*drawing counters*/
    glUseProgram(_counters.get_shader()->getProgramID());
    glUniformMatrix4fv(glGetUniformLocation(_counters.get_shader()->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));

    _counters.lock();
    glDrawArrays(GL_LINES, 0, _counters.getNbVertex());
    _counters.unlock();
    _modelview = tmp;
    checkGlError();

    /*drawing links*/
    if(false == Info::Render::_no_arrows){
        //matrix change that are necessary for each link
        _modelview = glm::translate(_modelview, glm::vec3(_default_entity_x_translate - _x_state_translate, _ruler_y + _ruler_height - _y_state_translate , _z_arrow));
        _modelview = glm::scale(_modelview, glm::vec3(_x_state_scale, _y_state_scale, 1.0));
        mvp = _projection * _modelview;
        //draw the lines
        std::map<EntityValue*, std::pair<Vbo *, Vbo*> >::iterator it_arrow = _arrows.begin();
        while(it_arrow != _arrows.end()){
            Shader *s = it_arrow->second.first->get_shader();
            glUseProgram(s->getProgramID());
            it_arrow->second.first->lock();
            glUniformMatrix4fv(glGetUniformLocation(s->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
            if(it_arrow->first == nullptr || it_arrow->first->get_visible())
                glDrawArrays(GL_LINES, 0, it_arrow->second.first->getNbVertex());
            it_arrow->second.first->unlock();
            if(Info::Render::_arrows_shape == 1){ //head = points
                it_arrow->second.second->lock();
                glEnable(GL_PROGRAM_POINT_SIZE);
                glEnable(GL_POINT_SMOOTH);
                glPointSize(5);
                if(it_arrow->first == nullptr || it_arrow->first->get_visible())
                    glDrawArrays(GL_POINTS, 0, it_arrow->second.second->getNbVertex());
                it_arrow->second.second->unlock();
            }
            it_arrow++;
        }
        if(Info::Render::_arrows_shape == 0){ //triangles
            std::map<EntityValue*, std::vector<Element_pos> >::iterator it_link = _links.begin();
            _modelview = glm::scale(_modelview, glm::vec3(1/_x_state_scale, 1/_y_state_scale, 1));
            tmp2 = _modelview;
            _arrows3.lock();
            while(it_link != _links.end()){
                Shader *s = _arrows[it_link->first].first->get_shader();
                glUseProgram(s->getProgramID());
                std::vector<Element_pos> v = it_link->second;
                int n = v.size()/3;
                if(it_link->first != nullptr && !it_link->first->get_visible()){
                    it_link++;
                    continue;
                }
                for(int i=0 ; i<n ; i++){
                    _modelview = glm::translate(_modelview, glm::vec3(_x_state_scale * v[3*i], _y_state_scale * v[3*i+1], 0));
                    _modelview = glm::rotate(_modelview, v[3*i+2], glm::vec3(0, 0, 1));
                    mvp = _projection * _modelview;
                    glUniformMatrix4fv(glGetUniformLocation(s->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));

                    glDrawArrays(GL_TRIANGLES, 0, _arrows3.getNbVertex());
                    _modelview = tmp2;
                }
                it_link++;
            }
            _arrows3.unlock();
        }
        _modelview = tmp;
    }
    checkGlError();

    /*drawing events*/
    if(false == Info::Render::_no_events){
        _modelview = glm::translate(_modelview, glm::vec3(_default_entity_x_translate - _x_state_translate, _ruler_y + _ruler_height - _y_state_translate , _z_event));
        _modelview = glm::scale(_modelview, glm::vec3(_x_state_scale, _y_state_scale, 1.0));
        mvp = _projection * _modelview;
        std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it_event = _events.begin();
        while(it_event != _events.end()){
            Shader *s = it_event->second.first->get_shader();
            glUseProgram(s->getProgramID());
            it_event->second.first->lock();
            glUniformMatrix4fv(glGetUniformLocation(s->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
            if(it_event->first==nullptr || it_event->first->get_visible()){
                //glDisable(GL_PROGRAM_POINT_SIZE);
                //draw points as circles instead of squares
                glEnable(GL_POINT_SMOOTH);
                glPointSize(5);
                glDrawArrays(GL_POINTS, 0, it_event->second.first->getNbVertex());
                it_event->second.first->unlock();
            }
            it_event->second.second->lock();
            glLineWidth(2);
            if(it_event->first==nullptr || it_event->first->get_visible())
                glDrawArrays(GL_LINES, 0, it_event->second.second->getNbVertex());
            it_event->second.second->unlock();
            it_event++;
        }
        glLineWidth(1);

    }

    _modelview = tmp;
    glUseProgram(_shader->getProgramID());


    /*draw selection if necessary*/
    if (_mouse_pressed && (Info::Render::_key_ctrl == false) && !_mouse_pressed_inside_container){
        //allow transparency
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        Element_pos x0, x1, y0, y1;
        x0 = screen_to_render_x(_mouse_x);
        y0 = screen_to_render_y(_mouse_y);
        x1 = screen_to_render_x(_new_mouse_x);
        y1 = screen_to_render_y(_new_mouse_y);
        _selection.add(x0, y0, 1.0, 1.0, 1.0);
        _selection.add(x0, y1, 1.0, 1.0, 1.0);
        _selection.add(x1, y1, 1.0, 1.0, 1.0);
        _selection.add(x1, y1, 1.0, 1.0, 1.0);
        _selection.add(x1, y0, 1.0, 1.0, 1.0);
        _selection.add(x0, y0, 1.0, 1.0, 1.0);
        _selection.config(_glsl);
        _selection.lock();
        glDrawArrays(GL_TRIANGLES, 0, _selection.getNbVertex());
        _selection.unlock();
        glDisable(GL_BLEND);
        _modelview = tmp;
    }
    draw_vertical_line();
    checkGlError();

    //deselect shader
    glUseProgram(0);
    checkGlError();
    QFont arial_font = QFont("Arial", 10);
    const QFontMetrics metric(arial_font);
    QString t = QString().setNum(vertical_line);
    // draw time corresponding to the vertical line position
    qglColor(Qt::red);
    checkGlError();
    renderText ( render_to_screen_x(trace_to_render_x(vertical_line))-metric.size(Qt::TextSingleLine,t).width() -5,
                 metric.height()-1,
                 t,
                 arial_font);
    /*render_text(t,
     render_to_screen_x(trace_to_render_x(vertical_line))-metric.size(Qt::TextSingleLine,t).width() -5,
     metric.height()-1,
     100,
     100);*/
    glGetError();
    /*render_text("Test",
     vertical_line,
     0,
     1,
     1);*/

    checkGlError();
    //draw texts for variables
    std::map<long int, Variable_text_>::const_iterator it=_variable_texts.begin();
    const std::map<long int, Variable_text_>::const_iterator it_end=_variable_texts.end();

    for(;it!=it_end;it++){
        renderText ( render_to_screen_x(trace_to_render_x(vertical_line))+3,
                     render_to_screen_y( trace_to_render_y((*it).second.y) + 0.5),
                     QString().setNum((*it).second.value),
                     arial_font);
    }
    checkGlError();


    qglColor(Qt::white);
    //we calculate the height of the interline we want : max height of the font + 1 pixel to avoid overlapping (metric.height() returns a bigger value, a bit too much)
    int height = metric.tightBoundingRect("fg").height()+1;

    /* Draw container text */
    const unsigned int texts_size = _texts.size();
    std::map<Element_pos,Element_pos> previous_by_column;


    //int skipped,displayed=0;
    for (unsigned int i=0 ; i<texts_size ; i++){



        if (trace_to_render_y(_texts[i].y) + 0.5 < 9) continue;/* Do not display text if it is on the ruler area */

        //check if ye are not too close to another container to properly display the text
        std::map<Element_pos,Element_pos>::const_iterator it = previous_by_column.find(_texts[i].x);
        const std::map<Element_pos,Element_pos>::const_iterator it_end = previous_by_column.end();

        if (it==it_end || render_to_screen_y(trace_to_render_y(_texts[i].y)) - render_to_screen_y(trace_to_render_y((*it).second))> height ){
            const QString text_elided = metric.elidedText(_texts[i].value.c_str(), Qt::ElideRight, 0.8 * _x_scale_container_state*Info::Screen::width/(Info::Trace::depth+1.));
            renderText ( render_to_screen_x(_texts[i].x * _x_scale_container_state/0.20),
                         render_to_screen_y( trace_to_render_y(_texts[i].y) + 0.5),
                         text_elided,
                         arial_font);

            //push only displayed values in the map
            previous_by_column[_texts[i].x]=_texts[i].y;
            //displayed++;
        }//else{skipped++;}
    }
    /*Draw ruler text*/
    std::ostringstream buf_txt;
    Element_pos graduation_diff;
    Element_pos coeff_prefix;
    graduation_diff = Ruler::get_graduation_diff(Info::Render::_x_min_visible, Info::Render::_x_max_visible);
    coeff_prefix    = Ruler::get_coeff_for_common_prefix(Info::Render::_x_min_visible, Info::Render::_x_max_visible);

    arial_font.setPointSize(14);

    buf_txt.str("");/* flush the buffer */
    buf_txt << "min: " << (double)Info::Render::_x_min_visible;

    renderText (render_to_screen_x(trace_to_render_x(Info::Render::_x_min_visible)),
                render_to_screen_y(3),
                buf_txt.str().c_str(),
                arial_font);

    buf_txt.str("");/* flush the buffer */
    buf_txt << "max: " << (double)Info::Render::_x_max_visible;

    renderText (render_to_screen_x(trace_to_render_x(Info::Render::_x_max_visible))-130,
                render_to_screen_y(3),
                buf_txt.str().c_str(),
                arial_font);

    buf_txt.str("");
    buf_txt << Ruler::get_common_part_string(Info::Render::_x_min_visible, coeff_prefix) << "--";

    renderText (render_to_screen_x(trace_to_render_x((Info::Render::_x_min_visible +
                                                      Info::Render::_x_max_visible) / 2)),
                render_to_screen_y(3),
                buf_txt.str().c_str(),
                arial_font);
    //glGetError();

    for (Element_pos i = Info::Render::_x_min_visible ;
         i < Info::Render::_x_max_visible ;
         i+=graduation_diff){

        buf_txt.str("");/* flush the buffer */
        buf_txt << Ruler::get_variable_part(i, coeff_prefix, 2);

        renderText (render_to_screen_x(trace_to_render_x(i)+1),
                    render_to_screen_y(8),
                    buf_txt.str().c_str(),
                    arial_font);

    }

    checkGlError();
}
/***********************************
 *
 *
 *
 * Building functions.
 *
 *
 *
 **********************************/



bool Render_alternate::build(){

    _state = DRAWING_STATE_DRAWING;/* change the drawing state */

    /* disable some OpenGL features to enhance the rendering */
    glDisable(GL_BLEND);
    replace_scale(1);/* for states scaling */
    _x_state_translate = 0;/* for states translation */
    _y_state_scale = 1;/* for states scaling */
    _y_state_translate = 0;/* for states translation */
    _x_scroll_pos = 0;/* horizontal bar placed on 0 */
    _y_scroll_pos = 0;/* vertical bar placed on 0 */
    checkGlError();
    if (nullptr == _render_instance)
        return true;

    return true;
}

/* trying to render text with qpainter outside paintGL
 Not working yet*/
/*void Render_alternate::paintEvent(QPaintEvent *Event){
 paintGL();
 QPainter p(this);
 QFont arial_font = QFont("Arial", 10);
 const QFontMetrics metric(arial_font);
 QString t =QString().setNum(vertical_line);
 p.drawText(render_to_screen_x(trace_to_render_x(vertical_line))-metric.size(Qt::TextSingleLine,t).width() -5,
 metric.height()-1,
 t);
 glGetError();
 checkGlError();
 }*/



bool Render_alternate::unbuild(){


    /**********************
     *
     * Init OpenGL features
     *
     **********************/

    /*enable some OpenGL features*/
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glEnable(GL_BLEND);/* enable blending for the alpha color */
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor3d(1.0, 1.0, 1.0);/* init color to white */


    /*****************************
     *
     * Init render area attributes
     *
     *****************************/

    _state = DRAWING_STATE_WAITING;/* change the drawing state */


    /* clear lists and maps*/
    _text_pos.clear();
    _text_value.clear();
    clear_text();
    _links.clear();
    _states.clear();
    _arrows.clear();
    _events.clear();

    return true;
}





/***********************************
 *
 *
 *
 * Drawing function for the wait screen.
 *
 *
 *
 **********************************/



GLuint Render_alternate::draw_wait() {
    if (_wait == nullptr) {
        Shader *s = new Shader(_glsl, 0);

        _wait = new Vbo();
        s->charger();
        _wait->set_shader(s);

        glGenTextures(1, &_textureID);
        glBindTexture(GL_TEXTURE_2D, _textureID);

        QFile texture_file(QString(":/img/img/logo") +  QDate::currentDate().toString("MMdd") + QString(".png"));
        if (true == texture_file.exists())/* The texture exists */
            _textureID = bindTexture(QPixmap(texture_file.fileName()), GL_TEXTURE_2D);
        else/* use the default picture */
            _textureID = bindTexture(QPixmap(":/img/img/logo.png"), GL_TEXTURE_2D);

        /* Coordinates of the two triangles storing the texture */
        _wait->add(-0.25, -0.25, 0, 0);
        _wait->add( 0.25, -0.25, 1, 0);
        _wait->add( 0.25,  0.25, 1, 1);
        _wait->add( 0.25,  0.25, 1, 1);
        _wait->add(-0.25,  0.25, 0, 1);
        _wait->add(-0.25, -0.25, 0, 0);
        _wait->config(_glsl);
    }

    return 1;
}


/* Function called by paintGL. Config ruler vbo*/
void Render_alternate::call_ruler(){
    _ruler.setNbVertex(0);
    Element_pos graduation_diff;
    //Element_pos coeff_prefix;
    const Element_pos offset_x = _default_entity_x_translate;

    update_visible_interval_value();

    graduation_diff = Ruler::get_graduation_diff(Info::Render::_x_min_visible, Info::Render::_x_max_visible);
    //coeff_prefix    = Ruler::get_coeff_for_common_prefix(Info::Render::_x_min_visible, Info::Render::_x_max_visible);
    //draw quads
    set_color(0.0, 0.0, 1.0);
    _ruler.add(trace_to_render_x(Info::Render::_x_min_visible), 3, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_min_visible), 8, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_max_visible), 8, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_max_visible), 8, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_max_visible), 3, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_min_visible), 3, _r, _g, _b);
    set_color(0.0, 0.0, 0.0);
    _ruler.add(trace_to_render_x(Info::Render::_x_min_visible), 0, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_min_visible), 3, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_max_visible), 3, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_max_visible), 3, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_max_visible), 0, _r, _g, _b);
    _ruler.add(trace_to_render_x(Info::Render::_x_min_visible), 0, _r, _g, _b);

    //draw graduations
    set_color(1.0, 1.0, 1.0);

    for (Element_pos i = Info::Render::_x_min_visible ; i < Info::Render::_x_max_visible ; i+=graduation_diff){
        const Element_pos grad_div_by_5 = graduation_diff/5;
        for (Element_pos j = (i+grad_div_by_5) ; j<(i+graduation_diff) ; j+= grad_div_by_5){
            draw_line( trace_to_render_x(j) + offset_x, 3,
                       trace_to_render_x(j) + offset_x, 5.5, _z_ruler);
        }

        draw_line( trace_to_render_x(i) + offset_x, 3,
                   trace_to_render_x(i) + offset_x, 8, _z_ruler);
    }

    return;
}



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

void Render_alternate::draw_text(const Element_pos x, const Element_pos y, const Element_pos size, const std::string s){
    if (_draw_ruler) return;/* do not draw text for ruler */
    Container_text_ buf;
    buf.x     = x;
    buf.y     = render_to_trace_y(y);/* Cancel previous transformation. */
    buf.value = s;
    buf.size = size;
    _texts.push_back(buf);
}

void Render_alternate::draw_quad(Element_pos x, Element_pos y, Element_pos z, Element_pos w, Element_pos h){
    checkGlError();
    Element_pos offset_x;
    const Element_pos offset_y = -_ruler_y - _ruler_height;

    offset_x = 0;
    if(_draw_container){
        _containers.add(x+offset_x  , y+offset_y  , _r,_g,_b);
        _containers.add(x+offset_x+w, y+offset_y  , _r,_g,_b);
        _containers.add(x+offset_x+w, y+offset_y+h, _r,_g,_b);
        _containers.add(x+offset_x+w, y+offset_y+h, _r,_g,_b);
        _containers.add(x+offset_x  , y+offset_y+h, _r,_g,_b);
        _containers.add(x+offset_x  , y+offset_y  , _r,_g,_b);
    }
    else if(_draw_states){
        offset_x = -_default_entity_x_translate;
        if(_glsl<330) { //float for color gradient
            _current->add( x+offset_x,   y+offset_y,   2.0f );
            _current->add( x+offset_x+w, y+offset_y,   1.0f );
            _current->add( x+offset_x+w, y+offset_y+h, 1.0f );
            _current->add( x+offset_x+w, y+offset_y+h, 1.0f );
            _current->add( x+offset_x,   y+offset_y+h, 2.0f );
            _current->add( x+offset_x,   y+offset_y,   2.0f );
        }
        else{ //char for color gradient
            char c1 = 1;
            char c2 = 2;
            _current->add(x+offset_x,   y+offset_y,   c2);
            _current->add(x+offset_x+w, y+offset_y,   c1);
            _current->add(x+offset_x+w, y+offset_y+h, c1);
            _current->add(x+offset_x+w, y+offset_y+h, c1);
            _current->add(x+offset_x,   y+offset_y+h, c2);
            _current->add(x+offset_x,   y+offset_y,   c2);
        }
    }
    else if(_draw_ruler){
    }
    checkGlError();

    (void)z;
}

void Render_alternate::draw_triangle(Element_pos , Element_pos ,
                                     Element_pos , Element_pos ){
}

void Render_alternate::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.add(x1+offset_x,y1+offset_y);//,_r,_g,_b);
        _counters.add(x2+offset_x,y2+offset_y);//,_r,_g,_b);
    }
    else if(_draw_ruler){
        _ruler.add(x1+offset_x, y1, _r, _g, _b);
        _ruler.add(x2+offset_x, y2, _r, _g, _b);
    }

    (void)z;
}

void Render_alternate::draw_circle(Element_pos /*x*/, Element_pos /*y*/, Element_pos /*z*/, Element_pos /*r*/){
}


void Render_alternate::start_draw(){
    _draw_ruler = false;
    _draw_container = false;
    _draw_arrow = false;
    _draw_event = false;
}

void Render_alternate::start_draw_containers(){
    _draw_container = true;
    Shader *s = new Shader(_glsl);
    s->charger();
    _containers.set_shader(s);
    _containers.setNbVertex(0);
}

void Render_alternate::draw_container(const Element_pos , const Element_pos , const Element_pos , const Element_pos ){
}

void Render_alternate::draw_container_text(const Element_pos , const Element_pos , const std::string &){
}

void Render_alternate::end_draw_containers(){
    _draw_container = false;
    checkGlError();
    _containers.config(_glsl);
    checkGlError();
}

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

void Render_alternate::draw_state( const Element_pos x,
                                   const Element_pos y,
                                   const Element_pos z,
                                   const Element_pos w,
                                   const Element_pos h,
                                   EntityValue *value )
{
    if( _states.count(value) == 0 ) { //if there is no vbo corresponding to value
        //we create a new vbo and a new shader corresponding to the current color*/
        Shader *s = new Shader(_glsl, _r, _g, _b, true);
        s->charger();
        //assert(value); // TODO: check why busy state exists and uncomment this assert
        Vbo *v = new Vbo(s);
        std::pair<EntityValue*, Vbo*> p2(value, v);
        _states.insert(p2);

        connect( value, SIGNAL(changedColor( EntityValue * )),
                 this, SLOT(update_ev( EntityValue *)) );
    }
    //add the state to the vbo
    _current = _states[value];
    draw_quad(x, y, z, w, h);
}

void Render_alternate::end_draw_states(){

    _draw_states = false;
    std::map<EntityValue*, Vbo*>::iterator it;
    it = _states.begin();
    while(it!=_states.end()){
        //std::cout << it->first->get_name().get_name() << std::endl;
        it->second->config(_glsl);
        it++;
    }
    checkGlError();
}

void Render_alternate::start_draw_arrows(){
    _draw_arrow = true;
}

void Render_alternate::draw_arrow( const Element_pos start_time,
                                   const Element_pos end_time,
                                   const Element_pos start_height,
                                   const Element_pos end_height,
                                   const Element_col red,
                                   const Element_col green,
                                   const Element_col blue,
                                   EntityValue* value)
{
    if(_arrows.count(value) == 0){ //if there is no vbo corresponding to value
        /* Create a new vbo and a new shader*/
        Shader *s = new Shader(_glsl, _r, _g, _b, false);
        s->charger();
        Vbo* v1 = new Vbo(s);
        Vbo* v2 = new Vbo(s);
        std::pair<Vbo*, Vbo*> p1(v1, v2);
        std::pair<EntityValue*, std::pair<Vbo*, Vbo*> > p2(value, p1);
        _arrows.insert(p2);
        std::vector<Element_pos> v;
        std::pair<EntityValue*, std::vector<Element_pos> > p3(value, v);
        _links.insert(p3);

        connect( value, SIGNAL(changedColor( EntityValue * )),
                 this, SLOT(update_ev( EntityValue *)) );
    }
    //store data in vbo
    const Element_pos offset_x = -_default_entity_x_translate;
    const Element_pos offset_y = -_ruler_y - _ruler_height;
    Element_pos x0, x1, y0, y1, l, alpha, cosa, sina;
    x0 = start_time   + offset_x;
    x1 = end_time     + offset_x;
    y0 = start_height + offset_y;
    y1 = end_height   + offset_y;
    //size of the arrow
    l = sqrt(pow(x1-x0,2)+pow(y1-y0,2));
    //calculate angle beetween arrow and horizontal axe
    cosa = (x1-x0)/l;
    sina = (y1-y0)/l;
    alpha = acos(cosa);
    if(sina<0) alpha*= -1;
    _current = _arrows[value].first;
    _current->add(x0, y0);
    _current->add(x1, y1);
    _current = _arrows[value].second;
    _current->add(x1, y1);
    /* Need this to draw triangles heads. Necessary for matrix operations*/
    std::vector<Element_pos> *v = &_links[value];
    v->push_back(x1);
    v->push_back(y1);
    v->push_back(alpha);

    (void)red;
    (void)green;
    (void)blue;
}

void Render_alternate::end_draw_arrows(){
    //coordinates that we use for draw the head all arrows when parameter arrows_shape is triangle, we will change the angle and scale of using the modelview matrix
    _draw_arrow = false;
    _arrows3.add(0,0,1,1,1);
    _arrows3.add(-1.2, -0.4, 1, 1, 1);
    _arrows3.add(-1.2, 0.4, 1, 1, 1);
    _arrows3.setNbVertex(3);
    //send datas to vbo
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it = _arrows.begin();
    while(it != _arrows.end()){
        it->second.first->config(_glsl);
        it->second.second->config(_glsl);
        it++;
    }
    //_arrows.config(_glsl);
    //_arrows2.config(_glsl);
    _arrows3.config(_glsl);
    checkGlError();
}

void Render_alternate::start_draw_events(){
    _draw_event = true;
}

void Render_alternate::draw_event(const Element_pos time, const Element_pos height,  const Element_pos container_height, EntityValue* value){
    if(_events.count(value) == 0){
        Shader *s = new Shader(_glsl, _r, _g, _b, false);
        s->charger();
        Vbo* v1 = new Vbo(s);
        Vbo* v2 = new Vbo(s);
        std::pair<Vbo*, Vbo*> p1(v1, v2);
        std::pair<EntityValue*, std::pair<Vbo*, Vbo*> > p2(value, p1);
        _events.insert(p2);

        connect( value, SIGNAL(changedColor( EntityValue * )),
                 this, SLOT(update_ev( EntityValue *)) );
    }
    const Element_pos offset_x = -_default_entity_x_translate;
    const Element_pos offset_y = -_ruler_y - _ruler_height;
    _current = _events[value].first;
    _current->add(time+offset_x, height + offset_y);
    _current = _events[value].second;
    _current->add(time+offset_x, height + offset_y);
    _current->add(time+offset_x, height+offset_y+container_height/2);
}


void Render_alternate::end_draw_events(){
    _draw_event = false;
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it = _events.begin();
    while(it != _events.end()){
        it->second.first->config(_glsl);
        it->second.second->config(_glsl);
        it++;
    }
    _draw_event = false;
    checkGlError();
}

void Render_alternate::start_draw_counter(){
    _draw_counter = true;
    /* create shader for counters : all vertex are white */
    Shader *s = new Shader(_glsl, 1, 1, 1, false);
    s->charger();
    _counters.set_shader(s);
}

void Render_alternate::draw_counter(const Element_pos , const Element_pos ){
}

void Render_alternate::end_draw_counter(){
    _draw_counter = false;
    _counters.config(_glsl);
    checkGlError();
}

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

void Render_alternate::end_ruler(){
    checkGlError();
    _draw_ruler = false;
}

void Render_alternate::end_draw(){
    checkGlError();
}


void Render_alternate::draw_stored_texts(){
}

void Render_alternate::draw_stored_arrows(){
}

void Render_alternate::draw_stored_circles(){
}

void Render_alternate::release(){
}

void Render_alternate::draw_text_value(long int id,double text, double y){
    if(y!=-1){
        Variable_text_ buf;
        buf.y=y;
        buf.value=text;
        // printf("adding %f at %f for %p\n", text, y, (void*)id);
        _variable_texts[id]=buf;
    }else{
        //it's an update
        Variable_text_ buf=_variable_texts[id];
        buf.value=text;
        //printf("updating %f at %f for %p\n", text, y, (void*)id);
        _variable_texts[id]=buf;
    }
}


void Render_alternate::show_minimap(){
}

/*!
 * \brief draws the vertical helper line
 */

void Render_alternate::draw_vertical_line(){
    glm::mat4 mvp;
    if(vertical_line==0)
        return;
    _time_line.add(trace_to_render_x(vertical_line), 0.0, 1.0, 0.0, 0.0);
    _time_line.add(trace_to_render_x(vertical_line), Info::Render::height, 1.0, 0.0, 0.0);
    _time_line.config(_glsl);
    _time_line.lock();
    mvp = _projection * _modelview;
    checkGlError();
    glUniformMatrix4fv(glGetUniformLocation(_shader->getProgramID(), "MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
    glDrawArrays(GL_LINES, 0, 2);
    _time_line.unlock();
    checkGlError();
}

/*!
 * \brief slot connected to the simple click event
 */
void Render_alternate::update_vertical_line(){
    if (_mouse_pressed_inside_container)
        set_vertical_line(0);
    else
        set_vertical_line(render_to_trace_x( screen_to_render_x(_mouse_x)));
    updateGL();
}

/*!
 * \brief set the vertical line offset
 * \param l the line offset.
 */
void Render_alternate::set_vertical_line(Element_pos new_coord){
    if(new_coord==vertical_line)vertical_line=0;
    else vertical_line=new_coord;
}

Element_pos Render_alternate::get_vertical_line(){
    return vertical_line;
}

void Render_alternate::clear_text (){
    _texts.clear();
    _variable_texts.clear();
}

/* Change the shader associated to entityType entity */
void
Render_alternate::update_ev_single( EntityValue *ev,
                                    std::map<EntityValue*, Vbo*> *evmap,
                                    bool shaded )
{
    std::map<EntityValue*, Vbo*>::iterator it;

    it = evmap->find( ev );
    if ( it != evmap->end() ) {
        Vbo   *vbo = it->second;
        Color *c = ev->get_used_color();

        //delete previous shader
        vbo->delete_shader();

        //create and load the new shader*/
        Shader *s = new Shader(_glsl,
                               c->get_red(),
                               c->get_green(),
                               c->get_blue(),
                               shaded );
        s->charger();
        vbo->set_shader(s);
    }
}

void
Render_alternate::update_ev_couple( EntityValue *ev,
                                    std::map<EntityValue*, std::pair<Vbo*, Vbo*> > *evmap,
                                    bool shaded )
{
    std::map< EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it;

    it = evmap->find( ev );
    if ( it != evmap->end() ) {
        Vbo   *vbo1 = it->second.first;
        Vbo   *vbo2 = it->second.second;
        Color *c = ev->get_used_color();

        //delete previous shader
        vbo1->delete_shader();

        //create and load the new shader*/
        Shader *s = new Shader(_glsl,
                               c->get_red(),
                               c->get_green(),
                               c->get_blue(),
                               shaded );
        s->charger();
        vbo1->set_shader(s);
        vbo2->set_shader(s);
    }
}


void
Render_alternate::update_ev( EntityValue *ev )
{
    EntityClass_t ec = ev->get_class();

    switch( ec ) {
    case _EntityClass_Variable:
        // NOT handled for now
        break;

    case _EntityClass_State:
        update_ev_single( ev, &_states, true );
        break;

    case _EntityClass_Event:
        update_ev_couple( ev, &_events, false );
        break;

    case _EntityClass_Link:
        update_ev_couple( ev, &_arrows, false );
    }
}

/* Change the shader associated to entityType entity */
void Render_alternate::change_color(const std::string &entity,
                                    Element_col r,
                                    Element_col g,
                                    Element_col b)
{
    std::map<EntityValue*, Vbo*>::iterator it;
    it = _states.begin();
    while(it != _states.end()){
        //assert(it->first); // TODO: check why busy state exists and uncomment this assert
        if(it->first && (it->first->get_name() == entity)){ //if we find a shader corresponding to parameter entity
            Color *c = new Color(r, g, b);
            it->first->set_used_color(c);
            //delete previous shader
            it->second->delete_shader();
            //create and load the new shader*/
            Shader *s = new Shader(_glsl, r, g, b, true);
            s->charger();
            it->second->set_shader(s);
            break;
        }
        it++;
    }
}

/*Same operating mode as change_color */
void Render_alternate::change_event_color(const std::string &event, Element_col r, Element_col g, Element_col b){
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it;
    it = _events.begin();
    while(it != _events.end()){
        //assert(it->first); // TODO: check why busy state exists and uncomment this assert
        if(it->first && (it->first->get_name() == event)){
            Color *c = new Color(r, g, b);
            it->first->set_used_color(c);
            it->second.first->delete_shader();
            Shader *s = new Shader(_glsl, r, g, b, false);
            s->charger();
            it->second.first->set_shader(s);
            it->second.second->set_shader(s);
            break;
        }
        it++;
    }
}
/*Same operating mode as change_color */
void Render_alternate::change_link_color(const std::string &link, Element_col r, Element_col g, Element_col b){
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it;
    it = _arrows.begin();
    while(it != _arrows.end()){

        //assert(it->first); // TODO: check why busy state exists and uncomment this assert
        if(it->first && (it->first->get_name() == link)){
            Color *c = new Color(r, g, b);
            it->first->set_used_color(c);
            it->second.first->delete_shader();
            Shader *s = new Shader(_glsl, r, g, b, false);
            s->charger();
            it->second.first->set_shader(s);
            it->second.second->set_shader(s);
            break;
        }
        it++;
    }
}

void Render_alternate::change_visible(const std::string &entity, bool visible){
    std::map<EntityValue*, Vbo*>::iterator it;
    it = _states.begin();
    while(it != _states.end()){
        //assert(it->first); // TODO: check why busy state exists and uncomment this assert
        if(it->first && (it->first->get_name() == entity)){
            it->first->set_visible(visible);
            break;
        }
        it++;
    }
}

void Render_alternate::change_event_visible(const std::string &event, bool visible){
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it;
    it = _events.begin();
    while(it != _events.end()){
        //assert(it->first); // TODO: check why busy state exists and uncomment this assert
        if(it->first && (it->first->get_name() == event)){
            it->first->set_visible(visible);
            break;
        }
        it++;
    }
}

void Render_alternate::change_link_visible(const std::string &link, bool visible){
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it;
    it = _arrows.begin();
    while(it != _arrows.end()){
        //assert(it->first); // TODO: check why busy state exists and uncomment this assert
        if(it->first && (it->first->get_name() == link)){
            it->first->set_visible(visible);
            break;
        }
        it++;
    }
}

/* reset colors to filecolors*/
void Render_alternate::reload_states(){
    std::map<EntityValue*, Vbo*>::iterator it = _states.begin();
    while(it != _states.end()){
        if(it->first){
            it->first->reload_file_color();
            it->first->set_visible(true);
            it->second->delete_shader();
            Shader* s = new Shader(_glsl, it->first->get_used_color()->get_red(),
                                   it->first->get_used_color()->get_green(),
                                   it->first->get_used_color()->get_blue(),
                                   true);
            s->charger();
            it->second->set_shader(s);
        }
        it++;
    }
}
void Render_alternate::reload_links(){
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it = _arrows.begin();
    while(it != _arrows.end()){
        if(it->first){
            it->first->reload_file_color();
            it->first->set_visible(true);
            it->second.first->delete_shader();
            Shader* s = new Shader(_glsl, it->first->get_used_color()->get_red(),
                                   it->first->get_used_color()->get_green(),
                                   it->first->get_used_color()->get_blue(),
                                   false);
            s->charger();
            it->second.first->set_shader(s);
            it->second.second->set_shader(s);
        }
        it++;
    }
}

void Render_alternate::reload_events(){
    std::map<EntityValue*, std::pair<Vbo*, Vbo*> >::iterator it = _events.begin();
    while(it != _events.end()){
        if(it->first){
            it->first->reload_file_color();
            it->first->set_visible(true);
            it->second.first->delete_shader();
            Shader* s = new Shader(_glsl, it->first->get_used_color()->get_red(),
                                   it->first->get_used_color()->get_green(),
                                   it->first->get_used_color()->get_blue(),
                                   false);
            s->charger();
            it->second.first->set_shader(s);
            it->second.second->set_shader(s);
        }
        it++;
    }
}
