/*
** 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 Hook_event.cpp
 */

#include <stack>
#include <sstream>
/* -- */
#include <QMessageBox>
#include <QMouseEvent>
#include <QGLWidget>
#include <QTimer>
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
/* -- */
#include "interface/Interface.hpp"
#include "core/Core.hpp"
/* -- */
#include "common/Message.hpp"
/* -- */
#include "render/Geometry.hpp"
#include "render/Render_template.hpp"
#include "render/Render_opengl.hpp"
#include "render/Hook_event.hpp"
/* -- */
using namespace std;

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


#ifdef WIN32
#define getTimeClick() GetDoubleClickTime()
#else
#define getTimeClick() 200/*
#include "X11/Intrinsic.h"
#include <QX11Info>

#define getTimeClick() try{\
XtGetMultiClickTime(((QWidget*)this->parent())->x11Info().display());\
}catch(char* e){\
printf("%s \n", e);\
}*/
#endif


const int Hook_event::DRAWING_STATE_WAITING = 1;
const int Hook_event::DRAWING_STATE_DRAWING = 2;
const int Hook_event::_ctrl_scroll_factor = 10;
const int Hook_event::_ctrl_zoom_factor = 3;
static const Element_pos zoom_limit = 0.000001;/* Use to control the minimum distance between
                                                   the minimum x visible and the maximum x visible. */
static const int scroll_margin = 100;/* Control the margin of the trace. Must be in percentage. 
                                (i.e. between [0; 100]) */

void Hook_event::updateRender(){
    //    _render_instance->updateOverlayGL();
    _render_instance->updateGL();
    //_render_instance->paintEvent(NULL);
}


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

Hook_event::Hook_event(Render_opengl* render_instance, Core* core, QWidget *parent, const QGLFormat& format)
    : QGLWidget(format, parent), _core(core) {
 

    //  GLenum glew_code;


    if (!QGLFormat::hasOpenGL ()){
        QMessageBox::information(0, tr("ViTE: Fatal OpenGL error"), tr("This system does not support OpenGL."));
    }

    /*   if (!QGLFormat::hasOpenGLOverlays () ) {
        message <<  tr("Render OpenGL: overlay is not supported!").toStdString() << Message::endw;  
        }*/

   //  makeCurrent();/* need to "enable" glew */

//     glew_code = glewInit();/* use for VBO and shaders */
    
//     if(GLEW_OK != glew_code){
//         message << "Cannot initialize GLEW: " << glewGetErrorString(glew_code) << Message::ende;
//     }
    
//     /*Check if VBO is supported */
//     if (GL_FALSE == glewIsSupported("GL_ARB_vertex_buffer_object")){
//         message << "VBO OpenGL extension is not supported by your graphic card." << Message::ende;
//     }   


    _render_instance = render_instance;    
    
    _state = DRAWING_STATE_WAITING;/* At the beginning, no trace is drawing */
   
    /* init main informations about OpenGL scene and QGLWidget size */

    Info::Screen::width  = width();  /* get the QGLWidget visibled width (in pixel)  */
    Info::Screen::height = height(); /* get the QGLWidget visibled height (in pixel) */

    _ruler_distance = 5;

    _mouse_x                        = 0;
    _mouse_y                        = 0;
    _new_mouse_x                    = 0;
    _new_mouse_y                    = 0;
    _mouse_pressed                  = false;
    _mouse_pressed_inside_container = false;
    _mouse_pressed_inside_ruler     = false;
    _key_scrolling                  = false;

    _minimum_distance_for_selection = 5;/* 5 pixels */

    _selection_rectangle_alpha = 0.5;


    /* Info init */
    // Info::Render::_key_alt = false;/* no CTRL key pushed */


    setAutoFillBackground(false);

    setMouseTracking (true);/* to catch mouse events */
    setFocusPolicy(Qt::StrongFocus);/* to catch keybord events (focus by tabbing or clicking) */
    
    //initialize the timer for single click handling
    _timer = new QTimer(this);
    _timer->setSingleShot(true);
    _connected=false;
    //updateRender();
   
}


Hook_event::~Hook_event(){
}




/***********************************
 *
 *
 *
 * Scaling and scrolling functions.
 *
 *
 *
 **********************************/
void Hook_event::mousePressEvent(QMouseEvent * event){
    /* Do nothing if no trace is loaded */
    if(_state == DRAWING_STATE_WAITING) {
        return;
    }

    /* If a right click was triggered, just restore the previous zoom */
    if( Qt::RightButton == event->button() ){

        /* Just a special case: if a zoom box is currently drawing, the right click is used
           to cancel the drawing */
        if ( true == _mouse_pressed){
            _mouse_pressed                  = false;
            _mouse_pressed_inside_container = false;
            _mouse_pressed_inside_ruler     = false;

            updateRender();
            return;
        }

        /* if there is no previous zoom box registered, return */
        if (true == _previous_selection.empty())
            return;

        /* restore the previous values */
        _x_state_scale = _previous_selection.top().x_scale;
        _y_state_scale = _previous_selection.top().y_scale;
        _x_state_translate = _previous_selection.top().x_translate;
        _y_state_translate = _previous_selection.top().y_translate;


        /* remove the previous value */
        _previous_selection.pop();
	
	refresh_scroll_bars(true);
       updateRender();
	

#ifdef DEBUG_MODE_RENDER_AREA_
             
        /* if there is no previous zoom box registered, return */
        if (true == _previous_selection.empty())
            return;

        cerr << __FILE__ << " l." << __LINE__ << ":" << endl;  
        cerr << _previous_selection.top().x_scale << " " 
             << _previous_selection.top().y_scale << " "
             << _previous_selection.top().x_translate << " "
             << _previous_selection.top().y_translate <<  endl << endl;
#endif

        int buf;

        buf = (int)(100*_x_state_scale);
        _core->launch_action(_core->_STATE_ZOOM_BOX_VALUE, &buf);

        /* Then, return */
        return;
    }

    /* else, registered current X and Y mouse position to draw a zoom box */

    _mouse_x = event->x();
    _new_mouse_x = _mouse_x;

    /* user had clicked on the container */
    if ( screen_to_render_x(_mouse_x) < _x_scale_container_state*Info::Render::width ){
        _mouse_pressed_inside_container = true;
        _mouse_x = render_to_screen_x(_x_scale_container_state*Info::Render::width);
    }
    

    _mouse_y = event->y();
    _new_mouse_y = _mouse_y;

    /* user had clicked on the ruler */
    if ( screen_to_render_y(_mouse_y) <= (_ruler_height+_ruler_y) ){
        _mouse_pressed_inside_ruler = true;
        _mouse_y = render_to_screen_y(_ruler_height+_ruler_y);
    }

    _mouse_pressed = true;
}


void Hook_event::mouseDoubleClickEvent ( QMouseEvent * event ){
    Element_pos x_result, y_result;/* The click coordinates for the Data Structure. */


    if(_timer->isActive()){
        _timer->stop(); 
    }
    
    if( Qt::LeftButton == event->button() ){
        x_result = render_to_trace_x(screen_to_render_x(_mouse_x));
        y_result = render_to_trace_y(screen_to_render_y(_mouse_y));

        Info::Render::_info_x = x_result;
        Info::Render::_info_y = y_result;
        Info::Render::_info_accurate = 1/coeff_trace_render_x();
        _core->launch_action(_core->_STATE_RENDER_DISPLAY_INFORMATION, NULL);
        
        _mouse_pressed = false;
        updateRender();
        
    }
}


void Hook_event::mouseMoveEvent(QMouseEvent * event){
    /* Do nothing if no trace is loaded */
    if(_state == DRAWING_STATE_WAITING || !_mouse_pressed) {
        return;
    }

    //if (_mouse_pressed_inside_container)
    //    _new_mouse_x = Info::Screen::width;
    //else
        _new_mouse_x = event->x();

    if (_mouse_pressed_inside_ruler)
        _new_mouse_y = Info::Screen::height;
    else
        _new_mouse_y = event->y();

    updateRender();
}


void Hook_event::mouseReleaseEvent(QMouseEvent * event){
    //if the timer has not been connected yet, connect it (there is a problem with QT signal/slots and genericty, and the type of this isn't right in the constructor)
    if(!_connected){
        connect(_timer, SIGNAL(timeout()), (Hook_event*)this, SLOT(update_vertical_line()));
        _connected=true;
    }
    
    /* Do nothing if no trace is loaded */
    if(_state == DRAWING_STATE_WAITING) {
        return;
    }
    
    Element_pos invert_buf_x;
    Element_pos invert_buf_y;

    Selection_ selection_stack_buf;


    /* If a right click was triggered, just restore the previous zoom */
    if( Qt::RightButton == event->button() )
        return;
        
    if(Info::Render::_key_ctrl == true && (!(_mouse_pressed_inside_ruler || _mouse_pressed_inside_container))){
    
        
        change_translate_y  (screen_to_render_y(1.5*(_new_mouse_y-_mouse_y)));
        change_translate    (screen_to_render_x(1.5*(_new_mouse_x-_mouse_x)));
        
        updateRender();
        refresh_scroll_bars(true);
        _key_scrolling = true;
        _mouse_pressed=false;
        event->accept();/* accept the event */
        
    }else if (_mouse_pressed_inside_container){
        Element_pos y1 = render_to_trace_y(screen_to_render_y(_mouse_y));
        Element_pos x1 = screen_to_render_x(_new_mouse_x) / (_x_scale_container_state*Info::Render::width);
        Element_pos y2 = render_to_trace_y(screen_to_render_y(_new_mouse_y));
        Element_pos x2 = screen_to_render_x(_new_mouse_x) / (_x_scale_container_state*Info::Render::width);
        Element_pos buf[4]={y1,y2, x1, x2};    
         _core->launch_action(_core->_STATE_SWITCH_CONTAINERS, &buf);

        _mouse_pressed=false;
        _mouse_pressed_inside_container=false;

    }else{
    if (_new_mouse_x < _mouse_x){
        invert_buf_x = _mouse_x;
        _mouse_x = _new_mouse_x;
        _new_mouse_x = (int)invert_buf_x;
    }
    
    if (_new_mouse_y < _mouse_y){
        invert_buf_y = _mouse_y;
        _mouse_y = _new_mouse_y;
        _new_mouse_y = (int)invert_buf_y;
    }

    /*
     * When the mouse is released:
     *
     * First, check if there is a significant difference between mouse coordinates. Prevent bad manipulations.
     */

    if(false==_mouse_pressed)
        return;

    if (((_new_mouse_x-_mouse_x) < _minimum_distance_for_selection)
        && ((_new_mouse_y-_mouse_y) < _minimum_distance_for_selection)){/* selection is too thin to draw a box. So, it must be a user click to display entity information */
        //start the timer to catch a click or double click
        _timer->start(getTimeClick());
		double d =render_to_trace_x( screen_to_render_x(_mouse_x));
        _core->launch_action(_core->_STATE_UPDATE_VARVALUES, &d);//update the value of the variables to display
			
        _mouse_pressed                  = false;
        _mouse_pressed_inside_container = false;
        _mouse_pressed_inside_ruler     = false;
        updateRender();
        return;/* escape */
    }

    /* Thin box in the ruler: ignore */
    if (_mouse_pressed_inside_ruler &&
        ((_new_mouse_x-_mouse_x) < _minimum_distance_for_selection) ){
		
        //start the timer to catch a click or double click
        _timer->start(getTimeClick());
   
        _mouse_pressed              = false;    
        _mouse_pressed_inside_ruler = false;
        updateRender();
        return;
    }            

    /* Thin box in the containers: ignore */
    if (_mouse_pressed_inside_container &&
        ((_new_mouse_y-_mouse_y) < _minimum_distance_for_selection) ){

		//hide the vertical line if we press inside a container
	    _render_instance->set_vertical_line(0);
		
		_render_instance->update_vertical_line();
        //start the timer to catch a click or double click
		
        _mouse_pressed                  = false;
        _mouse_pressed_inside_container = false;
        updateRender();
        return;
    }            

    /*
     * Now, user was drawing a box. Zoom in it!
     */

    
        /* Register this position which will be used by a right clic */
        selection_stack_buf.x_scale = _x_state_scale;
        selection_stack_buf.y_scale = _y_state_scale;
        selection_stack_buf.x_translate = _x_state_translate;
        selection_stack_buf.y_translate = _y_state_translate;

        _previous_selection.push(selection_stack_buf);

    #ifdef DEBUG_MODE_RENDER_AREA_
                 
            cerr << __FILE__ << " l." << __LINE__ << ":" << endl;  
            cerr << _previous_selection.top().x_scale << " " 
                 << _previous_selection.top().y_scale << " "
                 << _previous_selection.top().x_translate << " "
                 << _previous_selection.top().y_translate << endl << endl;
    #endif


          apply_zoom_box(_mouse_x, _new_mouse_x, _mouse_y, _new_mouse_y);
    }
      
}



void Hook_event::apply_zoom_box(Element_pos x_min, Element_pos x_max, Element_pos y_min, Element_pos y_max){

    Element_pos x_middle_selection;
    Element_pos y_middle_selection;
    Element_pos x_scaled_middle_selection;
    Element_pos y_scaled_middle_selection;
    Element_pos x_distance_between_state_origin_and_render_middle;
    Element_pos y_distance_between_state_origin_and_render_middle;
    Element_pos delta;
    
    /*
     * Now, we try to zoom on the selection rectangle. To perform this, the left of the selection rectangle must be fit with the left
     * of the render area. Idem for the right, the top and the bottom.
     *
     * Thus, we need to know the difference the scale between the rectangle width and height and the render area width and height.
     * Results are given by the scale: Info::Screen::width/(x_max - x_min) for the horizontal dimension.
     *
     * Then, our selection rectangle is scaled. Nevertheless, it should not be centered inside the render area. So, we work out
     * the correct x and y translation to make both the render area middle and the selection rectangle middle fit.
     * There are 3 steps for the middle x position :
     *  - First, find distance between the scaled selection rectangle middle and the state origin.
     *  - Second, find the distance between the state origin and the render area middle.
     *  - Finally, translate the scaled selection middle to the difference.
     */


    /*
     * Work out the horizontal middle of the selection area (the selection area width divide by 2 plus the x left coordinate)
     * Note: mouse positions are converted to render area coordinate with screen_to_render_**() methods.
     */
    x_middle_selection = screen_to_render_x(x_min + (x_max - x_min)/2 );
    y_middle_selection = screen_to_render_y(y_min + (y_max - y_min)/2 );
   

    /*
     * 1st step:
     *
     * Work out the new selection middle position after applying the scale.
     */
    x_scaled_middle_selection = (x_middle_selection + _x_state_translate - _default_entity_x_translate)*((Info::Screen::width*(1-_x_scale_container_state))/((x_max - x_min)));
    y_scaled_middle_selection = (y_middle_selection + _y_state_translate - _ruler_height )*((Info::Screen::height - render_to_screen_y(_ruler_height))/((y_max - y_min)));

    /*
     * 2nd step:
     *
     * Work out the distance between the state origin and the render area middle (Info::Render::width/2).
     */
    x_distance_between_state_origin_and_render_middle =  _x_state_translate + Info::Render::width*_x_scale_container_state - _default_entity_x_translate + Info::Render::width/2 - _default_entity_x_translate/2;
    y_distance_between_state_origin_and_render_middle =  _y_state_translate + (Info::Render::height - _ruler_height)/2;

    /*
     * 3rd step:
     *
     * Translate entities.
     */
    _x_state_translate +=  x_scaled_middle_selection -  x_distance_between_state_origin_and_render_middle ;
    _y_state_translate +=  y_scaled_middle_selection -  y_distance_between_state_origin_and_render_middle;


    /* 
     * Finally, perform the scale. 
     */
   
     /* NOTE: do not use replace_scale() because the translate will be also modified */
     int buf;
     _x_state_scale *= (Info::Render::width*(1-_x_scale_container_state)) / screen_to_render_x(x_max - x_min);
     


    _y_state_scale *= (Info::Render::height - _ruler_height) / screen_to_render_y(y_max - y_min);

    _mouse_pressed = false;
    _mouse_pressed_inside_container = false;
    _mouse_pressed_inside_ruler     = false;


    /* Now, check if zoom is not too much */
    update_visible_interval_value();

    delta = Info::Render::_x_max_visible - Info::Render::_x_min_visible;
    
    if ( delta <=  zoom_limit ){/* if too much, cancel */

        _x_state_scale     *= (x_max - x_min) / Info::Screen::width;
        _y_state_scale     *= (y_max - y_min) / Info::Screen::height;
        _x_state_translate -= (x_scaled_middle_selection -  x_distance_between_state_origin_and_render_middle);
        _y_state_translate -= (y_scaled_middle_selection -  y_distance_between_state_origin_and_render_middle);
    }
     #if defined(USE_ITC) && defined(BOOST_SERIALIZE)
    if(Info::Splitter::preview==true && Info::Render::_key_ctrl == true){
        //we are in preview mode, we have to load the actual data from the serialized files
        Info::Splitter::_x_min= Info::Render::_x_min_visible;
        Info::Splitter::_x_max= Info::Render::_x_max_visible;
      //  Info::Splitter::preview=false;
        _core->launch_action(_core->_LOAD_DATA, NULL);
        Info::Render::_key_ctrl =false;
       // return;
        }
    #endif
        
     buf = (int)(100*_x_state_scale);
     _core->launch_action(_core->_STATE_ZOOM_BOX_VALUE, &buf);
    /* Update render */
    updateRender();
    refresh_scroll_bars(true);
}

void Hook_event::apply_zoom_on_interval(Element_pos t1, Element_pos t2){

    Element_pos x_min = render_to_screen_x( trace_to_render_x( t1 ) );
    Element_pos x_max = render_to_screen_x( trace_to_render_x( t2 ) );
    Element_pos y_min = render_to_screen_y(_ruler_height+_ruler_y);
    Element_pos y_max = Info::Screen::height;
    
    apply_zoom_box( x_min, x_max, y_min, y_max); 
}

void Hook_event::wheelEvent(QWheelEvent * event){
     int num_degrees = event->delta() / 8;
     int num_steps = num_degrees / 15;
     Element_pos scale_coeff = num_steps;
     
     
     _mouse_x=event->globalX();
     int ctrl_factor = 1;
     
     if (event->modifiers() == Qt::CTRL) ctrl_factor *= _ctrl_zoom_factor;

     //   cerr << Info::Render::_key_alt << endl;
     if (true ==  Info::Render::_key_alt){/* Zoom on height */
         change_scale_y(scale_coeff);
     }else{ /* Zoom on time */
         change_scale(scale_coeff*ctrl_factor);
     }
    updateRender();
    event->accept();/* accept the event */
}


void Hook_event::keyPressEvent(QKeyEvent * event) {
    
    int ctrl_factor = 1;
    
    if (event->key() == Qt::Key_Alt) {
	//    cerr << "Push" << endl;
        Info::Render::_key_alt = true;
    }
    
    if (event->modifiers() == Qt::CTRL) {
        ctrl_factor *= _ctrl_scroll_factor;
	Info::Render::_key_ctrl = true;
    }
    
    switch (event->key()) {
    case Qt::Key_Left:
        /*
         * Key 'left' pressed.
         */
        change_translate(-1*ctrl_factor);
	break;
    case Qt::Key_Right:
        /*
         * Key 'right' pressed.
         */
        change_translate(1*ctrl_factor);
	break;
    case Qt::Key_Up:
	/*
         * Key 'up' pressed.
         */
        change_translate_y(-1*ctrl_factor);
	break;
    case Qt::Key_Down:
	/*
         * Key 'down' pressed.
         */
        change_translate_y(1*ctrl_factor);
	break;
    case Qt::Key_PageUp:
	/*
         * Key 'Page Up' pressed.
         */
        if (true == Info::Render::_key_alt)
            change_translate_y(-(int)Info::Render::height);
        else
            change_translate((int)Info::Render::width);
        break;
    case Qt::Key_PageDown:
	/*
         * Key 'Page Down' pressed.
         */
        if (true == Info::Render::_key_alt)
            change_translate_y((int)Info::Render::height);
        else
            change_translate(-(int)Info::Render::width);
        break;
	
    default:
	/*
	 * Unknow key pressed.
	 */
	break;
    }
    
    _key_scrolling = true;
    event->accept();/* accept the event */
}


void Hook_event::keyReleaseEvent(QKeyEvent * event){
    if (event->key() == Qt::Key_Alt) {
        Info::Render::_key_alt = false;
    }
    
    if (event->key() == Qt::Key_Control) {
	Info::Render::_key_ctrl = false;
    }
}



void  Hook_event::change_scale(Element_pos scale_coeff){
    Element_pos new_scale;

    new_scale = _x_state_scale*(1+scale_coeff*0.05);/* 5% scale */
 
    if (new_scale<1.0)
        replace_scale(1.0);
    else
        replace_scale(new_scale);
}

void  Hook_event::change_scale_y(Element_pos scale_coeff){

    Element_pos new_scale;
    
    new_scale = _y_state_scale*(1+scale_coeff*0.05);/* 5% scale */

    if (new_scale<1.0)
        _y_state_scale = 1.0;
    else
        replace_scale_y(new_scale);
}


void  Hook_event::replace_scale(Element_pos new_scale){
    int buf;
 
    if(new_scale > 0.0){
        /* 
         * Reajust the entity translation to recenter the same point previously under the mouse pointer 
         *
         * Work out the distance between the point in the middle Widget and the state origin.
         * Then multiply it by the scale coefficient ( (new_scale / old_scale) ) less 1. 
         * 1 corresponding to the original translation of the point from the state origin.
         * Finally, translate the result.
         *
         */
        _x_state_translate += ( _x_state_translate/*screen_to_render_x(_mouse_x)*/ - _default_entity_x_translate + (Element_pos)Info::Render::width/2.0) * ((new_scale)/(_x_state_scale) - 1);
        _x_state_scale = new_scale;

        buf = (int)(100*_x_state_scale);
	
        _core->launch_action(_core->_STATE_ZOOM_BOX_VALUE, &buf);
	
        
	refresh_scroll_bars(true);
    }
}

void  Hook_event::replace_scale_y(Element_pos new_scale){

    if(new_scale > 0.0){
        /* 
         * Reajust the entity translation to recenter the same point previously under the mouse pointer 
         *
         * Work out the distance between the point in the middle Widget and the state origin.
         * Then multiply it by the scale coefficient ( (new_scale / old_scale) ) less 1. 
         * 1 corresponding to the original translation of the point from the state origin.
         * Finally, translate the result.
         *
         */
        _y_state_translate += ( _y_state_translate - _ruler_height + (Element_pos)Info::Render::height/2.0) * ((new_scale)/(_y_state_scale) - 1);
        _y_state_scale = new_scale;
        	        
        /* TODO add a zoom box value for y zoom */
        updateRender();
	refresh_scroll_bars(true);
    }
}



void Hook_event::change_translate(int translate){
    replace_translate(_x_state_translate + translate);
}


void Hook_event::change_translate_y(int translate){
    replace_translate_y(_y_state_translate + translate);
}


void Hook_event::replace_translate(Element_pos new_translate){
    if ( new_translate < (-scroll_margin*_x_state_scale) ){
	new_translate = -scroll_margin*_x_state_scale;
    }else if ( new_translate > (scroll_margin*_x_state_scale) ){
	new_translate = scroll_margin*_x_state_scale;
    }
    
    _x_state_translate = new_translate;
     
    if (_key_scrolling){
	refresh_scroll_bars();
	_key_scrolling = false;
    }
    updateRender();
}


void Hook_event::replace_translate_y(Element_pos new_translate){
    if ( new_translate < (-scroll_margin*_y_state_scale) ){
	new_translate = -scroll_margin*_y_state_scale;
    }else if ( new_translate > (scroll_margin*_y_state_scale) ){
	new_translate = scroll_margin*_y_state_scale;
    }
    
    _y_state_translate = new_translate;
     
    if (_key_scrolling){
	refresh_scroll_bars();
	_key_scrolling = false;
    }
    updateRender();
}


void Hook_event::registered_translate(int id){
   
    switch (id){

    case Info::Render::X_TRACE_BEGINNING:/* show the beginning entities */
        _x_state_translate =  _default_entity_x_translate - (Element_pos)Info::Render::width/2.0;
        break;
    case Info::Render::Y_TRACE_BEGINNING:/* show the beginning entities */
        _y_state_translate = (Element_pos)Info::Render::height/2.0 - _ruler_height;
        break;
    case Info::Render::X_TRACE_ENDING:/* show the ending entities */
        //        _x_state_translate =  (_default_entity_x_translate - (Element_pos)Info::Render::width/2.0 + _state_x_max*_x_state_scale
        //                   *((Info::Render::width-_default_entity_x_translate)/(_state_x_max-_state_x_min)));
        _x_state_translate =  (_default_entity_x_translate - (Element_pos)Info::Render::width/2.0 + Info::Entity::x_max*coeff_trace_render_x());//_x_state_scale
                               //                             *((Info::Render::width-_default_entity_x_translate)/(_state_x_max-_state_x_min)));
       
        break;
    case Info::Render::Y_TRACE_ENDING:/* show the ending entities */
        _y_state_translate =  ( -_ruler_height + (Element_pos)Info::Render::height/2.0 - _state_y_max*_y_state_scale
                                *((Info::Render::height-_ruler_height)/(_state_y_max-_state_y_min)));
        break;
    case Info::Render::X_TRACE_ENTIRE:/* show the entire entities */
        //        replace_translate(0);//_x_state_translate = 0;
        replace_scale(1);//_x_state_scale = 1;    
        replace_translate(0);
        break;
    case Info::Render::Y_TRACE_ENTIRE:/* show the entire entities */
        /*        _y_state_translate = 0;
                  _y_state_scale = 1; */
        replace_scale_y(1); 
        replace_translate_y(0);
        break;
    default:
        message << tr("Unknown registered translate").toStdString() << Message::endw;
    }
    
    refresh_scroll_bars();
    updateRender();
}


void Hook_event::refresh_scroll_bars(bool LENGTH_CHANGED){
    if (LENGTH_CHANGED){
	Element_pos scroll_bar_length[2] = {_x_state_scale*scroll_margin, _y_state_scale*scroll_margin};
	_core->launch_action(_core->_STATE_AJUST_SCROLL_BARS, scroll_bar_length);
    }

    _x_scroll_pos = _x_state_translate;
    _y_scroll_pos = _y_state_translate;
    Element_pos buf[2] = {_x_scroll_pos, _y_scroll_pos};
    _core->launch_action(_core->_STATE_REFRESH_SCROLL_BARS, buf);
}


void Hook_event::change_scale_container_state(int view_size){
    
    _x_scale_container_state = 0.01 * view_size;
    updateRender();
}



