/**
 * \file src/gui/widgets/qcp_massdelta/qcpmassdelta.cpp
 * \date 20/03/2021
 * \author Olivier Langella
 * \brief customized object replacing QCustomPlot
 */


/*******************************************************************************
 * Copyright (c) 2021 Olivier Langella
 *<Olivier.Langella@universite-paris-saclay.fr>.
 *
 * This file is part of XTPcpp.
 *
 *     XTPcpp 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.
 *
 *     XTPcpp 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 XTPcpp.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#include "qcpmassdelta.h"
#include "massdeltawidget.h"
#include "../../../core/project.h"
#include <QDebug>

QCPMassDelta::QCPMassDelta(QWidget *parent) : QCustomPlot(parent)
{
  m_peptideLabel = new QCPItemText(this);
  m_peptideLabel->setVisible(false);
  // m_peptideLabel->setPositionAlignment(Qt::AlignBottom | Qt::AlignHCenter);
  m_peptideLabel->setPositionAlignment(Qt::AlignTop | Qt::AlignHCenter);
  m_peptideLabel->position->setType(QCPItemPosition::ptAxisRectRatio);
  m_peptideLabel->position->setCoords(0.5, 0);

  m_peptideLabel->setFont(QFont(font().family(), 12)); // make font a bit larger


  m_massDeltaLine = new QCPItemStraightLine(this);
  m_massDeltaLine->setVisible(false);
  m_massDeltaLine->setPen(QPen(QColor(0, 0, 255, 150)));


  m_precisionRange = new QCPItemRect(this);
  m_precisionRange->setVisible(false);
  m_precisionRange->setPen(QPen(Qt::NoPen));
  m_precisionRange->setBrush(QBrush(QColor(0, 0, 255, 120)));
  // m_peptideLabel->setPen(QPen(Qt::black));


  mp_precision         = pappso::PrecisionFactory::getPpmInstance(10);
  mpa_currentMassRange = new pappso::MzRange(0, mp_precision);
}

QCPMassDelta::~QCPMassDelta()
{

  if(mpa_currentMassRange != nullptr)
    {
      delete mpa_currentMassRange;
    }
}

void
QCPMassDelta::setMassDeltaWidget(MassDeltaWidget *p_mass_delta_widget)
{
  mp_massDeltaWidget = p_mass_delta_widget;
}

void
QCPMassDelta::mouseMoveEvent(QMouseEvent *event)
{
  double rank = xAxis->pixelToCoord(event->x());
  QCustomPlot::mouseMoveEvent(event);

  if(this->graphCount() > 0)
    {
      QSharedPointer<QCPDataContainer<QCPGraphData>> qsp_pe_list =
        graph(0)->data();

      rankToMass(rank, *(qsp_pe_list.get()));
      // qDebug() << m_currentMass;
    }

  if(msp_currentPeptideEvidence != nullptr)
    {
      qDebug();
    }
}

double
QCPMassDelta::rankToMass(double rank,
                         const QCPDataContainer<QCPGraphData> &container)
{
  double mass = 0;

  if(mpa_currentMassRange != nullptr)
    {
      delete mpa_currentMassRange;
      mpa_currentMassRange = nullptr;
    }
  auto it                    = container.constBegin();
  auto itprev                = container.constBegin();
  msp_currentPeptideEvidence = nullptr;
  m_peptideLabel->setVisible(false);
  m_massDeltaLine->setVisible(false);
  m_precisionRange->setVisible(false);

  while((it != container.constEnd()) && (rank > it->mainKey()))
    {
      itprev = it;
      mass   = it->mainValue();
      it++;
    }
  if(it == container.constEnd())
    {
      mpa_currentMassRange = new pappso::MzRange(mass, mp_precision);
      return mass;
    }
  if(it == itprev)
    {
      mpa_currentMassRange = new pappso::MzRange(mass, mp_precision);
      return mass;
    }
  if(itprev != container.constEnd())
    {
      // interpolation
      qDebug() << "rank=" << rank << " mainKey=" << itprev->mainKey();
      double ratio = rank - itprev->mainKey();
      // qDebug() << "ratio=" << ratio;
      ratio = ratio / (it->mainKey() - itprev->mainKey());

      // qDebug() << "mass=" << mass;
      mass = mass + ((it->mainValue() - itprev->mainValue()) * ratio);

      qDebug();

      setCurrentPeptideEvidenceSp(m_peptideEvidenceSpList.at(it->key));

      // m_peptideLabel->position->setCoords(it->key, it->value);

      qDebug() << ratio;
      if(ratio < 0.5)
        {
          setCurrentPeptideEvidenceSp(m_peptideEvidenceSpList.at(itprev->key));
          // m_peptideLabel->position->setCoords(itprev->key, itprev->value);
        }
      qDebug() << msp_currentPeptideEvidence.get();

      m_peptideLabel->setVisible(true);
      m_peptideLabel->setText(
        msp_currentPeptideEvidence.get()->getPeptideXtpSp().get()->toString());


      m_massDeltaLine->setVisible(true);
      m_massDeltaLine->point1->setCoords(0, mass);
      m_massDeltaLine->point2->setCoords(m_peptideEvidenceSpList.size() - 1,
                                         mass);

      mpa_currentMassRange = new pappso::MzRange(mass, mp_precision);

      m_precisionRange->setVisible(true);
      m_precisionRange->topLeft->setCoords(0, mpa_currentMassRange->upper());
      m_precisionRange->bottomRight->setCoords(
        m_peptideEvidenceSpList.size() - 1, mpa_currentMassRange->lower());
      replot();
    }
  return mass;
}


void
QCPMassDelta::setPeptideEvidenceList(
  const Project *p_project,
  const std::vector<std::shared_ptr<PeptideEvidence>> &peptide_evidence_list_in)
{

  qDebug();
  m_peptideEvidenceSpList = peptide_evidence_list_in;

  std::sort(m_peptideEvidenceSpList.begin(),
            m_peptideEvidenceSpList.end(),
            [](std::shared_ptr<PeptideEvidence> &pa,
               std::shared_ptr<PeptideEvidence> &pb) {
              return pa->getDeltaMass() < pb->getDeltaMass();
            });

  QSharedPointer<QCPGraphDataContainer> qsp_pe_list =
    QSharedPointer<QCPGraphDataContainer>(new QCPGraphDataContainer);
  QSharedPointer<QCPGraphDataContainer> qsp_pe_target_list =
    QSharedPointer<QCPGraphDataContainer>(new QCPGraphDataContainer);

  double i = 0;
  qDebug();
  for(auto &&pe : m_peptideEvidenceSpList)
    {
      qsp_pe_list.get()->add(QCPGraphData(i, pe.get()->getDeltaMass()));

      if(p_project->isTarget(pe.get()))
        {
          qsp_pe_target_list.get()->add(
            QCPGraphData(i, pe.get()->getDeltaMass()));
        }
      i++;
    }
  qDebug();

  graph(0)->setData(qsp_pe_list);
  graph(1)->setData(qsp_pe_target_list);

  graph(0)->rescaleAxes();
  replot();
  qDebug();
}

void
QCPMassDelta::reset()
{
  removeGraph(0);
  removeGraph(1);
  m_peptideEvidenceSpList.clear();
  replot();
}

void
QCPMassDelta::setCurrentPeptideEvidenceSp(
  std::shared_ptr<PeptideEvidence> &currentPeptideEvidence)
{
  if(msp_currentPeptideEvidence.get() != currentPeptideEvidence.get())
    {
      msp_currentPeptideEvidence = currentPeptideEvidence;
      if(mp_massDeltaWidget != nullptr)
        {
          mp_massDeltaWidget->setCurrentPeptideEvidenceSp(
            msp_currentPeptideEvidence);
        }
    }
}


void
QCPMassDelta::mousePressEvent(QMouseEvent *event)
{
  qDebug() << "click";

  if(msp_currentPeptideEvidence.get() != nullptr)
    {
      if(mp_massDeltaWidget != nullptr)
        {
          mp_massDeltaWidget->setSelectedPeptideEvidenceSp(
            msp_currentPeptideEvidence);
        }
    }
  QCustomPlot::mousePressEvent(event);
}
