/**
 * \file src/gui/xic_view/xic_box/xicbox.cpp
 * \date 12/1/2018
 * \author Olivier Langella
 * \brief XIC box widget
 */
/*******************************************************************************
 * Copyright (c) 2018 Olivier Langella <olivier.langella@u-psud.fr>.
 *
 * This file is part of i2MassChroQ.
 *
 *     i2MassChroQ 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.
 *
 *     i2MassChroQ 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 i2MassChroQ.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <olivier.langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "xicbox.h"
#include "ui_xic_box.h"
#include <QMessageBox>
#include <algorithm>
#include <pappsomspp/core/exception/exceptionnotfound.h>
#include "../xicworkerthread.h"
#include "../../project_view/projectwindow.h"
#include <pappsomspp/core/processing/detection/tracedetectionzivy.h>
#include <pappsomspp/core/exception/exceptionnotpossible.h>


bool
XicBoxNaturalIsotope::contains(const pappso::TracePeakCstSPtr &peak) const
{
  try
    {
      auto peak_ptr = peak.get();
      auto found =
        std::find_if(detected_peak_list.begin(),
                     detected_peak_list.end(),
                     [peak_ptr](const pappso::TracePeakCstSPtr &peak_i) {
                       return (peak_i.get() == peak_ptr);
                     });

      return found != detected_peak_list.end();
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

void
XicBoxNaturalIsotope::computeMeanIntensityIn(
  const std::vector<std::size_t> &rt_list)
{
  try
    {
      meanIntensityInCurrentPeak = 0;

      pappso::XicCstSPtr tmp_xic_sp = xic_sp;
      std::size_t nb_rt             = 0;
      for(auto indice : rt_list)
        {

          auto found = std::find_if(
            xic_sp.get()->begin(),
            xic_sp.get()->end(),
            [indice](auto &datapoint) { return (datapoint.x == indice); });
          if(found != xic_sp.get()->end())
            {
              meanIntensityInCurrentPeak += found->y;
              nb_rt++;
            }
        }

      meanIntensityInCurrentPeak /= rt_list.size();
      qDebug() << meanIntensityInCurrentPeak;
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}


class XicDetectionList : public pappso::TraceDetectionSinkInterface
{
  public:
  XicDetectionList()
  {
    _max_peak = nullptr;
  }
  void
  setPeptideEvidenceList(
    const std::vector<const PeptideEvidence *> &peptide_evidence_list)
  {
    for(const PeptideEvidence *p_evidence : peptide_evidence_list)
      {
        _rt_list.push_back(p_evidence->getHardenedRetentionTime());
      }
  }
  void
  setTracePeak(pappso::TracePeak &xic_peak) override
  {
    pappso::TracePeakCstSPtr peak_sp = xic_peak.makeTracePeakCstSPtr();
    _peak_list.push_back(peak_sp);

    for(pappso::pappso_double rt : _rt_list)
      {
        if(xic_peak.containsRt(rt))
          {
            if((_max_peak == nullptr) ||
               (xic_peak.getArea() > _max_peak.get()->getArea()))
              {
                _max_peak = peak_sp;
              }
          }
      }
  };
  const pappso::TracePeakCstSPtr &
  getMatchedPeak() const
  {
    return _max_peak;
  }
  const std::vector<pappso::TracePeakCstSPtr> &
  getXicPeakList() const
  {
    return _peak_list;
  };
  void
  clear()
  {
    _peak_list.clear();
    _max_peak = nullptr;
  };

  private:
  unsigned int _count = 0;
  std::vector<pappso::TracePeakCstSPtr> _peak_list;
  std::vector<pappso::pappso_double> _rt_list;
  pappso::TracePeakCstSPtr _max_peak;
};


XicBox::XicBox(XicWindow *parent) : QWidget(parent), ui(new Ui::XicBox)
{
  _p_xic_window = parent;
  ui->setupUi(this);

  XicWorkerThread *p_worker = new XicWorkerThread(this);
  p_worker->moveToThread(&_xic_thread);
  _xic_thread.start();


  // ui->histo_widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom );
  // ui->xic_list_widget->setLayout(new QVBoxLayout(ui->xic_list_widget));
  ui->histo_widget->legend->setVisible(true);

  // Set the Loading icon
  mp_loadingMovie = new QMovie(":icons/resources/icons/icon_wait.gif");
  //   mp_loadingMovie->setScaledSize(QSize(100, 100));
  ui->loading_label->setMovie(mp_loadingMovie);
  mp_loadingMovie->start();

  showLoadingIcon(true);

  if(_p_xic_window->isRetentionTimeSeconds())
    {
      ui->xic_widget->setRetentionTimeInSeconds();
    }
  else
    {
      ui->xic_widget->setRetentionTimeInMinutes();
    }

#if QT_VERSION >= 0x050000
  // Qt5 code
  connect(this, &XicBox::loadXic, p_worker, &XicWorkerThread::doXicLoad);
  connect(p_worker, &XicWorkerThread::xicLoaded, this, &XicBox::setXic);
  connect(p_worker, &XicWorkerThread::operationFailed, this, &XicBox::error);


  connect(this,
          &XicBox::computeIsotopeMassList,
          p_worker,
          &XicWorkerThread::doComputeIsotopeMassList);
  connect(p_worker,
          &XicWorkerThread::isotopeMassListComputed,
          this,
          &XicBox::setIsotopeMassList);

  connect(
    _p_xic_window, &XicWindow::reExtractXicNeeded, this, &XicBox::reExtractXic);
  /*  connect(ui->xic_widget,
          qOverload<std::vector<std::pair<pappso::XicCstSPtr,
  pappso::XicPeakSp>>>( &pappso::XicWidget::xicPeakListChanged), this,
          &XicBox::setXicPeakList);

  connect(ui->xic_widget,
          &pappso::XicWidget::clicked,
          this,
          &XicBox::onXicWidgetClick);
*/
  connect(_p_xic_window,
          &XicWindow::rtUnitChangeNeeded,
          this,
          &XicBox::onRtUnitChanged);

  /** @brief Handle axis size to move simultaneously in boxs
   */
  connect(ui->xic_widget->getRtAxisP(),
          qOverload<const QCPRange &>(&QCPAxis::rangeChanged),
          this,
          &XicBox::doGetNewRtRange);
  connect(ui->xic_widget->getIntensityAxisP(),
          qOverload<const QCPRange &>(&QCPAxis::rangeChanged),
          this,
          &XicBox::doGetNewIntensityRange);
  connect(
    this, &XicBox::fitAxisRangeInXics, _p_xic_window, &XicWindow::doFitAllAxis);

#else
// Qt4 code
#endif


  QStringList msrun_list;
  for(MsRunSp msrun_sp : _p_xic_window->getProjectWindow()
                           ->getProjectP()
                           ->getMsRunStore()
                           .getMsRunList())
    {
      msrun_list << msrun_sp.get()->getFileName();
      qDebug() << "ProteinListWindow::setIdentificationGroup "
               << msrun_sp.get()->getFileName();
    }
}

XicBox::~XicBox()
{
  qDebug() << "XicBox::~XicBox";
  _xic_thread.quit();
  _xic_thread.wait();
}

void
XicBox::rescaleXicWidget(QString axis_name, QCPRange new_range)
{
  ui->xic_widget->rescaleOneRange(axis_name, new_range);
}

void
XicBox::doGetNewRtRange(QCPRange new_range)
{
  emit fitAxisRangeInXics("xAxis", new_range);
}

void
XicBox::doGetNewIntensityRange(QCPRange new_range)
{
  emit fitAxisRangeInXics("yAxis", new_range);
}

QCPRange
XicBox::getRtRange()
{
  return ui->xic_widget->getRtAxisP()->range();
}


void
XicBox::onXicWidgetClick(double rt [[maybe_unused]],
                         double intensity [[maybe_unused]])
{
  qDebug();
  try
    {
      ui->xic_widget->clearXicPeakBorders();
      std::vector<pappso::TracePeakCstSPtr> draw_peak_borders;
      for(XicBoxNaturalIsotope peak : _natural_isotope_list)
        {
          qDebug();
          draw_peak_borders.push_back(peak.one_peak_sp);
          if(peak.one_peak_sp.get() != nullptr)
            {
              ui->xic_widget->drawXicPeakBorders(peak.one_peak_sp);
            }
        }

      if(_peptide_evidence_list.size() == 0)
        {
          drawObservedAreaBars(draw_peak_borders);
        }
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

void
XicBox::remove()
{
  _p_xic_window->removeXicBox(this);
}

void
XicBox::error(QString error_message)
{
  QMessageBox::warning(this, tr("Error extracting XIC :"), error_message);
}

void
XicBox::extractXicInOtherMsRun()
{
  qDebug();
  try
    {
      QString location =
        QFileInfo(_p_peptide_evidence->getMsRunP()->getFileName())
          .absoluteDir()
          .absolutePath();

      QStringList filenames = QFileDialog::getOpenFileNames(
        this,
        tr("select peak list files"),
        location,
        tr("any mz files (*.mzXML *.mzxml *.mzML *.mzml *.mgf *.tdf);;mzXML "
           "(*.mzXML "
           "*.mzxml);;mzML (*.mzML *.mzml);;MGF (*.mgf);; tdf (*.tdf);;all "
           "files (*)"));

      foreach(QString new_filename, filenames)
        {
          MsRunSp msrun_sp = _p_xic_window->getProjectWindow()
                               ->getProjectP()
                               ->getMsRunStore()
                               .getInstance(new_filename);
          _p_xic_window->addXicInMsRun(_p_peptide_evidence, msrun_sp);
        }
    }
  catch(pappso::ExceptionNotFound &error)
    {
      qDebug() << " not found ";
    }
}

void
XicBox::setPeptideEvidence(const PeptideEvidence *p_peptide_evidence)
{
  try
    {
      showLoadingIcon(true);
      _p_peptide_evidence = p_peptide_evidence;
      _msrun_sp =
        p_peptide_evidence->getIdentificationDataSource()->getMsRunSp();

      ui->peptide_label->setText(
        _p_peptide_evidence->getPeptideXtpSp().get()->toString());
      ui->charge_label->setText(
        QString("%1").arg(_p_peptide_evidence->getCharge()));
      ui->mz_label->setText(
        QString::number(_p_peptide_evidence->getTheoreticalMz(), 'f', 4));
      ui->msrun_label->setText(
        _p_peptide_evidence->getMsRunP()->getSampleName());
      ui->msrun_label->setToolTip("Sample name");
      // get same xic peptide evidence (msrun, peptide, charge)
      // p_projet
      _peptide_evidence_list.clear();
      _p_xic_window->getProjectWindow()
        ->getProjectP()
        ->getSameXicPeptideEvidenceList(
          _peptide_evidence_list,
          _msrun_sp.get(),
          _p_peptide_evidence->getPeptideXtpSp().get(),
          _p_peptide_evidence->getCharge());

      emit computeIsotopeMassList(_p_peptide_evidence->getPeptideXtpSp(),
                                  _p_peptide_evidence->getCharge(),
                                  _p_xic_window->getXicExtractPrecision(),
                                  ui->isotopic_distribution_spinbox->value());
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

void
XicBox::setPeptideEvidenceInMsRun(const PeptideEvidence *p_peptide_evidence,
                                  MsRunSp msrun_sp)
{
  try
    {
      showLoadingIcon(true);
      _p_peptide_evidence = p_peptide_evidence;
      _msrun_sp           = msrun_sp;

      ui->peptide_label->setText(
        _p_peptide_evidence->getPeptideXtpSp().get()->toString());
      ui->charge_label->setText(
        QString("%1").arg(_p_peptide_evidence->getCharge()));
      ui->mz_label->setText(
        QString::number(_p_peptide_evidence->getTheoreticalMz(), 'f', 4));
      ui->msrun_label->setText(QFileInfo(msrun_sp->getFileName()).fileName());
      ui->msrun_label->setToolTip(msrun_sp->getFileName());
      // get same xic peptide evidence (msrun, peptide, charge)
      // p_projet
      _peptide_evidence_list.clear();

      _p_xic_window->getProjectWindow()
        ->getProjectP()
        ->getSameXicPeptideEvidenceList(
          _peptide_evidence_list,
          _msrun_sp.get(),
          _p_peptide_evidence->getPeptideXtpSp().get(),
          _p_peptide_evidence->getCharge());
      //_p_xic_window->getProjectWindow()->getProjectP()->getSameXicPeptideEvidenceList(p_peptide_evidence,
      //_peptide_evidence_list);

      emit computeIsotopeMassList(_p_peptide_evidence->getPeptideXtpSp(),
                                  _p_peptide_evidence->getCharge(),
                                  _p_xic_window->getXicExtractPrecision(),
                                  ui->isotopic_distribution_spinbox->value());
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

const PeptideEvidence *
XicBox::getPeptideEvidenceP() const
{
  return _p_peptide_evidence;
}

MsRunSp
XicBox::getMsRunSp()
{
  return _msrun_sp;
}

void
XicBox::setXic(std::vector<pappso::XicCoordSPtr> xic_sp_list)
{
  try
    {
      qDebug() << xic_sp_list.size() << _natural_isotope_list.size();
      ui->xic_widget->clear();
      for(pappso::XicCoordSPtr &xic_coord_sp : xic_sp_list)
        {
          //_natural_isotope_list[i].xic_sp = xic_sp_list[i];
          if(xic_coord_sp.get()->xicSptr == nullptr)
            {
              throw pappso::PappsoException(
                QString(
                  "Error in %1 %2 %3:\nxic_coord_sp.get()->xicSptr == nullptr")
                  .arg(__FILE__)
                  .arg(__FUNCTION__)
                  .arg(__LINE__));
            }
          qDebug() << xic_coord_sp.get()->xicSptr.get()->size();
          if(xic_coord_sp.get()->xicSptr.get()->size() == 0)
            {
              throw pappso::PappsoException(
                QString("Error in %1 %2 "
                        "%3:\nxic_coord_sp.get()->xicSptr.get()->size() == 0")
                  .arg(__FILE__)
                  .arg(__FUNCTION__)
                  .arg(__LINE__));
            }
          bool found = false;
          for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
            {
              if(xic_isotope.xic_sp.get() == xic_coord_sp.get()->xicSptr.get())
                {
                  found = true;
                }
            }

          if(found == false)
            { /*
               throw pappso::PappsoException(
                 QString(
                   "Error in %1 %2 %3:\nthis is not the result we are waiting
               for") .arg(__FILE__) .arg(__FUNCTION__) .arg(__LINE__));*/
              // this is not the result we are waiting for
              return;
            }
        }
      // pappso::XicWidget * xic_widget = new pappso::XicWidget(this);
      // ui->xic_list_widget->layout()->addWidget(xic_widget);
      for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          // qDebug() << "XicBox::setXic xic " << xic_isotope.xic_sp.get();
          if(xic_isotope.xic_sp.get() == nullptr)
            {
              throw pappso::PappsoException(
                "Error in XicBox::setXic:\n xic_isotope.xic_sp.get() == "
                "nullptr");
            }
          qDebug() << xic_isotope.xic_sp.get()->size();
          if(xic_isotope.xic_sp.get()->size() == 0)
            {
              throw pappso::PappsoException(
                "Error in XicBox::setXic:\n xic_isotope.xic_sp.get()->size() "
                "== 0");
            }
          ui->xic_widget->addXicSp(xic_isotope.xic_sp);
          QString isotope_name = QString("+%1").arg(
            xic_isotope.peptide_natural_isotope_sp.get()->getIsotopeNumber());
          if(xic_isotope.peptide_natural_isotope_sp.get()->getIsotopeRank() > 1)
            {
              isotope_name =
                QString("+%1 [%2]")
                  .arg(xic_isotope.peptide_natural_isotope_sp.get()
                         ->getIsotopeNumber())
                  .arg(xic_isotope.peptide_natural_isotope_sp.get()
                         ->getIsotopeRank());
            }
          isotope_name.append(QString(" (%1%)").arg(
            (int)(xic_isotope.peptide_natural_isotope_sp.get()
                    ->getIntensityRatio() *
                  100)));
          ui->xic_widget->setName(xic_isotope.xic_sp.get(), isotope_name);

          if(xic_isotope.peptide_natural_isotope_sp.get()->getIsotopeNumber() ==
             0)
            {
              for(const PeptideEvidence *peptide_evidence :
                  _peptide_evidence_list)
                {
                  qDebug() << peptide_evidence->getHardenedRetentionTime();
                  ui->xic_widget->addMsMsEvent(
                    xic_isotope.xic_sp.get(),
                    peptide_evidence->getHardenedRetentionTime());
                }
            }
        }
      qDebug();

      if(!_scaled)
        {
          ui->xic_widget->rescale();
          _scaled = true;
        }

      /*
      if (_isotope_mass_list.size() > _xic_widget_list.size()) {
          emit loadXic(_p_peptide_evidence->getMsRunP(),
      _isotope_mass_list[_xic_widget_list.size()].get()->getMz(),
      _p_xic_window->getXicExtractPrecision(), XicExtractMethod::max);
      }
      */
      XicDetectionList xic_list;
      xic_list.setPeptideEvidenceList(_peptide_evidence_list);

      std::vector<pappso::TracePeakCstSPtr> draw_peak_borders;

      for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          try
            {
              xic_list.clear();
              _p_xic_window->xicDetect(*(xic_isotope.xic_sp.get()), &xic_list);
              xic_isotope.matched_peak_sp = xic_list.getMatchedPeak();
              qDebug() << "size : " << xic_list.getXicPeakList().size();
              xic_isotope.detected_peak_list = xic_list.getXicPeakList();
              ui->xic_widget->addXicPeakList(xic_isotope.xic_sp.get(),
                                             xic_list.getXicPeakList());
              draw_peak_borders.push_back(xic_isotope.matched_peak_sp);
            }
          catch(const pappso::ExceptionNotPossible &e)
            {
              qDebug() << e.qwhat();
            }
        }
      qDebug() << "XicBox::setXic plot";
      ui->xic_widget->plot();
      drawObservedAreaBars(draw_peak_borders);
      showLoadingIcon(false);
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}


void
XicBox::drawObservedAreaBars(
  const std::vector<pappso::TracePeakCstSPtr> &observed_peak_to_draw_list)
{
  try
    {
      if(m_observedAreaBars == nullptr)
        {
          qDebug() << " new QCPBars";
          m_observedAreaBars =
            new QCPBars(ui->histo_widget->xAxis, ui->histo_widget->yAxis2);
          //       m_observedRatioBars = new QCPBars(ui->histo_widget->xAxis,
          //       ui->histo_widget->yAxis);
        }
      else
        {
          qDebug() << "plot clearData";
          m_observedAreaBars->data().clear();
          //       m_observedRatioBars->data().clear();
        }
      m_observedAreaBars->setName("peak area");
      //   m_observedRatioBars->setName("obs. ratio");
      // ui->histo_widget->yAxis2->setLabel("intensity");


      QVector<double> observed_intensity_data;
      QVector<double> observed_ratio_data;
      QVector<QString> labels;

      QVector<double> ticks;
      double sum = 0;
      int i      = 0;

      std::vector<std::size_t> common_peak_rt_measure_list;

      qDebug() << " plot _isotope_mass_list";
      for(const XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          pappso::TracePeakCstSPtr peak_to_draw;
          for(pappso::TracePeakCstSPtr observed_peak :
              observed_peak_to_draw_list)
            {
              if(xic_isotope.contains(observed_peak))
                {
                  qDebug() << "OK";
                  peak_to_draw = observed_peak;
                }
            }
          if(peak_to_draw.get() == nullptr)
            {
            }
          else
            {
              addCommonRt(common_peak_rt_measure_list,
                          peak_to_draw.get(),
                          xic_isotope.xic_sp.get());


              sum += peak_to_draw.get()->getArea();
              observed_intensity_data << peak_to_draw.get()->getArea();
              QString isotope_name =
                QString("+%1").arg(xic_isotope.peptide_natural_isotope_sp.get()
                                     ->getIsotopeNumber());
              if(xic_isotope.peptide_natural_isotope_sp.get()
                   ->getIsotopeRank() > 1)
                {
                  isotope_name =
                    QString("+%1 [%2]")
                      .arg(xic_isotope.peptide_natural_isotope_sp.get()
                             ->getIsotopeNumber())
                      .arg(xic_isotope.peptide_natural_isotope_sp.get()
                             ->getIsotopeRank());
                }
              isotope_name.append(QString(" (%1%)").arg(
                (int)(xic_isotope.peptide_natural_isotope_sp.get()
                        ->getIntensityRatio() *
                      100)));
              labels << isotope_name;
              ticks << i;
            }
          i++;
        }

      //   m_observedRatioBars->setPen(QPen(QColor("red")));
      m_observedAreaBars->setPen(QColor(180, 15, 32, 200));
      m_observedAreaBars->setBrush(QColor(180, 15, 32, 200));
      //_graph_peak_surface_list.back()->setScatterStyle(QCPScatterStyle::ssDot);
      // observed_intensity->setBrush(QBrush(QColor(170, 255, 0, 0)));

      double sum_observed_ratio = 0;
      double total_ratio        = 0;
      for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          xic_isotope.computeMeanIntensityIn(common_peak_rt_measure_list);

          sum_observed_ratio += xic_isotope.meanIntensityInCurrentPeak;
          total_ratio +=
            xic_isotope.peptide_natural_isotope_sp.get()->getIntensityRatio();
        }
      for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          observed_ratio_data
            << ((xic_isotope.meanIntensityInCurrentPeak / sum_observed_ratio) *
                total_ratio);
        }

      if(ticks.size() > 0)
        {
          for(double &tick : ticks)
            {
              tick += 0.1;
            }
          m_observedAreaBars->setData(ticks, observed_intensity_data);
          m_observedAreaBars->setWidth(0.6);

          //       QVector<QString> labels;
          //       for(double tick : ticks)
          //         {
          //           labels.push_back(QString::number(tick));
          //         }
          //       QSharedPointer<QCPAxisTickerText> textTicker(new
          //       QCPAxisTickerText); textTicker->addTicks(ticks, labels);
          //       ui->histo_widget->yAxis->setTicker(textTicker);
          //       m_observedRatioBars->setData(ticks, observed_ratio_data);

          ui->histo_widget->yAxis2->setVisible(true);
          ui->histo_widget->yAxis2->setRange(0, sum);
          ui->histo_widget->yAxis2->setLabel("observed intensity");
          ui->histo_widget->yAxis2->setLabelPadding(0);
          ui->histo_widget->replot();
        }
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
  qDebug();
}


void
XicBox::setIsotopeMassList(
  std::vector<pappso::PeptideNaturalIsotopeAverageSp> isotope_mass_list)
{
  try
    {
      _natural_isotope_list.clear();

      MasschroqFileParametersSp params = _p_xic_window->getProjectWindow()
                                           ->getProjectSP()
                                           .get()
                                           ->getMasschroqFileParametersSp();
      pappso::XicCoordSPtr xic_coord_ref =
        _msrun_sp.get()
          ->getMsRunReaderSPtr()
          .get()
          ->newXicCoordSPtrFromSpectrumIndex(
            _p_peptide_evidence->getSpectrumIndexByScanNumber(),
            params.get()
              ->m_quantificationMethod.getXicExtractionUppersPrecisionPtr());

      std::vector<pappso::XicCoordSPtr> mass_list;
      for(pappso::PeptideNaturalIsotopeAverageSp &natural_isotope_average :
          isotope_mass_list)
        {
          qDebug() << natural_isotope_average.get()->getMz();
          pappso::XicCoordSPtr xic_coord =
            xic_coord_ref.get()->initializeAndClone();
          xic_coord.get()->mzRange = pappso::MzRange(
            natural_isotope_average.get()->getMz(),
            params.get()
              ->m_quantificationMethod.getXicExtractionUppersPrecisionPtr());
          mass_list.push_back(xic_coord);

          _natural_isotope_list.push_back({xic_coord.get()->xicSptr,
                                           natural_isotope_average,
                                           nullptr,
                                           nullptr,
                                           {}});
        }

      emit loadXic(_msrun_sp,
                   mass_list,
                   _p_xic_window->getProjectWindow()
                     ->getProjectSP()
                     .get()
                     ->getMasschroqFileParametersSp());

      // histogram
      if(m_theoreticalRatioBars == nullptr)
        {
          m_theoreticalRatioBars =
            new QCPBars(ui->histo_widget->xAxis, ui->histo_widget->yAxis);
        }
      else
        {
          m_theoreticalRatioBars->data()->clear();
        }
      m_theoreticalRatioBars->setName("th. ratio");
      ui->histo_widget->xAxis->setLabel("isotopes");
      m_theoreticalRatioBars->setPen(QColor(59, 154, 178));
      m_theoreticalRatioBars->setBrush(QColor(59, 154, 178));
      // ui->histo_widget->yAxis->setLabel("th. ratio");

      QVector<double> theoretical_ratio_data;

      QVector<double> ticks;
      QVector<QString> labels;
      int i      = 0;
      double sum = 0;
      for(const XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          sum +=
            xic_isotope.peptide_natural_isotope_sp.get()->getIntensityRatio();
          theoretical_ratio_data
            << xic_isotope.peptide_natural_isotope_sp.get()
                 ->getIntensityRatio();
          QString isotope_name = QString("+%1").arg(
            xic_isotope.peptide_natural_isotope_sp.get()->getIsotopeNumber());
          if(xic_isotope.peptide_natural_isotope_sp.get()->getIsotopeRank() > 1)
            {
              isotope_name =
                QString("+%1 [%2]")
                  .arg(xic_isotope.peptide_natural_isotope_sp.get()
                         ->getIsotopeNumber())
                  .arg(xic_isotope.peptide_natural_isotope_sp.get()
                         ->getIsotopeRank());
            }
          isotope_name.append(QString(" (%1%)").arg(
            (int)(xic_isotope.peptide_natural_isotope_sp.get()
                    ->getIntensityRatio() *
                  100)));
          labels << QString::number(
            xic_isotope.peptide_natural_isotope_sp.get()->getIsotopeNumber());
          ticks << i;
          i++;
        }
      QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
      textTicker->addTicks(ticks, labels);
      ui->histo_widget->xAxis->setTicker(textTicker);
      ui->histo_widget->xAxis->setTickLabelRotation(0);
      // ui->histo_widget->xAxis->setSubTicks(false);
      // ui->histo_widget->xAxis->setTickLength(0, 4);
      // ui->histo_widget->xAxis->setRange(0, 8);
      /*
        ui->histo_widget->xAxis->setAutoTickStep(
          false); // <-- disable to use your own value

        ui->histo_widget->xAxis->setTickStep(1);
      */
      for(double &tick : ticks)
        {
          tick -= 0.1;
        }
      m_theoreticalRatioBars->setData(ticks, theoretical_ratio_data);
      m_theoreticalRatioBars->setWidth(0.6);


      ui->histo_widget->yAxis->setRange(0, sum);
      ui->histo_widget->yAxis->setLabel("intensity ratio");
      ui->histo_widget->yAxis->setLabelPadding(0);
      ui->histo_widget->xAxis->setRange(-0.5,
                                        _natural_isotope_list.size() - 0.5);
      ui->histo_widget->replot();
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}


void
XicBox::reExtractXic()
{
  try
    {
      qDebug();
      ui->xic_widget->clear();

      MasschroqFileParametersSp params = _p_xic_window->getProjectWindow()
                                           ->getProjectSP()
                                           .get()
                                           ->getMasschroqFileParametersSp();


      pappso::XicCoordSPtr xic_coord_ref =
        _msrun_sp.get()
          ->getMsRunReaderSPtr()
          .get()
          ->newXicCoordSPtrFromSpectrumIndex(
            _p_peptide_evidence->getSpectrumIndexByScanNumber(),
            params.get()
              ->m_quantificationMethod.getXicExtractionUppersPrecisionPtr());

      std::vector<pappso::XicCoordSPtr> mass_list;
      for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          pappso::XicCoordSPtr xic_coord =
            xic_coord_ref.get()->initializeAndClone();
          xic_coord.get()->mzRange =
            params.get()->m_quantificationMethod.getXicExtractionMzRange(
              xic_isotope.peptide_natural_isotope_sp.get()->getMz());
          mass_list.push_back(xic_coord);
          xic_isotope.xic_sp = xic_coord.get()->xicSptr;
        }

      qDebug();
      emit loadXic(_msrun_sp,
                   mass_list,
                   _p_xic_window->getProjectWindow()
                     ->getProjectSP()
                     .get()
                     ->getMasschroqFileParametersSp());

      qDebug();
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

void
XicBox::setRetentionTime(double rt)
{
  qDebug() << " begin";
  ui->rt_label->setText(tr("rt=%1 (sec) rt=%2 (min)").arg(rt).arg(rt / 60));
}
void
XicBox::setXicPeakList(
  std::vector<std::pair<pappso::XicCstSPtr, pappso::TracePeakCstSPtr>>
    xic_peak_list)
{
  try
    {
      qDebug() << " begin";
      QString html;
      for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
        {
          xic_isotope.one_peak_sp = nullptr;
        }

      for(std::pair<pappso::XicCstSPtr, pappso::TracePeakCstSPtr>
            &pair_xic_peak : xic_peak_list)
        {
          for(XicBoxNaturalIsotope &xic_isotope : _natural_isotope_list)
            {
              if(xic_isotope.xic_sp.get() == pair_xic_peak.first.get())
                {
                  xic_isotope.one_peak_sp = pair_xic_peak.second;
                }
            }
          html.append(
            tr("<p>%1<br/>area: %2<br/>rt begin: %3<br/>rt max: "
               "%4<br/>rt end: %5<br/></p>")
              .arg(ui->xic_widget->getName(pair_xic_peak.first.get()))
              .arg(QString::number(
                std::trunc(pair_xic_peak.second.get()->getArea()), 'G', 16))
              .arg(pair_xic_peak.second.get()->getLeftBoundary().x)
              .arg(pair_xic_peak.second.get()->getMaxXicElement().x)
              .arg(pair_xic_peak.second.get()->getRightBoundary().x));
        }

      ui->xic_widget->setToolTip(html);
      /*
          if (_popup_peak_info == nullptr) delete _popup_peak_info;
          _popup_peak_info = new QFrame( this ,Qt::Popup);
          //_popup_peak_info->setFrameStyle(Qt::WinPanel|Qt::Raised );
          _popup_peak_info->resize(150,100);
          _popup_peak_info->show();
          */
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}


void
XicBox::onRtUnitChanged()
{
  try
    {
      if(_p_xic_window->isRetentionTimeSeconds())
        {
          ui->xic_widget->setRetentionTimeInSeconds();
        }
      else
        {
          ui->xic_widget->setRetentionTimeInMinutes();
        }
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

void
XicBox::onIsotopicDistributionClick()
{
  //   ui->histo_widget->legend->clear();
  try
    {
      setPeptideEvidence(_p_peptide_evidence);
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

void
XicBox::addCommonRt(std::vector<std::size_t> &common_peak_rt_measure_list,
                    const pappso::TracePeak *peak,
                    const pappso::Xic *xic) const
{
  try
    {

      if(common_peak_rt_measure_list.size() == 0)
        { // no common peaks, filling with whole peak
          auto it = pappso::findFirstEqualOrGreaterX(
            xic->begin(), xic->end(), peak->getLeftBoundary().x);
          auto itend = pappso::findFirstGreaterX(
            xic->begin(), xic->end(), peak->getRightBoundary().x);

          std::size_t i = it - xic->begin();

          while(it != itend)
            {
              if(it->y > (0.6 * peak->getMaxXicElement().y))
                {
                  common_peak_rt_measure_list.push_back(i);
                }
              it++;
              i++;
            }
        }
      else
        {
          std::vector<std::size_t> intersect(common_peak_rt_measure_list);
          std::vector<std::size_t> new_rt;
          auto it = pappso::findFirstEqualOrGreaterX(
            xic->begin(), xic->end(), peak->getLeftBoundary().x);
          auto itend = pappso::findFirstGreaterX(
            xic->begin(), xic->end(), peak->getRightBoundary().x);

          std::size_t i = it - xic->begin();
          while(it != itend)
            {
              if(it->y > 0)
                {
                  new_rt.push_back(i);
                }
              it++;
              i++;
            }

          auto itinter =
            std::set_intersection(intersect.begin(),
                                  intersect.end(),
                                  new_rt.begin(),
                                  new_rt.end(),
                                  common_peak_rt_measure_list.begin());
          common_peak_rt_measure_list.resize(
            itinter - common_peak_rt_measure_list.begin());
          /*
                for(auto indice : common_peak_rt_measure_list)
                  {
                    qDebug() << indice << " " << xic->at(indice).x << " "
                             << xic->at(indice).y;
                  }
                  */
        }
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 :\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(error.qwhat()));
    }
  catch(std::exception &std_error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 std_error:\n%3")
                                      .arg(__FILE__)
                                      .arg(__FUNCTION__)
                                      .arg(std_error.what()));
    }
}

std::vector<XicBoxNaturalIsotope>
XicBox::getNaturalIsotopList() const
{
  return _natural_isotope_list;
}

double
XicBox::getIsotopicFractionDistribution() const
{
  return ui->isotopic_distribution_spinbox->value();
}

void
XicBox::showLoadingIcon(bool loading_status)
{
  ui->loading_label->setVisible(loading_status);
  if(loading_status)
    {
      int size = ui->xic_widget->size().rheight() * 0.5;
      mp_loadingMovie->setScaledSize(QSize(size, size));
    }

  ui->xic_widget->setVisible(!loading_status);
  ui->histo_widget->setVisible(!loading_status);
}
