/*
** 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 
**
*/
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>

/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
#include "common/Message.hpp"
#include "interface/resource.hpp"
#include "interface/Interface.hpp"

#include "core/Core.hpp"
#include "interface/Interface_graphic.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityValue.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/tree/Interval.hpp"
#include "trace/Container.hpp"
/* -- */
#include <QKeyEvent>

#include "interface/Interval_select.hpp"

#undef max
#include <limits>

using namespace std;

Interval_select::Interval_select(Interface_graphic * console,QWidget *parent) : QDialog(parent), _trace(NULL),_console(console) {
    setupUi(this);
	connect( minSpinBox, SIGNAL(valueChanged( double )), SLOT(minSpinBoxValueChanged( double ) ) );
	connect( interval_slider, SIGNAL(lowerValueChanged( int )), SLOT(minSliderValueChanged( int ) ) );
	connect( maxSpinBox, SIGNAL(valueChanged( double )), SLOT(maxSpinBoxValueChanged( double ) ) );
	connect( interval_slider, SIGNAL(upperValueChanged( int )), SLOT(maxSliderValueChanged( int ) ) );
    QMetaObject::connectSlotsByName(NULL);
	_auto_refresh=auto_refresh_box->isChecked();//true by default
	_applied=false;
	//interval_slider->setHandleMovementMode(QxtSpanSlider::NoOverlapping);
}

Interval_select::~Interval_select() {
}

Trace* Interval_select::get_trace() {
	return _trace;
}

void Interval_select::set_trace(Trace *trace) {
    // Initialize _trace
    _trace = trace;
	//double max =_trace->get_max_date().get_value();
	min_value->setText(QString().setNum (Info::Entity::x_min));
	max_value->setText(QString().setNum (Info::Entity::x_max));
	minSpinBox->setMinimum(Info::Entity::x_min);
	minSpinBox->setMaximum(std::numeric_limits<double>::max());
	maxSpinBox->setMinimum(Info::Entity::x_min);
	maxSpinBox->setMaximum(std::numeric_limits<double>::max());
	//the slider stays in int, we will translate its values
	/*interval_slider->setMinimum(0);
	interval_slider->setMaximum(99);*/

	double delta=Info::Entity::x_max-Info::Entity::x_min;
	double step= 0.001*delta; //make steps of .1% for spinboxes
	minSpinBox->setSingleStep(step);
	maxSpinBox->setSingleStep(step);

	update_values();
}

//called if a zoom is triggered outside of the window, to update slider position and spinboxes with the real values
void Interval_select::update_values() {

	if(_trace!=NULL){//if init

Element_pos _min;
Element_pos _max;

//choose which value to load the actual position from (can change if we are loading from a splitted file set)
if(Info::Splitter::preview==true){
    _min=Info::Entity::x_min;
    _max=Info::Entity::x_max;
}else if(Info::Splitter::load_splitted==true){
	Info::Render::_x_min=Info::Splitter::_x_min;
	Info::Render::_x_max=Info::Splitter::_x_max;
	auto_refresh_box->setChecked(false);//set the checkbox to false because reload is expensive for splitted mode
    _min=Info::Splitter::_x_min;
    _max=Info::Splitter::_x_max;
}else{
    _min=Info::Render::_x_min;
    _max=Info::Render::_x_max;
    }
    bool v = minSpinBox->blockSignals(true);
	bool v2 = maxSpinBox->blockSignals(true);
	bool v3 = interval_slider->blockSignals(true);
	int maxvalue=int(_max*(interval_slider->maximum() - interval_slider->minimum())/(_trace->get_max_date() - minSpinBox->minimum()));
	interval_slider->setUpperValue(maxvalue);
	interval_slider->setLowerValue(int(_min*(interval_slider->maximum() - interval_slider->minimum())/(_trace->get_max_date() - minSpinBox->minimum())));
	maxSpinBox->setValue(_max);
	minSpinBox->setValue(_min);
	minSpinBox->blockSignals(v);
	maxSpinBox->blockSignals(v2);
	interval_slider->blockSignals(v3);
	_applied=false;
	}
}


void Interval_select::minSpinBoxValueChanged( double _value )
{
	QPalette myPalette(minSpinBox->palette());

	if(_value < maxSpinBox->value()){

		  bool v = interval_slider->blockSignals(true);
		  interval_slider->setLowerValue( int(_value *(interval_slider->maximum() - interval_slider->minimum())/(_trace->get_max_date() - minSpinBox->minimum())) );

		  interval_slider->blockSignals(v);
		  emit( minValueChanged( minSpinBox->value() ) );
		  myPalette.setColor(QPalette::Active, QPalette::Text, Qt::black);
		  myPalette.setColor(QPalette::Active, QPalette::HighlightedText, Qt::white);
		  
		  if(_auto_refresh)apply_settings();
	}else{
		//min cannot be greater than max
		//set the incorrect value to red, but don't change it in order to let the user type a full correct value
		  myPalette.setColor(QPalette::Active, QPalette::Text, Qt::red);
		  myPalette.setColor(QPalette::Active, QPalette::HighlightedText, Qt::red);
		//minSliderValueChanged(  maxSpinBox->value() );
	}
	
	minSpinBox->setPalette(myPalette);
	maxSpinBox->setPalette(myPalette);

  _applied=false;

}

void Interval_select::minSliderValueChanged( int _value )
{
	if(_value < interval_slider->upperValue()){
	  bool v = minSpinBox->blockSignals(true);
	  minSpinBox->setValue( _value *(_trace->get_max_date() - minSpinBox->minimum())/(interval_slider->maximum() - interval_slider->minimum()));
	  minSpinBox->blockSignals(v);
	  emit( minValueChanged( minSpinBox->value() ) );
	  if(_auto_refresh)apply_settings();
	}
  _applied=false;
}

void Interval_select::maxSpinBoxValueChanged( double _value )
{
	QPalette myPalette(minSpinBox->palette());
	if(_value > minSpinBox->value()){
		  bool v = interval_slider->blockSignals(true);
		  interval_slider->setUpperValue( int(_value* (interval_slider->maximum() - interval_slider->minimum())/(_trace->get_max_date() - maxSpinBox->minimum())));
		  interval_slider->blockSignals(v);
		  emit( maxValueChanged( maxSpinBox->value() ) );
		  myPalette.setColor(QPalette::Active, QPalette::Text, Qt::black);
		  myPalette.setColor(QPalette::Active, QPalette::HighlightedText, Qt::white);
		  if(_auto_refresh)apply_settings();
	}else{
		//max cannot be lower than min

		  myPalette.setColor(QPalette::Active, QPalette::Text, Qt::red);
		  myPalette.setColor(QPalette::Active, QPalette::HighlightedText, Qt::red);
		//maxSliderValueChanged(  minSpinBox->value() ) ;
	}
	maxSpinBox->setPalette(myPalette);
	minSpinBox->setPalette(myPalette);
	_applied=false;
}

void Interval_select::maxSliderValueChanged( int _value )
{
	
	if(_value > interval_slider->lowerValue()){
	  bool v = maxSpinBox->blockSignals(true);
      maxSpinBox->setValue( _value * (_trace->get_max_date() - maxSpinBox->minimum())/(interval_slider->maximum() - interval_slider->minimum()));
	  maxSpinBox->blockSignals(v);
	  emit( maxValueChanged( maxSpinBox->value() ) );
	  if(_auto_refresh)apply_settings();
	}
  _applied=false;
}


void Interval_select::apply_settings(){
    if(minSpinBox->value()!=maxSpinBox->value()){
	    Element_pos zoom[2]={minSpinBox->value(), maxSpinBox->value()};
	
        //Info::Render::_x_min_visible = 0.0;
		//Info::Render::_x_max_visible = 0.0;
        _console->get_console()->launch_action(Core:: _STATE_CLEAN_RENDER_AREA);
		
	    //reload data from disk if needed
	    #if defined(USE_ITC) && defined(BOOST_SERIALIZE)
	    Info::Splitter::_x_min=zoom[0];
	    Info::Splitter::_x_max=zoom[1];
	    _trace->updateTrace(new Interval(zoom[0], zoom[1]));
	    #endif
	    
        _console->get_console()->draw_trace(_console->get_filename(),Core::_DRAW_OPENGL);
        
	    _console->get_console()->launch_action(Core:: _STATE_ZOOM_IN_AN_INTERVAL, &zoom);
        _console->get_console()->launch_action(Core:: _STATE_RENDER_UPDATE);
    }
}


void Interval_select::on_apply_button_clicked(){
	apply_settings();
	_applied=true;
}

void Interval_select::on_cancel_button_clicked(){
	hide();
}

void Interval_select::on_ok_button_clicked(){

	if(!_applied)on_apply_button_clicked();
	hide();
}


void Interval_select::on_reset_button_clicked(){
	//maxValueChanged( interval_slider->maximum() );
	//minValueChanged( interval_slider->minimum() );
	interval_slider->setUpperValue(interval_slider->maximum());
	interval_slider->setLowerValue(interval_slider->minimum());
	maxSliderValueChanged(  interval_slider->maximum() );
	minSliderValueChanged(  interval_slider->minimum() );
}


void Interval_select::on_auto_refresh_box_stateChanged(){
	_auto_refresh=auto_refresh_box->isChecked();
}

/*
void Stats_window::init() {
    // We set the names of the containers for the tree widget
    _nodes_selected->clear();
    set_container_names();
    
    // We init the times
    _start_time = Info::Render::_x_min_visible;
    _end_time   = Info::Render::_x_max_visible;

    QString temp;
    temp.setNum(_start_time);
    _start_time_widget->setText(temp);
    temp.setNum(_end_time);
    _end_time_widget->setText(temp);

    _ui_stats_area->clear();
    Reinit_scroll_bars();
}

void Stats_window::clear() {
    _ui_stats_area->makeCurrent();
    _nodes_selected->clear();
    _ui_stats_area->clear();
    _kind_of_state_box->clear();
    Reinit_scroll_bars();
    _ui_stats_area->doneCurrent();
}

void Stats_window::set_arguments(std::map<std::string , QVariant *>) {
}

void Stats_window::execute() {
       on_reload_button_clicked(); 
}

string Stats_window::get_name() {
    return "Statistics window";
}*/
