/**
 * \file pappsomspp/widget/xicwidget/xicwidget.h
 * \date 12/1/2018
 * \author Olivier Langella
 * \brief plot a 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 "xicwidget.h"
#include <QDebug>
#include <QHBoxLayout>
#include "qcpxic.h"
#include "pappsomspp/core/exception/exceptionnotfound.h"

using namespace pappso;

XicWidget::XicWidget(QWidget *parent) : GraphicDeviceWidget(parent)
{
  qDebug() << "XicWidget::XicWidget begin";


  this->setLayout(new QHBoxLayout(this));

  setMinimumSize(200, 160);
  this->layout()->setContentsMargins(0, 0, 0, 0);

  _qcp_xic = new QCPXic(this);
  this->layout()->addWidget(_qcp_xic);
  qDebug() << "XicWidget::XicWidget end";
}
XicWidget::~XicWidget()
{
}

void
XicWidget::addMsMsEvent(const Xic *xic_p, pappso::pappso_double rt)
{
  XicCstSPtr xic_sp = getXicCstSPtr(xic_p);
  _qcp_xic->addMsMsEvent(xic_p, rt);
  _map_xic_msms_event[xic_p] = rt;
}
QCPGraph *
XicWidget::addXicSp(XicCstSPtr xic_sp)
{
  _xic_sp_list.push_back(xic_sp);
  return _qcp_xic->addXicP(xic_sp.get());
}

const QString &
XicWidget::getName(const Xic *xic_p) const
{
  XicCstSPtr xic_sp = getXicCstSPtr(xic_p);
  return _map_xic_name.at(xic_p);
}

void
XicWidget::setName(const Xic *xic_p, const QString &name)
{
  XicCstSPtr xic_sp = getXicCstSPtr(xic_p);
  _qcp_xic->legend->setVisible(true);
  _qcp_xic->setName(xic_p, name);
  _map_xic_name[xic_p] = name;
}

void
XicWidget::plot()
{
  _qcp_xic->replot();
}
void
XicWidget::rescale()
{
  _qcp_xic->xAxis->rescale(true);
  _qcp_xic->yAxis->rescale(true);
  _qcp_xic->rescale();
}

QCPAxis *
XicWidget::getRtAxisP()
{
  return _qcp_xic->xAxis;
}

QCPAxis *
XicWidget::getIntensityAxisP()
{
  return _qcp_xic->yAxis;
}

void
XicWidget::rescaleOneRange(QString axis_name, QCPRange new_range)
{
  if(axis_name == "xAxis")
    {
      _qcp_xic->xAxis->setRange(new_range);
    }
  else // axis_name == "yAxis"
    {
      _qcp_xic->yAxis->setRange(new_range);
    }
  _qcp_xic->replot();
}

void
XicWidget::clear()
{
  _map_xic_name.clear();
  _xic_sp_list.clear();
  _xic_peak_sp_list.clear();
  _qcp_xic->clear();
  _map_xic_msms_event.clear();
}

XicCstSPtr
XicWidget::getXicCstSPtr(const Xic *xic_p) const
{
  std::vector<XicCstSPtr>::const_iterator it =
    std::find_if(_xic_sp_list.begin(), _xic_sp_list.end(), [xic_p](XicCstSPtr xic_sp) {
      return xic_sp.get() == xic_p;
    });
  if(it == _xic_sp_list.end())
    {
      throw pappso::ExceptionNotFound(tr("ERROR : xic pointer not found"));
    }
  return *it;
}

void
XicWidget::addXicPeakList(const Xic *xic_p,
                          const std::vector<pappso::TracePeakCstSPtr> &xic_peak_list)
{
  XicCstSPtr xic_sp = getXicCstSPtr(xic_p);
  _qcp_xic->addXicPeakList(xic_p, xic_peak_list);
  for(const pappso::TracePeakCstSPtr &xic_peak : xic_peak_list)
    {
      _xic_peak_sp_list.push_back(std::pair<XicCstSPtr, TracePeakCstSPtr>(xic_sp, xic_peak));
    }
}
void
XicWidget::rtChangeEvent(pappso::pappso_double rt) const
{
  emit rtChanged(rt);

  std::vector<std::pair<XicCstSPtr, TracePeakCstSPtr>> over_xic_peak_list;
  for(std::pair<XicCstSPtr, TracePeakCstSPtr> pair_xic_peak : _xic_peak_sp_list)
    {
      if(pair_xic_peak.second.get()->containsRt(rt))
        {
          over_xic_peak_list.push_back(pair_xic_peak);
        }
    }

  // if (over_xic_peak_list.size() > 0) {
  emit xicPeakListChanged(over_xic_peak_list);
  //}
}

void
XicWidget::toQPaintDevice(QPaintDevice *device, const QSize &size)
{

  if(_qcp_xic != nullptr)
    {
      QCPPainter painter;
      painter.begin(device);
      _qcp_xic->toPainter(&painter, size.width(), size.height());
      painter.end();
    }
}


void
XicWidget::setRetentionTimeInSeconds()
{
  _rt_in_seconds = true;
  _qcp_xic->xAxis->setLabel("retention time (sec)");
  replotAll();
}
void
XicWidget::setRetentionTimeInMinutes()
{
  _rt_in_seconds = false;
  _qcp_xic->xAxis->setLabel("retention time (min)");
  replotAll();
}

void
XicWidget::replotAll()
{
  _qcp_xic->clear();

  for(XicCstSPtr xic_sp : _xic_sp_list)
    {
      _qcp_xic->addXicP(xic_sp.get());

      std::vector<TracePeakCstSPtr> xic_peak_list;
      for(auto xic_map_peak_list : _xic_peak_sp_list)
        {
          if(xic_map_peak_list.first.get() == xic_sp.get())
            xic_peak_list.push_back(xic_map_peak_list.second);
        }
      _qcp_xic->addXicPeakList(xic_sp.get(), xic_peak_list);
    }
  for(auto xic_name : _map_xic_name)
    {
      setName(xic_name.first, xic_name.second);
    }
  for(auto xic_msms : _map_xic_msms_event)
    {
      _qcp_xic->addMsMsEvent(xic_msms.first, xic_msms.second);
    }

  rescale();
  _qcp_xic->replot();
}

void
XicWidget::xicClickEvent(pappso::pappso_double rt, pappso::pappso_double intensity) const
{
  emit clicked(rt, intensity);
}


void
XicWidget::drawXicPeakBorders(pappso::TracePeakCstSPtr xic_peak)
{
  XicCstSPtr xic_sp;
  for(std::pair<XicCstSPtr, TracePeakCstSPtr> pair_xic_peak : _xic_peak_sp_list)
    {
      if(pair_xic_peak.second.get() == xic_peak.get())
        {
          xic_sp = pair_xic_peak.first;
          break;
        }
    }

  if(xic_sp.get() != nullptr)
    {

      unsigned int i = 0;
      for(XicCstSPtr xic_in_list : _xic_sp_list)
        {
          if(xic_in_list.get() == xic_sp.get())
            {
              break;
            }
          i++;
        }
      _qcp_xic->drawXicPeakBorders(i, xic_sp.get(), xic_peak.get());
    }
}


void
XicWidget::clearXicPeakBorders()
{
  _qcp_xic->clearXicPeakBorders();
}
