/***************************************************************************
 *   Copyright (C) 2007 by Muylkens Toon   *
 *   toon.muylkens@student.kuleuven.be   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


#include "QtrainerPlotFrame.h"
//   #include <stdio.h>
//   #include <iostream>
//   using namespace std;


QtrainerPlotFrame::QtrainerPlotFrame(QWidget *parent, int myindex)
     : QWidget(parent)
 {
     	ui.setupUi(this);
	this->myindex=myindex;
	QObject::connect(ui.spinBox,SIGNAL(valueChanged(int)),this,SLOT(sliderValueChanged(int)));
	QObject::connect(ui.checkBox_bevier,SIGNAL(stateChanged(int)),this,SLOT(setPlotMethod(int)));
	QObject::connect(ui.checkBox_line,SIGNAL(stateChanged(int)),this,SLOT(setPlotMethod(int)));
	QObject::connect(ui.checkBox_spline,SIGNAL(stateChanged(int)),this,SLOT(setPlotMethod(int)));
	this->setMinimumHeight(400);

	bezier=false;
	line=false;
	spline=false;
	this->myPlotter = new Plotter(this);
	ui.vboxLayout->insertWidget(0,this->myPlotter);
	
	setSliderMaximum(0);
	ui.spinBox->setValue(0);
}

/**
*only plot the 'number' last datapoints.
*\return false when number > getData().size()
*/
bool QtrainerPlotFrame::setNbOfPointsToPlot(int number)
{
if(getData().size()<number){
	//cout<<"QtrainerPlotFrame: setNbOfPointsToPlot: illegal nb of points"<<endl;
	return false;
}
else{
	ui.spinBox->setValue(number); //will only emit signal when number != current value
	replot();
	return true;
	}
}

/**
*\return current number of points used for the plots
*always smaller or equal to getData().size()
*/
int QtrainerPlotFrame::getNbOfPointsPlotted(){
return ui.spinBox->value(); //the spinBox always has the right value
}

/**
*slidermaximum is always equal to getData().size()
*/
void QtrainerPlotFrame::setSliderMaximum(int i)
{
ui.spinBox->setMaximum(i);
}

/**
*Returns the index of this Widget
*/
int QtrainerPlotFrame::getMyIndex()
{
return this->myindex;
}


/**
*the slides telling how many points to plot was changed => emit nbOfPointsPlottedChanged and replot
*/
void QtrainerPlotFrame::sliderValueChanged(int i)
{
if(i<2){
	ui.checkBox_spline->setCheckState(Qt::Unchecked);
	}
replot();
emit nbOfPointsPlottedChanged(i, getMyIndex()); //maybe this value needs to be saved into the profile
}

/**
*Sets the title of this widget to 'title'
*/
void QtrainerPlotFrame::setTitle(QString title)
{
ui.groupBox->setTitle(title);
}

/**
*Returns the title of this widget
*/
QString QtrainerPlotFrame::getTitle()
{
return ui.groupBox->title();
}


/**
*After toggling the checkboxes, we set the plotmethod of the plotter.
*\note variable state isn't used.
*/
void QtrainerPlotFrame::setPlotMethod(int state){
	bezier=false;
	line=false;
	spline=false;
	if(ui.checkBox_bevier->isChecked()){bezier=true;}
	if(ui.checkBox_line->isChecked()){line=true;}
	if(ui.checkBox_spline->isChecked()){spline=true;}

	plotMethodChanged();
}

/**
*Emit the plotMethodChanged signal
*/
void QtrainerPlotFrame::plotMethodChanged(){
	QStringList methodlist;
	if(bezier) {methodlist.append("Bevier");}
	if(line) {methodlist.append("Line");}
	if(spline) {methodlist.append("Spline");}
	emit plotMethodChanged(methodlist, getMyIndex());
	replot();
}

/**
*Plots bezier,line, spline when their value is true, overrides and updates the values
*selected by the checkboxes
*/
void QtrainerPlotFrame::setPlotMethod(bool bezier, bool line, bool spline){
if(bezier) {ui.checkBox_bevier->setCheckState(Qt::Checked);}
if(spline) {ui.checkBox_spline->setCheckState(Qt::Checked);}
if(line) {ui.checkBox_line->setCheckState(Qt::Checked);}
}

/**
*sets the checkboxes and plotstatus to the given one
*/
void QtrainerPlotFrame::setCheckBoxes(){
if(bezier) {ui.checkBox_bevier->setCheckState(Qt::Checked);}
if(spline) {ui.checkBox_spline->setCheckState(Qt::Checked);}
if(line) {ui.checkBox_line->setCheckState(Qt::Checked);}
}

/**
*Returns a pointer to the plotter shown in the Widget
*/
Plotter* QtrainerPlotFrame::getPlotter(){
return this->myPlotter;
}

/**
*Sets the plot-data-points to the one in the vector.
*The selected plotmethods are used to visualize the data.
*/
void QtrainerPlotFrame::setDataAndPlot(QVector<QPointF> vector){
setSliderMaximum(vector.size());
this->plotData = vector;
	QString text;
	QString textn;
	text = tr("Number of datapoints available: ");
	textn.setNum(vector.size());
	text.append(textn);
	ui.labelavailable->setText(text);
ui.checkBox_spline->setEnabled(true); ui.checkBox_spline->setCheckable(true);
if(vector.size()<2){ ui.checkBox_spline->setEnabled(false); ui.checkBox_spline->setCheckable(false);} //not enough points for spline
replot();
}

/**
*Returns the vector containing all the data available for plotting (the entire vector)
*/
QVector<QPointF> QtrainerPlotFrame::getData(){
return this->plotData;
}

/**
*After executing the internal vector containing only the getNbOfPointsPlotted() most recent
* points is up to date with the entire datavector
*/
void QtrainerPlotFrame::calculateTruncatedData(){
int countermax = getNbOfPointsPlotted();
int size = getData().size();
this->truncatedData.clear();
for(int i=0;i<countermax;i++){
	this->truncatedData.append(getData().at(i));
}

}	

/**
*Returns the vector containing all the data needed for plotting the getNbOfPointsPlotted() most recent
*datapoints of the dataVector (getData())
*getData().size() >= getTruncatedData().size()
*/
QVector<QPointF> QtrainerPlotFrame::getTruncatedData(){
// if (this->truncatedData.size() != getNbOfPointsPlotted()) { //doesn't work because when updating a datapoint the size stays the same but calculateTruncatedData() must be exectuted!
	calculateTruncatedData();
// }
return this->truncatedData;
}


/**
*Replots the data
*It checks all the parameters again: which plot-type, how many points, rescaling, ...
*/
void QtrainerPlotFrame::replot(){

QVector<QPointF> vector  = getTruncatedData();
Extremes myextremes(vector);
getPlotter()->clearCurve(0);
getPlotter()->clearCurve(1);
getPlotter()->clearCurve(2);

if(vector.size()>0){
	
	if(line) 	{getPlotter()->setCurveData(0,vector);}
	if(bezier) 	{getPlotter()->setCurveData(1,vector);}
	if(spline) 	{getPlotter()->setCurveData(2,vector);}

	double maxx=vector.value(0).x(); double minx=vector.value(vector.size()-1).x(); 
	double miny=myextremes.getminy(); double maxy = myextremes.getmaxy();
	miny=miny-1; maxy=maxy+1;
	if(maxy == miny) {maxy = miny+1;}
	getPlotter()->adjustAxis(minx,maxx,miny,maxy);
	}
}


/**
* Constructor of Extremes.
* This class need a Vector of QPointF's and has methodes which retrun extreme values
*/
 Extremes::Extremes(QVector<QPointF> vector)
 {
	this->vector=vector;
 }

/**
 * returns the smallest Y value of a vector fro QPoints
 * @return double: smallest y value
 */
double Extremes::getminy()
{
	int min=99999999;
	QVectorIterator<QPointF> i(vector);
 	while (i.hasNext())
     	{double y= i.next().y();
	if(y<min){min=y;}}
	return min;
}


/**
 * returns the bigest Y value of a vector fro QPoints
 * @return double: bigest y value
 */
double Extremes::getmaxy()
{
	int max=0;
	QVectorIterator<QPointF> i(vector);
 	while (i.hasNext())
     	{double y= i.next().y();
	if(y>max){max=y;}}
	return max;
}