/***************************************************************************
 *   Copyright (C) 2007 by Faubet Pierre   *
 *   pierre.faubet@e.ujf-grenoble.fr   *
 *                                                                         *
 *   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 <QDebug>

#include <qwt_plot_marker.h>
#include <qwt_legend.h>
#include <qwt_data.h>
#include <qwt_text.h>
#include <qwt_plot_zoomer.h>
#include <qwt_plot_panner.h>
#include <qwt_plot_layout.h>
#include <math.h>
#include <qwt_interval_data.h>

#include "plot.h"

Plot::Plot(QWidget *parent): QwtPlot(parent)
{
  plotType = Empty;
}

Plot::~Plot()
{
  clear();
}

void Plot::TracePlot(double *x,double *y,int size,QString title)
{
  plotType = Trace;

  setTitle("Trace");

  setAxisTitle(xBottom, "Iterations");
  setAxisTitle(yLeft,title);

  // Insert new curves
  cCurve = new QwtPlotCurve("Trace");
  cCurve->setPen(QPen(Qt::blue));
  cCurve->attach(this);

  // Create data
  cCurve->setData(x,y,size);

  plotLayout()->setAlignCanvasToScales(true);

  setAxisScale(xBottom, x[0], x[size-1]);
  setAxisAutoScale(yLeft);

  grid = new QwtPlotGrid;
  grid->enableXMin(true);
  grid->enableYMin(true);
  grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
  grid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
  grid->attach(this);

  zoomer = new Zoomer(canvas());
  zoomer->setRubberBandPen(QPen(Qt::black, 2, Qt::DotLine));
  zoomer->setTrackerPen(QPen(Qt::black));

  replot();
}

void Plot::HistogramPlot(double *x,int size,QString title,int nbbins,double lb,double ub)
{
  plotType = Histogram;

  gsl_histogram *hist = gsl_histogram_alloc(nbbins);
  gsl_histogram_set_ranges_uniform (hist,lb,ub);
  for (int i=0;i<size;i++)
    gsl_histogram_increment(hist,x[i]);

  double histh = (ub-lb)/(nbbins);
  gsl_histogram_scale(hist,1.0/(size*histh));

  //setCanvasBackground(QColor(Qt::white));
  setTitle("Histogram");

  setAxisTitle(xBottom,title);
  setAxisTitle(yLeft,"Probability");

  grid = new QwtPlotGrid;
  grid->enableXMin(true);
  grid->enableYMin(true);
  grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
  grid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
  grid->attach(this);

  histogram = new HistogramItem();
  histogram->setColor(Qt::blue);

  QwtArray<QwtDoubleInterval> intervals(nbbins);
  QwtArray<double> values(nbbins);

  double pos = gsl_histogram_min(hist);
  for ( int i = 0; i < (int)intervals.size(); i++ )
    {
      double lower,upper;
      gsl_histogram_get_range(hist,i,&lower,&upper);
      const double width = upper - lower;
      const double value = gsl_histogram_get(hist,i);

      intervals[i] = QwtDoubleInterval(pos, pos + width);
      values[i] = value;

      pos += width;
    }

  histogram->setData(QwtIntervalData(intervals, values));
  histogram->attach(this);

  setAxisScale(xBottom, gsl_histogram_min(hist), pos);
  setAxisAutoScale(yLeft);

  replot();

  gsl_histogram_free(hist);
}

void Plot::DensityPlot(double *x,double *y,int size,QString title)
{
  plotType = Density;

  setTitle("Kernel Density Estimation");

  setAxisTitle(xBottom,title);
  setAxisTitle(yLeft,"Density");

  cCurve = new QwtPlotCurve("Density");
  //#if QT_VERSION >= 0x040000
  //cDensity->setRenderHint(QwtPlotItem::RenderAntialiased);
  //#endif
  cCurve->setPen(QPen(Qt::blue));
  cCurve->attach(this);

  cCurve->setData(x,y,size);

  setAxisScale(xBottom, x[0],x[size-1]);
  setAxisAutoScale(yLeft);

  grid = new QwtPlotGrid;
  grid->enableXMin(true);
  grid->enableYMin(true);
  grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
  grid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
  grid->attach(this);

  replot();
}

void Plot::RunningmeanPlot(double *x,double *y,int size,QString title)
{
  plotType = Runningmean;

  setTitle("Running mean");

  double *runningmean = new double [size];
  if (!runningmean)
    qDebug () << "Running mean error";

  double sum = 0;
  for (int i=0;i<size;i++)
    {
      sum += y[i];
      runningmean[i] = sum/(i+1);
    }

  setAxisTitle(xBottom, "Iterations");
  setAxisTitle(yLeft,title);

  cCurve = new QwtPlotCurve("Running mean");
  //#if QT_VERSION >= 0x040000
  //cRunningMean->setRenderHint(QwtPlotItem::RenderAntialiased);
  //#endif
  cCurve->setPen(QPen(Qt::blue));
  cCurve->attach(this);

  plotLayout()->setAlignCanvasToScales(true);

  cCurve->setData(x,runningmean,size);

  setAxisScale(xBottom, x[0],x[size-1]);
  setAxisAutoScale(yLeft);
  //setAxisScale(yLeft,lb,ub);

  grid = new QwtPlotGrid;
  grid->enableXMin(true);
  grid->enableYMin(true);
  grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
  grid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
  grid->attach(this);

  zoomer = new Zoomer(canvas());
  zoomer->setRubberBandPen(QPen(Qt::black, 2, Qt::DotLine));
  zoomer->setTrackerPen(QPen(Qt::black));

  replot();
}

void Plot::clear()
{
  switch (plotType)
    {
    case Trace:
      delete cCurve;
      delete zoomer;
      delete grid;
      break;

    case Runningmean:
      delete cCurve;
      delete zoomer;
      delete grid;
      break;

    case Histogram:
      delete histogram;
      delete grid;
      break;

    case Density:
      delete cCurve;
      delete grid;
      break;

    default:
      break;
    }
}
