/**
 * \file pappsomspp/peptide/peptidefragmentionlistbase.cpp
 * \date 10/3/2015
 * \author Olivier Langella
 * \brief fragmentation base object
 */

/*******************************************************************************
 * Copyright (c) 2015 Olivier Langella <Olivier.Langella@moulon.inra.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@moulon.inra.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "peptidefragmentionlistbase.h"

#include <QDebug>
#include <memory>
#include "pappsomspp/core/pappsoexception.h"

namespace pappso
{

std::list<Enums::PeptideIon>
PeptideFragmentIonListBase::getCIDionList()
{
  IonList ret;
  // populate ret

  ret.push_back(Enums::PeptideIon::y);
  ret.push_back(Enums::PeptideIon::yp);
  ret.push_back(Enums::PeptideIon::ystar);
  ret.push_back(Enums::PeptideIon::yo);
  ret.push_back(Enums::PeptideIon::b);
  ret.push_back(Enums::PeptideIon::bp);
  ret.push_back(Enums::PeptideIon::a);
  ret.push_back(Enums::PeptideIon::bstar);
  ret.push_back(Enums::PeptideIon::bo);
  return ret;
}

std::list<Enums::PeptideIon>
PeptideFragmentIonListBase::getETDionList()
{
  IonList ret;
  // populate ret

  ret.push_back(Enums::PeptideIon::y);
  ret.push_back(Enums::PeptideIon::c);
  ret.push_back(Enums::PeptideIon::z);
  ret.push_back(Enums::PeptideIon::ystar);
  ret.push_back(Enums::PeptideIon::yo);
  return ret;
}

const std::list<Enums::PeptideIon> &
PeptideFragmentIonListBase::getIonList() const
{
  return m_ionList;
}

PeptideFragmentIonListBase::PeptideFragmentIonListBase(const PeptideSp &peptide,
                                                       const IonList &ions)
  : msp_peptide(peptide), m_ionList(ions)
{
  try
    {
      qDebug() << "PeptideFragmentIonListBase::PeptideFragmentIonListBase begin " << ions.size();
      std::list<PeptideFragmentSp> fragment_list =
        PeptideFragmentIonListBase::getPeptideFragmentList(msp_peptide);

      m_phosphorylationNumber             = 0;
      AaModificationP phosphorylation_mod = nullptr;


      qDebug();
      for(auto &&fragment_sp : fragment_list)
        {
          // qDebug()<< "PeptideFragmentIonListBase::PeptideFragmentIonListBase
          // ition";
          if(fragment_sp.get()->getPeptideIonDirection() == PeptideDirection::Cter)
            {
              for(auto &&ion_type : m_ionList)
                {
                  // qDebug()<<
                  // "PeptideFragmentIonListBase::PeptideFragmentIonListBase
                  // ition";
                  if((ion_type == Enums::PeptideIon::y) || (ion_type == Enums::PeptideIon::ystar) ||
                     (ion_type == Enums::PeptideIon::yo) || (ion_type == Enums::PeptideIon::z))
                    {
                      msp_peptide_fragment_ion_list.push_back(
                        std::make_shared<PeptideFragmentIon>(fragment_sp, ion_type));
                    }
                  else if(ion_type == Enums::PeptideIon::yp)
                    {
                      if(phosphorylation_mod == nullptr)
                        {
                          phosphorylation_mod = AaModification::getInstance("MOD:00696");
                          m_phosphorylationNumber =
                            peptide.get()->getNumberOfModification(phosphorylation_mod);
                        }
                      for(unsigned int i = 0; i < m_phosphorylationNumber; i++)
                        {
                          msp_peptide_fragment_ion_list.push_back(
                            std::make_shared<PeptideFragmentIon>(fragment_sp, ion_type, i + 1));
                        }
                    }
                }
            }
          else
            {
              for(auto &&ion_type : m_ionList)
                {
                  // b, bstar, bo, a
                  if((ion_type == Enums::PeptideIon::b) || (ion_type == Enums::PeptideIon::bstar) ||
                     (ion_type == Enums::PeptideIon::bo) || (ion_type == Enums::PeptideIon::a) ||
                     (ion_type == Enums::PeptideIon::c))
                    {
                      msp_peptide_fragment_ion_list.push_back(
                        std::make_shared<PeptideFragmentIon>(fragment_sp, ion_type));
                    }
                  else if(ion_type == Enums::PeptideIon::bp)
                    {
                      if(phosphorylation_mod == nullptr)
                        {
                          phosphorylation_mod = AaModification::getInstance("MOD:00696");
                          m_phosphorylationNumber =
                            peptide.get()->getNumberOfModification(phosphorylation_mod);
                        }
                      for(unsigned int i = 0; i < m_phosphorylationNumber; i++)
                        {
                          msp_peptide_fragment_ion_list.push_back(
                            std::make_shared<PeptideFragmentIon>(fragment_sp, ion_type, i + 1));
                        }
                    }
                }
            }
        }
      qDebug() << "PeptideFragmentIonListBase::PeptideFragmentIonListBase end " << ions.size();
    }
  catch(PappsoException &exception_pappso)
    {
      QString errorStr =
        QObject::tr("ERROR building PeptideFragmentIonListBase, PAPPSO exception:\n%1")
          .arg(exception_pappso.qwhat());
      qDebug() << "PeptideFragmentIonListBase::PeptideFragmentIonListBase "
                  "PappsoException :\n"
               << errorStr;
      throw PappsoException(errorStr);
    }
  catch(std::exception &exception_std)
    {
      QString errorStr =
        QObject::tr("ERROR building PeptideFragmentIonListBase, std exception:\n%1")
          .arg(exception_std.what());
      qDebug() << "PeptideFragmentIonListBase::PeptideFragmentIonListBase "
                  "std::exception :\n"
               << errorStr;
      throw PappsoException(errorStr);
    }
}

PeptideFragmentIonListBase::PeptideFragmentIonListBase(const PeptideFragmentIonListBase &other)
  : msp_peptide(other.msp_peptide),
    msp_peptide_fragment_ion_list(other.msp_peptide_fragment_ion_list),
    m_ionList(other.m_ionList),
    m_phosphorylationNumber(other.m_phosphorylationNumber)
{
}


PeptideFragmentIonListBaseSp
PeptideFragmentIonListBase::makePeptideFragmentIonListBaseSp() const
{
  return std::make_shared<const PeptideFragmentIonListBase>(*this);
}


PeptideFragmentIonListBase::~PeptideFragmentIonListBase()
{
}

const std::list<PeptideFragmentSp>
PeptideFragmentIonListBase::getPeptideFragmentList(const PeptideSp &peptide)
{

  qDebug();
  std::list<PeptideFragmentSp> peptide_fragment_list;

  if(peptide.get()->size() < 1)
    {
      return peptide_fragment_list;
    }

  unsigned int max = peptide.get()->size() - 1;

  for(unsigned int i = 0; i < max; i++)
    {

      peptide_fragment_list.push_back(
        std::make_shared<PeptideFragment>(peptide, PeptideDirection::Nter, i + 1));
      peptide_fragment_list.push_back(
        std::make_shared<PeptideFragment>(peptide, PeptideDirection::Cter, i + 1));
    }
  qDebug();
  return peptide_fragment_list;
}

const std::list<PeptideFragmentIonSp>
PeptideFragmentIonListBase::getPeptideFragmentIonSp(Enums::PeptideIon ion_type) const
{
  std::list<PeptideFragmentIonSp> ion_list;
  for(auto &&peptide_fragment_ion_sp : msp_peptide_fragment_ion_list)
    {
      if(peptide_fragment_ion_sp.get()->getPeptideIonType() == ion_type)
        {
          ion_list.push_back(peptide_fragment_ion_sp);
        }
    }
  return (ion_list);
}

const PeptideFragmentIonSp &
PeptideFragmentIonListBase::getPeptideFragmentIonSp(Enums::PeptideIon ion_type,
                                                    unsigned int size) const
{

  return getPeptideFragmentIonSp(ion_type, size, 0);
}

const PeptideFragmentIonSp &
PeptideFragmentIonListBase::getPeptideFragmentIonSp(
  Enums::PeptideIon ion_type, unsigned int size, unsigned int number_of_neutral_phospho_loss) const
{
  for(auto &&peptide_fragment_ion_sp : msp_peptide_fragment_ion_list)
    {
      if(peptide_fragment_ion_sp.get()->getPeptideIonType() == ion_type)
        {
          if(peptide_fragment_ion_sp.get()->size() == size)
            {
              if(peptide_fragment_ion_sp.get()->getNumberOfNeutralPhosphoLoss() ==
                 number_of_neutral_phospho_loss)
                {
                  return (peptide_fragment_ion_sp);
                }
            }
        }
    }

  throw PappsoException(QString("PeptideFragmentIon %1 of size %2 not found")
                          .arg(PeptideFragmentIon::getPeptideIonName(ion_type))
                          .arg(size));
}

} // namespace pappso

std::size_t
pappso::PeptideFragmentIonListBase::size() const
{
  return msp_peptide_fragment_ion_list.size();
}

const std::list<pappso::PeptideFragmentIonSp> &
pappso::PeptideFragmentIonListBase::getPeptideFragmentIonList() const
{
  return msp_peptide_fragment_ion_list;
}

const pappso::PeptideSp &
pappso::PeptideFragmentIonListBase::getPeptideSp() const
{
  return msp_peptide;
}

unsigned int
pappso::PeptideFragmentIonListBase::getPhosphorylationNumber() const
{
  return m_phosphorylationNumber;
}

std::list<pappso::PeptideFragmentIonSp>::const_iterator
pappso::PeptideFragmentIonListBase::begin() const
{
  return msp_peptide_fragment_ion_list.begin();
}

std::list<pappso::PeptideFragmentIonSp>::const_iterator
pappso::PeptideFragmentIonListBase::end() const
{
  return msp_peptide_fragment_ion_list.end();
}
