/*
 * *******************************************************************************
 * * Copyright (c) 2015 Olivier Langella <Olivier.Langella@moulon.inra.fr>.
 * *
 * * This file is part of MassChroqPRM.
 * *
 * *     MassChroqPRM 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.
 * *
 * *     MassChroqPRM 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 MassChroqPRM.  If not, see <http://www.gnu.org/licenses/>.
 * *
 * * Contributors:
 * *     Olivier Langella <Olivier.Langella@moulon.inra.fr> - initial API and
 * implementation
 * ******************************************************************************/


#include "peptideisotopespectrummatch.h"

namespace pappso
{
PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch(
  const MassSpectrum &spectrum,
  const PeptideSp &peptideSp,
  unsigned int parent_charge,
  PrecisionPtr precision,
  std::list<PeptideIon> ion_type_list,
  unsigned int max_isotope_number,
  [[maybe_unused]] unsigned int max_isotope_rank)
  : _precision(precision)
{

  try
    {
      qDebug() << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch "
                  "begin max_isotope_number="
               << max_isotope_number;
      PeptideFragmentIonListBase fragmentIonList(peptideSp, ion_type_list);
      qDebug() << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch "
                  "peak_list spectrum.size="
               << spectrum.size();
      std::list<DataPoint> peak_list(spectrum.begin(), spectrum.end());

      qDebug() << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch "
                  "ion_type_list";
      for(auto ion_type : ion_type_list)
        {
          auto ion_list = fragmentIonList.getPeptideFragmentIonSp(ion_type);
          qDebug() << "PeptideIsotopeSpectrumMatch::"
                      "PeptideIsotopeSpectrumMatch fragmentIonList";

          for(unsigned int charge = 1; charge <= parent_charge; charge++)
            {
              for(auto &&ion : ion_list)
                {
                  unsigned int askedIsotopeRank = 1;
                  for(unsigned int isotope_number = 0;
                      isotope_number <= max_isotope_number;
                      isotope_number++)
                    {
                      PeptideNaturalIsotopeAverage isotopeIon(ion,
                                                              askedIsotopeRank,
                                                              isotope_number,
                                                              charge,
                                                              precision);

                      std::list<DataPoint>::iterator it_peak =
                        getBestPeakIterator(peak_list, isotopeIon);
                      if(it_peak != peak_list.end())
                        {
                          _peak_ion_match_list.push_back(PeakIonIsotopeMatch(
                            *it_peak,
                            isotopeIon.makePeptideNaturalIsotopeAverageSp(),
                            ion));
                          peak_list.erase(it_peak);
                        }
                    }
                }
            }
        }
      qDebug()
        << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch end";
    }
  catch(PappsoException &exception_pappso)
    {
      QString errorStr =
        QObject::tr(
          "ERROR building PeptideIsotopeSpectrumMatch, PAPPSO exception:\n%1")
          .arg(exception_pappso.qwhat());
      qDebug() << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch "
                  "PappsoException :\n"
               << errorStr;
      throw PappsoException(errorStr);
    }
  catch(std::exception &exception_std)
    {
      QString errorStr =
        QObject::tr(
          "ERROR building PeptideIsotopeSpectrumMatch, std exception:\n%1")
          .arg(exception_std.what());
      qDebug() << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch "
                  "std::exception :\n"
               << errorStr;
      throw PappsoException(errorStr);
    }
}

PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch(
  const MassSpectrum &spectrum,
  std::vector<PeptideNaturalIsotopeAverageSp> v_peptideIsotopeList,
  std::vector<PeptideFragmentIonSp> v_peptideIonList,
  PrecisionPtr precision)
  : _precision(precision)
{
  qDebug() << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch begin";
  if(v_peptideIsotopeList.size() != v_peptideIonList.size())
    {
      throw PappsoException(
        QObject::tr(
          "v_peptideIsotopeList.size() %1 != v_peptideIonList.size() %2")
          .arg(v_peptideIsotopeList.size())
          .arg(v_peptideIonList.size()));
    }

  auto isotopeIt = v_peptideIsotopeList.begin();
  auto ionIt     = v_peptideIonList.begin();
  std::list<DataPoint> peak_list(spectrum.begin(), spectrum.end());

  while(isotopeIt != v_peptideIsotopeList.end())
    {
      std::list<DataPoint>::iterator it_peak =
        getBestPeakIterator(peak_list, *(isotopeIt->get()));
      if(it_peak != peak_list.end())
        {
          _peak_ion_match_list.push_back(
            PeakIonIsotopeMatch(*it_peak, *isotopeIt, *ionIt));
          peak_list.erase(it_peak);
        }
      isotopeIt++;
      ionIt++;
    }
  qDebug() << "PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch end";
}


PeptideIsotopeSpectrumMatch::PeptideIsotopeSpectrumMatch(
  const PeptideIsotopeSpectrumMatch &other)
  : _precision(other._precision),
    _peak_ion_match_list(other._peak_ion_match_list)
{
}

PeptideIsotopeSpectrumMatch::~PeptideIsotopeSpectrumMatch()
{
}


std::list<DataPoint>::iterator
PeptideIsotopeSpectrumMatch::getBestPeakIterator(
  std::list<DataPoint> &peak_list,
  const PeptideNaturalIsotopeAverage &ion) const
{
  // qDebug();
  std::list<DataPoint>::iterator itpeak   = peak_list.begin();
  std::list<DataPoint>::iterator itend    = peak_list.end();
  std::list<DataPoint>::iterator itselect = peak_list.end();

  pappso_double best_intensity = 0;

  while(itpeak != itend)
    {
      if(ion.matchPeak(itpeak->x))
        {
          if(itpeak->y > best_intensity)
            {
              best_intensity = itpeak->y;
              itselect       = itpeak;
            }
        }
      itpeak++;
    }
  // qDebug();
  return (itselect);
}

const std::list<PeakIonIsotopeMatch> &
PeptideIsotopeSpectrumMatch::getPeakIonIsotopeMatchList() const
{
  return _peak_ion_match_list;
}


} // namespace pappso
