/**
 * \file pappsomspp/widget/xicwidget/qcpxic.cpp
 * \date 12/1/2018
 * \author Olivier Langella
 * \brief custom plot XIC
 */


/*******************************************************************************
 * Copyright (c) 2018 Olivier Langella <Olivier.Langella@u-psud.fr>.
 *
 * This file is part of the PAPPSOms++ library.
 *
 *     PAPPSOms++ 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 3 of the License, or
 *     (at your option) any later version.
 *
 *     PAPPSOms++ 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 PAPPSOms++.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/


#include "qcpxic.h"
#include "../../processing/detection/tracepeak.h"

using namespace pappso;

QCPXic::QCPXic(XicWidget *parent) : QCustomPlot(parent)
{
  qDebug() << "QCPXic::QCPXic begin";
  _parent = parent;
  setFocusPolicy(Qt::ClickFocus);

  if(_parent->_rt_in_seconds)
    {
      xAxis->setLabel("retention time (sec)");
    }
  else
    {
      xAxis->setLabel("retention time (min)");
    }

  yAxis->setLabel("intensity");
  setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
  axisRect()->setRangeDrag(Qt::Horizontal);
  axisRect()->setRangeZoom(Qt::Horizontal);

  connect(this->xAxis,
          SIGNAL(rangeChanged(QCPRange)),
          this,
          SLOT(setRtRangeChanged(QCPRange)));

  //
  // http://tools.medialab.sciences-po.fr/iwanthue/
  _colours = {QColor(197, 89, 110),
              QColor(94, 185, 86),
              QColor(132, 95, 203),
              QColor(176, 175, 69),
              QColor(202, 72, 160),
              QColor(91, 126, 59),
              QColor(193, 126, 189),
              QColor(81, 183, 159),
              QColor(210, 77, 58),
              QColor(99, 137, 203),
              QColor(223, 147, 71),
              QColor(156, 105, 52)};

  qDebug() << "QCPXic::QCPXic end";
}
QCPXic::~QCPXic()
{
}
void
QCPXic::keyPressEvent(QKeyEvent *event)
{
  if(event->key() == Qt::Key_Control)
    {
      _control_key = true;
    }
  qDebug() << "QCPXic::keyPressEvent end";
}

void
QCPXic::keyReleaseEvent(QKeyEvent *event)
{
  if(event->key() == Qt::Key_Control)
    {
      _control_key = false;
    }
  qDebug() << "QCPXic::keyReleaseEvent end";
}

void
QCPXic::mousePressEvent(QMouseEvent *event)
{
  qDebug() << " begin ";
  _mouse_move = false;
  _click      = true;

#if QT_VERSION < 0x060000
  _old_x = event->x();
  _old_y = yAxis->pixelToCoord(event->y());
#else
  _old_x = event->position().x();
  _old_y = yAxis->pixelToCoord(event->position().y());
#endif
  if(_old_y < 0)
    {
      _old_y = 0;
    }
  else
    {
    }
  qDebug() << "QCPXic::mousePressEvent end";
}
void
QCPXic::mouseReleaseEvent(QMouseEvent *event)
{

#if QT_VERSION < 0x060000
  qDebug() << "QCPXic::mouseReleaseEvent begin "
           << xAxis->pixelToCoord(event->x()) << " "
           << yAxis->pixelToCoord(event->y());
#else
  qDebug() << "QCPXic::mouseReleaseEvent begin "
           << xAxis->pixelToCoord(event->position().x()) << " "
           << yAxis->pixelToCoord(event->position().y());
#endif

  _click = false;
  if(_mouse_move)
    {
      _mouse_move = false;
    }
  else
    {
      _parent->xicClickEvent(xAxisToSeconds(_old_x), _old_y);
    }
  qDebug() << "QCPXic::mouseReleaseEvent end";
}
void
QCPXic::mouseMoveEvent(QMouseEvent *event)
{
  _mouse_move = true;

#if QT_VERSION < 0x060000
  pappso::pappso_double x = xAxis->pixelToCoord(event->x());
#else
  pappso::pappso_double x = xAxis->pixelToCoord(event->position().x());
#endif
  if(_click)
    {

#if QT_VERSION < 0x060000
      qDebug() << "QCPXic::mouseMoveEvent begin "
               << xAxis->pixelToCoord(event->x()) << " "
               << yAxis->pixelToCoord(event->y());
      pappso::pappso_double y = yAxis->pixelToCoord(event->y());
#else
      qDebug() << "QCPXic::mouseMoveEvent begin "
               << xAxis->pixelToCoord(event->position().x()) << " "
               << yAxis->pixelToCoord(event->position().y());
      pappso::pappso_double y = yAxis->pixelToCoord(event->position().y());
#endif
      if(y < 0)
        {
          y = 0;
        }
      if(_control_key)
        {
          if(y > 0)
            {
              this->yAxis->scaleRange(_old_y / y, 0);
            }
        }
      else
        {

#if QT_VERSION < 0x060000
          this->xAxis->moveRange(xAxis->pixelToCoord(_old_x) -
                                 xAxis->pixelToCoord(event->x()));
#else
          this->xAxis->moveRange(xAxis->pixelToCoord(_old_x) -
                                 xAxis->pixelToCoord(event->position().x()));
#endif
        }

#if QT_VERSION < 0x060000
      _old_x = event->x();
#else
      _old_x = event->position().x();
#endif
      _old_y = y;
      replot();
      qDebug() << "QCPXic::mouseMoveEvent end";
    }
  else
    {
      if(_map_xic_graph.size() > 0)
        {
          // pappso::pappso_double mouse_mz_range = xAxis->pixelToCoord(10) -
          // xAxis->pixelToCoord(5); getNearestPeakBetween(x, mouse_mz_range);
          _parent->rtChangeEvent(xAxisToSeconds(x));
        }
    }
}

QCPGraph *
QCPXic::addXicP(const Xic *xic_p)
{

  _graph_color = _colours[(int)(_map_xic_graph.size() % _colours.size())];

  QCPGraph *graph_xic = addGraph();
  graph_xic->setPen(QPen(_graph_color));
  _map_xic_graph.insert(std::pair<const Xic *, QCPGraph *>(xic_p, graph_xic));
  graph_xic->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 2.0));

  if(xic_p->size() > 0)
    {
      for(const DataPoint &element : *xic_p)
        {
          graph_xic->addData(getRetentionTimeFromSecondsToLocal(element.x),
                             element.y);
        }
      if(_rt_range.lower > getRetentionTimeFromSecondsToLocal(xic_p->front().x))
        _rt_range.lower =
          getRetentionTimeFromSecondsToLocal(xic_p->front().x) - 1;
      if(_rt_range.upper < getRetentionTimeFromSecondsToLocal(xic_p->back().x))
        _rt_range.upper =
          getRetentionTimeFromSecondsToLocal(xic_p->back().x) + 1;
      _intensity_range.lower = 0;
      if(_intensity_range.upper < xic_p->maxYDataPoint().y)
        _intensity_range.upper = xic_p->maxYDataPoint().y;
    }

  return graph_xic;
}


void
QCPXic::rescale()
{
}


void
QCPXic::setRtRangeChanged(QCPRange range)
{
  qDebug() << "QCPXic::setMzRangeChanged _rt_range.lower" << _rt_range.lower;
  if(range.lower < _rt_range.lower)
    {
      range.lower = _rt_range.lower;
    }
  if(range.upper > _rt_range.upper)
    {
      range.upper = _rt_range.upper;
    }

  xAxis->setRange(range);
}


void
QCPXic::addMsMsEvent(const Xic *xic_p, pappso::pappso_double rt)
{
  _current_ms2_event = new QCPItemTracer(this);
  // itemDemoPhaseTracer = phaseTracer; // so we can access it later in the
  // bracketDataSlot for animation

  _current_ms2_event->setGraph(_map_xic_graph.at(xic_p));
  _current_ms2_event->setGraphKey(getRetentionTimeFromSecondsToLocal(rt));
  _current_ms2_event->setInterpolating(true);
  _current_ms2_event->setStyle(QCPItemTracer::tsCircle);
  _current_ms2_event->setPen(QPen(Qt::red));
  _current_ms2_event->setBrush(Qt::red);
  _current_ms2_event->setSize(7);

  // addItem(_current_ms2_event);
}

void
QCPXic::setName(const Xic *xic_p, const QString &name)
{
  _map_xic_graph.at(xic_p)->addToLegend();
  _map_xic_graph.at(xic_p)->setName(name);
}


void
QCPXic::clear()
{
  legend->clearItems();
  _map_xic_graph.clear();
  this->clearGraphs();
  this->clearItems();
  this->clearPlottables();
}


void
QCPXic::addXicPeakList(
  const Xic *xic_p, const std::vector<pappso::TracePeakCstSPtr> &xic_peak_list)
{
  for(const pappso::TracePeakCstSPtr &peak : xic_peak_list)
    {
      _graph_peak_surface_list.push_back(addGraph());
      for(auto &xic_element : *(xic_p))
        {
          if(peak.get()->containsRt(xic_element.x))
            {
              _graph_peak_surface_list.back()->addData(
                getRetentionTimeFromSecondsToLocal(xic_element.x),
                xic_element.y);
            }
        }
      // graph()->setData(rt_peak, intensity_peak);
      _graph_peak_surface_list.back()->removeFromLegend();
      _graph_peak_surface_list.back()->setChannelFillGraph(0);
      _graph_peak_surface_list.back()->setLineStyle(
        QCPGraph::LineStyle::lsLine);
      QColor color = _colours[_graph_peak_surface_list.size() % 12];
      color.setAlpha(0);
      // QColor(0, 110, 110, 30)
      _graph_peak_surface_list.back()->setPen(QPen(color));
      color.setAlpha(40);
      //_graph_peak_surface_list.back()->setScatterStyle(QCPScatterStyle::ssDot);
      _graph_peak_surface_list.back()->setBrush(QBrush(color));
    }
}

pappso::pappso_double
QCPXic::getRetentionTimeFromSecondsToLocal(pappso::pappso_double rt) const
{
  if(_parent->_rt_in_seconds)
    {
      return rt;
    }
  else
    {
      return (rt / (pappso::pappso_double)60);
    }
}

pappso::pappso_double
QCPXic::xAxisToSeconds(pappso::pappso_double rt) const
{
  if(_parent->_rt_in_seconds)
    {
      return rt;
    }
  else
    {
      return (rt * (pappso::pappso_double)60);
    }
}

void
QCPXic::drawXicPeakBorders(unsigned int i,
                           const Xic *xic_p,
                           const pappso::TracePeak *p_xic_peak)
{
  QCPGraph *p_graph = _map_xic_graph.at(xic_p);
  QColor color      = _colours[i % 12];
  // color.setAlpha(95);

  QCPItemTracer *p_peak_border_left = new QCPItemTracer(this);
  // itemDemoPhaseTracer = phaseTracer; // so we can access it later in the
  // bracketDataSlot for animation
  QPen border_pen(color);
  border_pen.setWidth(3);

  p_peak_border_left->setGraph(p_graph);
  p_peak_border_left->setGraphKey(
    getRetentionTimeFromSecondsToLocal(p_xic_peak->getLeftBoundary().x));
  p_peak_border_left->setInterpolating(true);
  p_peak_border_left->setStyle(QCPItemTracer::tsPlus);
  p_peak_border_left->setPen(border_pen);
  p_peak_border_left->setBrush(color);
  p_peak_border_left->setSize(30);

  _graph_peak_border_list.push_back(p_peak_border_left);

  // addItem(p_peak_border_left);

  QPen apex_pen(color);
  apex_pen.setWidth(2);
  p_peak_border_left = new QCPItemTracer(this);
  p_peak_border_left->setGraph(_map_xic_graph.at(xic_p));
  p_peak_border_left->setGraphKey(
    getRetentionTimeFromSecondsToLocal(p_xic_peak->getMaxXicElement().x));
  p_peak_border_left->setInterpolating(true);
  p_peak_border_left->setStyle(QCPItemTracer::tsPlus);
  p_peak_border_left->setPen(apex_pen);
  p_peak_border_left->setBrush(color);
  p_peak_border_left->setSize(8);

  _graph_peak_border_list.push_back(p_peak_border_left);

  // addItem(p_peak_border_left);


  p_peak_border_left = new QCPItemTracer(this);
  p_peak_border_left->setGraph(_map_xic_graph.at(xic_p));
  p_peak_border_left->setGraphKey(
    getRetentionTimeFromSecondsToLocal(p_xic_peak->getRightBoundary().x));
  p_peak_border_left->setInterpolating(true);
  p_peak_border_left->setStyle(QCPItemTracer::tsPlus);
  p_peak_border_left->setPen(border_pen);
  p_peak_border_left->setBrush(color);
  p_peak_border_left->setSize(30);

  _graph_peak_border_list.push_back(p_peak_border_left);

  // addItem(p_peak_border_left);

  replot();
}

void
QCPXic::clearXicPeakBorders()
{
  for(QCPItemTracer *p_tracer : _graph_peak_border_list)
    {
      removeItem(p_tracer);
      // delete p_tracer;
    }
  _graph_peak_border_list.clear();
  replot();
}
