/*
** 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 "common/common.hpp"
#include "common/Info.hpp"
/* -- */
//#include "render/render.hpp"

#include <GL/glew.h>
#include "render/Hook_event.hpp"

#include "render/Render_alternate.hpp"
/* -- */

#include "interface/resource.hpp"
//#include "interface/interface.hpp"
#include "render/Render.hpp"
#include "core/Core.hpp"
/* -- */

#include "vbo.hpp"


using namespace std;


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

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

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

Render_alternate::Render_alternate(Core* core, QWidget *parent, const QGLFormat& format)
    : Hook_event((Render_opengl*)this, core, parent, format){

    _arrows.clear();
    _circles.clear();
    _texts.clear();
    _vbos.clear();


    
    setAutoFillBackground(false);
}


Render_alternate::~Render_alternate(){
}

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

void  Render_alternate::initializeGL() {
    glClearColor(0.5f, 0.5f, 0.55f, 1.0f);

    glEnable(GL_DEPTH_TEST);

    glClearStencil(0);
}

void  Render_alternate::resizeGL(int width, int height) {
    glViewport(0, 0, width, height);
    
    /* update informations about widget size */
    Info::Screen::width  = width;
    Info::Screen::height = height;
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();


        
    if(DRAWING_STATE_WAITING == _state){// A wait is drawn
        glOrtho(-50, 50, -50, 50, 0, 1000);
    }else if (DRAWING_STATE_DRAWING == _state){// A trace is drawn 
        glOrtho(0, Info::Render::width, 0, Info::Render::height, 0, -1000);
    }else{
        message << tr("Undefined value for the drawing state attribute - Render area").toStdString() << Message::ende;
    }
      

    glMatrixMode(GL_MODELVIEW);
}


void  Render_alternate::paintGL(){
 
    resizeGL(Render_alternate::QGLWidget::width(), Render_alternate::QGLWidget::height());
    Render_alternate::QGLWidget::setFocus(Qt::ActiveWindowFocusReason);/* give the focus to the render area for mouse and keyboard events */

  
    glClearDepth(1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();

   
    if(DRAWING_STATE_WAITING == _state){/* A wait is drawn */
        
        /* turn around y axis */
        _wait_angle+=0.1f;
        if (_wait_angle>=360) _wait_angle=0.0f;
      
        glPushMatrix();
      
        glScalef(15, 15, 0);
      
        glRotatef(-_wait_angle,0, 1, 0);
        glRotatef(_wait_angle_y, 1, 0, 0);
        

        glPopMatrix();
	
    
    }else if (DRAWING_STATE_DRAWING == _state){/* A trace is drawn */
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glPushMatrix();
	{
            glTranslated(0.0, Info::Render::height, 100.0);
	    glRotated(180.0, 1.0, 0.0, 0.0);
	    

            glPushMatrix();
            {
                
                glTranslated(_default_entity_x_translate - _x_state_translate, _ruler_y + _ruler_height - _y_state_translate, 0.0);
                glScalef(_x_state_scale, _y_state_scale, 1.0);

                for (unsigned int i=0 ; 
                     i<_vbos.size()   ;
                     i++){
                    _vbos[i]->display();
                }
            }
            glPopMatrix();                

            call_ruler();


             if (false == Info::Render::_no_arrows)/* display arrows */
                 draw_stored_arrows();
            
             if (false == Info::Render::_no_events)/* display events */
                 draw_stored_circles();
                        
        }
        glPopMatrix();

        glPushMatrix();
        {
            glTranslated(0.0,  0.0, 100.0);/* not accurate */
           
            if (_mouse_pressed){
               
               
                glTranslated(0.0, 0.0, _z_container_under);
               
                Element_pos old_x, old_y, new_x, new_y;
               
 

                old_x = _mouse_x*(Info::Render::width/Info::Screen::width);
                old_y =  Info::Render::height - _mouse_y*(Info::Render::height/Info::Screen::height);
                new_x = _new_mouse_x*(Info::Render::width/Info::Screen::width);
                new_y =  Info::Render::height - _new_mouse_y*(Info::Render::height/Info::Screen::height);

#ifdef DEBUG_MODE_RENDER_OPENGL
               
                cerr << __FILE__ << " l." << __LINE__ << ":" << endl;  
                cerr << "Selection rectangle position: (" << old_x << ", " << old_y << ") - (" << new_x << ", " << new_y << ")" << endl;  
#endif
               
                glEnable(GL_BLEND);
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
               
                /* Square for selection */
                glBegin(GL_QUADS);
                {
                    glColor4d(0.9, 1.0, 0.9, _selection_rectangle_alpha);glVertex2d(old_x, old_y);
                    glColor4d(0.9, 0.9, 0.9, _selection_rectangle_alpha);glVertex2d(old_x, new_y);
                    glColor4d(0.9, 0.9, 0.9, _selection_rectangle_alpha);glVertex2d(new_x, new_y);
                    glColor4d(0.9, 0.9, 0.9, _selection_rectangle_alpha);glVertex2d(new_x, old_y);
                }
                glEnd();
              
                glDisable(GL_BLEND);
                               
            }/* end  if (true==_mouse_pressed) */
        }
        glPopMatrix();



    }else{
        message << tr("Undefined value for the drawing state attribute - Render area").toStdString() << Message::ende;
    }
  
    glFlush();


    /* Check the errors */
    GLenum glerror;
    glerror = glGetError();
    if(glerror != GL_NO_ERROR)
        message << tr("Render area : the following OpengGL error occured: ").toStdString() << (char *)gluErrorString(glerror) << Message::endw;



    if(DRAWING_STATE_WAITING == _state)/* A wait is drawn, do not take car about the ruler drawing */
        return;

    QFont arial_font = QFont("Arial", 10);
    qglColor(Qt::white);//QColor(0, 0, 0));


    /* Draw container text */
    const unsigned int texts_size = _texts.size();
    for (unsigned int i=0 ; i<texts_size ; i++){
        const QFontMetrics metric(arial_font);
        const QString text_elided = metric.elidedText(_texts[i].value.c_str(), Qt::ElideRight, _x_scale_container_state*Info::Screen::width/3.);
        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);
    }

    /* 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);

    //    painter.setFont(QFont("Arial", 14));

    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);

    arial_font.setPointSize(10);

    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);
    }      
}





/***********************************
 *
 *
 *
 * Building functions.
 *
 *
 *
 **********************************/



bool Render_alternate::build(){
    
    _state = DRAWING_STATE_DRAWING;/* change the drawing state */

    /* disable some OpenGL features to enhance the rendering */
    glDisable(GL_TEXTURE_2D);
    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 */
 
    if (NULL == _render_instance)
        return true;

    return true;
}



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_TEXTURE_2D);

    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 */

    _wait_angle=0.0f;/* begin with 0 rad angle */
    _wait_angle_y=0.0f;/* begin with 0 rad angle */

    /* init measurement attributes */    
    Info::Container::x_max = 0;
    Info::Container::y_max = 0;
    Info::Container::x_min = 0;
    Info::Container::y_min = 0;

    //    Info::Render::_ui_render_min_value->setText("");
    // Info::Render::_ui_render_max_value->setText("");

    Info::Entity::x_max = 0;
    Info::Entity::x_min = 0;
    //    _state_x_max = 0;
    _state_y_max = 0;
    //    _state_x_min = 0;
    _state_y_min = 0;

    /* clear lists to store container texts */
    _text_pos.clear();
    _text_value.clear();

    _arrows.clear();
    _circles.clear();
    _texts.clear();

    for (unsigned int i=0 ; 
         i<_vbos.size()   ;
         i++){
        delete _vbos[i];
    }
    _vbos.clear();

    /* clear the event vector */
    // _events.clear();

    /* clear the arrow vector */
    // _arrows.clear();
    
    /* empty the selection stack */
    while(false == _previous_selection.empty())
        _previous_selection.pop();

    if (NULL == _render_instance)
        return true;

    /* Now, timer is set */
    if (_wait_timer == NULL){
        _wait_angle = 0.0f;
        
        /*  _wait_timer = new QTimer(this);
        connect(_wait_timer, SIGNAL(timeout()), _render_instance, SLOT(updateGL()));
        _wait_timer->start(_wait_spf);*/
    }


    return true;//_render_instance->display_unbuild();
}





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



GLuint Render_alternate::draw_wait() {
    GLuint object;
    GLuint texture;

    glGenTextures(1, &texture);/* create the texture and link it with the list previously created */   
    
    QFile texture_file(QString(":/img/img/logo") +  QDate::currentDate().toString("MMdd") + QString(".png"));
  
    if (true == texture_file.exists())/* The texture exists */
        texture = bindTexture(QPixmap(texture_file.fileName()), GL_TEXTURE_2D);
    else/* use the default picture */
        texture = bindTexture(QPixmap(":/img/img/logo.png"), GL_TEXTURE_2D);

   
    /* apply some parameters on the texture */
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   
    glEnable(GL_TEXTURE_2D);

    glEnable(GL_BLEND);/* enable blending for the alpha color */ 
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  
    /* Now, timer is set */
    if (_wait_timer == NULL){
        _wait_angle = 0.0f;
        /*
        _wait_timer = new QTimer(this);
        connect(_wait_timer, SIGNAL(timeout()), _render_instance, SLOT(updateGL()));
        _wait_timer->start(_wait_spf);*/
    }

    return object;
}





void Render_alternate::call_ruler(){
    Element_pos graduation_diff;
    Element_pos coeff_prefix;
    const Element_pos offset_x = _default_entity_x_translate;
    const Element_pos offset_y = _ruler_y + _ruler_height+3.5;

    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);
    
    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, offset_y  ,
                       trace_to_render_x(j) + offset_x, 2+offset_y, _z_ruler);
        }

        draw_line( trace_to_render_x(i) + offset_x, offset_y-1  ,
                   trace_to_render_x(i) + offset_x, 4+offset_y, _z_ruler);
    }
    
    glBegin(GL_QUADS);
    {
        glColor4d(0.0, 0.0, 1.0, 0.8);
        glVertex3d(trace_to_render_x(Info::Render::_x_min_visible) , 0, _z_ruler_under );
        glVertex3d(trace_to_render_x(Info::Render::_x_min_visible) , 8, _z_ruler_under );
        glVertex3d(trace_to_render_x(Info::Render::_x_max_visible) , 8, _z_ruler_under );
        glVertex3d(trace_to_render_x(Info::Render::_x_max_visible) , 0, _z_ruler_under );
    }
    glEnd();
    
    glBegin(GL_QUADS);
    {
        glColor4d(0.0, 0.0, 0.0, 1.0);
        glVertex3d(trace_to_render_x(Info::Render::_x_min_visible) , 0, _z_ruler_over );
        glVertex3d(trace_to_render_x(Info::Render::_x_min_visible) , 3, _z_ruler_over );
        glVertex3d(trace_to_render_x(Info::Render::_x_max_visible) , 3, _z_ruler_over );
        glVertex3d(trace_to_render_x(Info::Render::_x_max_visible) , 0, _z_ruler_over );
    }
    glEnd();
         
    return;
}    



void Render_alternate::set_color(float r, float g, float b){
    _red = r;
    _green = g;
    _blue = b;
}

void Render_alternate::draw_text(const Element_pos x, const Element_pos y, const Element_pos, 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;

        _texts.push_back(buf);
}


void Render_alternate::draw_quad(Element_pos x, Element_pos y, Element_pos z, Element_pos w, Element_pos h){
    int state;
    Element_pos data[8];

    Element_pos offset_x;
    const Element_pos offset_y = -_ruler_y - _ruler_height;

    offset_x = 0;

    if (!_draw_container)
        offset_x = -_default_entity_x_translate;

    data[0] = x + offset_x;
    data[1] = y + offset_y;
    data[2] = x + offset_x; 
    data[3] = y + h + offset_y;
    data[4] = x + w + offset_x;
    data[5] = y + h + offset_y;
    data[6] = x + w + offset_x;
    data[7] = y + offset_y;

    state = Vbo::VBO_OK;

    if(NULL != _current_vbo)
        state = _current_vbo->add(8, data);

    if (Vbo::VBO_OUT_OF_MEMORY == state){
        /* Store the current vbo */
        _vbos.push_back(_current_vbo); 
        
        /* Create a new vbo */
        _current_vbo = NULL;/* DO NOT DEALLOCATE BEFORE! */
        _current_vbo = new Vbo(100000, _current_vbo->QUADS);

        if (NULL == _current_vbo)
            message << tr("Cannot create a Vbo for states.").toStdString() << Message::ende;
    }

    /*
    glBegin(GL_QUADS);
    {
        glColor3d(_red, _green, _blue);
        glVertex3d(x + offset_x    , y + offset_y    , z        );
        glVertex3d(x + offset_x    , y + h + offset_y, z        );
        glColor3d(_red/1.5         , _green/1.5      , _blue/1.5);
        glVertex3d(x + w + offset_x, y + h + offset_y, z        );
        glVertex3d(x + w + offset_x, y + offset_y    , z        );
    }
    glEnd();*/
}

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){
    if (_draw_ruler || _draw_arrow || _draw_event) return;/* do not draw line for ruler or for arrow or for event */


    const Element_pos offset_x = -_default_entity_x_translate;
    const Element_pos offset_y = -_ruler_y - _ruler_height;

    glBegin(GL_LINES);
    {
        glColor3d(_red, _green, _blue);
        glVertex3d(x1 + offset_x, y1 + offset_y, z);
        glVertex3d(x2 + offset_x, y2 + offset_y, z);
    }
    glEnd();
}

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


void Render_alternate::start_draw(){
    /* Init GLEW */
    glewInit();
    _draw_ruler = false;
    _draw_container = false;
    _draw_arrow = false;
    _draw_event = false;

    _current_vbo = NULL;
   
}

void Render_alternate::start_draw_containers(){
    _list_containers = glGenLists(1);/* create the list */
    if (_list_containers == 0) {
        *Message::get_instance() << tr("Error when creating list.").toStdString() << Message::endw;
    }
    
    glNewList(_list_containers, GL_COMPILE);/* open the list */
    _draw_container = true;
}

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;
    glEndList();/* close the list */
}

void Render_alternate::start_draw_states(){
    _current_vbo = NULL;
    _current_vbo = new Vbo((1<<20), _current_vbo->QUADS);/* Allocate 1 MiB */

    if (NULL == _current_vbo)
        message << tr("Cannot create a Vbo for states.").toStdString() << Message::ende;
}

void Render_alternate::draw_state(const Element_pos , const Element_pos , const Element_pos , const Element_pos , const Element_col , const Element_col , const Element_col ){
}

void Render_alternate::end_draw_states(){

    _vbos.push_back(_current_vbo);
}

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){

    Arrow_ buf;
    const Element_pos offset_x = -_default_entity_x_translate;
    const Element_pos offset_y = -_ruler_y - _ruler_height;

    buf.start_time   = start_time   + offset_x;
    buf.end_time     = end_time     + offset_x;
    buf.start_height = start_height + offset_y;
    buf.end_height   = end_height   + offset_y;
    buf.red          = red;
    buf.green        = green;
    buf.blue         = blue;

    _arrows.push_back(buf);
}

void Render_alternate::end_draw_arrows(){
    _draw_arrow = false;
}

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){
    Event_ buf;
    const Element_pos offset_x = -_default_entity_x_translate;
    const Element_pos offset_y = -_ruler_y - _ruler_height;

    buf.time             = time   + offset_x;
    buf.height           = height + offset_y;
    buf.container_height = container_height   + offset_y;
    buf.red              = _red;
    buf.green            = _green;
    buf.blue             = _blue;

    _circles.push_back(buf);
}


void Render_alternate::end_draw_events(){
    _draw_event = false;
}

void Render_alternate::start_draw_counter(){
}

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

void Render_alternate::end_draw_counter(){
}

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

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

void Render_alternate::end_draw(){
}


void Render_alternate::draw_stored_texts(){
}

void Render_alternate::draw_stored_arrows(){

    /* Only draw triangle. Lines are already in a display list */
    const Element_pos coeff = 180.0f/M_PI;
    Element_pos angle;
    Element_pos start_time, end_time, start_height, end_height;
    Element_pos scaled_start_time, scaled_end_time, scaled_start_height, scaled_end_height;



    const unsigned int arrow_size = _arrows.size();
    for (unsigned int i=0 ; i<arrow_size ; i++){
        
        start_time   = _arrows[i].start_time;// + _x_state_scale*_x_state_translate;
        end_time     = _arrows[i].end_time;// + _x_state_scale*_x_state_translate;
        start_height = _arrows[i].start_height;
        end_height   = _arrows[i].end_height;

        set_color(_arrows[i].red, _arrows[i].green, _arrows[i].blue);
        
        scaled_start_time   = start_time   * _x_state_scale;
        scaled_end_time     = end_time     * _x_state_scale;
        scaled_start_height = start_height * _y_state_scale;
        scaled_end_height   = end_height   * _y_state_scale;

        glPushMatrix();
        {
            
            glTranslated(_default_entity_x_translate + _x_state_scale*end_time - _x_state_translate, 
                         _ruler_y + _ruler_height + _y_state_scale*end_height - _y_state_translate,
                         _z_arrow);

            if (start_time != end_time){
                angle = atan2((scaled_end_height - scaled_start_height), (scaled_end_time - scaled_start_time))*coeff;/* arc tangent */
                glRotatef(angle, 0, 0, 1);
            }
            else
                glRotatef(90, 0, 0, 1);/* vertical alignment */
       
            glBegin(GL_TRIANGLES);
            {
                // glColor3d(_red, _green, _blue);
                glVertex2d(0.0, 0.0);
                glVertex2d(-1.2, -0.4);
                glVertex2d(-1.2, 0.4);
            }
            glEnd();
        
        }
        glPopMatrix();

        glPushMatrix();
        {
            
            glTranslated(_default_entity_x_translate - _x_state_translate,
                         _ruler_y + _ruler_height - _y_state_translate,
                         _z_arrow);
            glScalef(_x_state_scale, _y_state_scale, 1.0);
     
            glBegin(GL_LINES);
            {
                glVertex2d(start_time, start_height);
                glVertex2d(end_time  , end_height  );
            }
            glEnd();
        }
        glPopMatrix();
    }
}

void Render_alternate::draw_stored_circles(){
    const int step          = 20;/* 20 polygons for the circle */
    const float angle       = M_PI/2.0f;
    const float delta_angle = 2*M_PI/step;
    const float radius = .5f;

    const unsigned int size = _circles.size();

    for (unsigned int i=0 ; i<size ; i++){
 
        glPushMatrix();
        {

            set_color(1.0 - _circles[i].red, 1.0 - _circles[i].green, 1.0 - _circles[i].blue); 
                      
            glTranslated(_default_entity_x_translate - _x_state_translate,
                         _ruler_y + _ruler_height - _y_state_translate,
                         _z_arrow);
          
             glScalef(_x_state_scale, _y_state_scale, 1.0); 
       
             /* Draw the circle */
                
             glBegin(GL_POLYGON);
             {
                 for(int j = 0 ; j < step ; j ++){
                     glVertex2d(_circles[i].time + cos(angle+delta_angle*j)*radius/_x_state_scale,
                                _circles[i].height + sin(angle+delta_angle*j)*(radius/_y_state_scale)*Info::Screen::width/Info::Screen::height);                 
                 }
             }
             glEnd();
             

             set_color(_circles[i].red, _circles[i].green, _circles[i].blue); 
             
             /* Draw the sub-circle */
             glBegin(GL_POLYGON);
             {
                 for(int j = 0 ; j < step ; j ++){
                     glVertex3d(_circles[i].time + cos(angle+delta_angle*j)*radius/(1.2*_x_state_scale) ,
                                _circles[i].height + sin(angle+delta_angle*j)*radius/(1.2*_y_state_scale)*Info::Screen::width/Info::Screen::height , 
                                0.1);
                 }
             }
             glEnd();
             
           
             glLineWidth( 3.0 );
            /* Draw the line */
             glBegin(GL_LINES);
            {
                glVertex2d(_circles[i].time, _circles[i].height);
                glVertex2d(_circles[i].time, _circles[i].height+_circles[i].container_height);
            }
            glEnd();

            glLineWidth( 1.0 );


        }
        glPopMatrix();
    }

    set_color(1.0, 1.0, 1.0);
  
}
    
