/**
 * \file protein/peptidevariablemodificationreplacement.h
 * \date 5/12/2016
 * \author Olivier Langella
 * \brief potential replacement of a modification by an other
 */
/*******************************************************************************
 * Copyright (c) 2016 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 "peptidevariablemodificationreplacement.h"


namespace pappso
{
PeptideVariableModificationReplacement::PeptideVariableModificationReplacement(
  AaModificationP mod_before, AaModificationP mod_after)
  : PeptideVariableModificationBuilder(mod_before)
{
  mp_modAfter = mod_after;
  /** this forces to check that the targetted modified sites really has the
   * mod_before */
  m_modificationCount = 1;
}

PeptideVariableModificationReplacement::
  ~PeptideVariableModificationReplacement()
{
}


void
PeptideVariableModificationReplacement::replaceModificationsAtPosition(
  Peptide &new_peptide, unsigned int position)
{
  // replace all mod_before by mod_after :
  Aa &aa = new_peptide.getAa(position);
  aa.removeAaModification(mp_mod);
  unsigned int i = 0;
  while(i < m_modificationCount)
    {
      aa.addAaModification(mp_modAfter);
      i++;
    }
}


void
PeptideVariableModificationReplacement::setPeptideSp(
  std::int8_t sequence_database_id,
  const ProteinSp &protein_sp,
  bool is_decoy,
  const PeptideSp &peptide_sp_original,
  unsigned int start,
  bool is_nter,
  unsigned int missed_cleavage_number,
  bool semi_enzyme)
{
  // QString s = "Banana";
  // s.replace(QRegExp("a[mn]"), "ox");


  bool modify_this_peptide = true;
  if(m_isProtNterMod || m_isProtCterMod)
    {
      modify_this_peptide = false;
      if((m_isProtNterMod) && (is_nter))
        {
          // this an Nter peptide
          modify_this_peptide = true;
        }
      else if((m_isProtCterMod) &&
              (protein_sp.get()->size() ==
               (start + peptide_sp_original.get()->size())))
        {
          // this is a Cter peptide
          modify_this_peptide = true;
        }
      else if(m_isProtElseMod)
        {
          modify_this_peptide = true;
        }
    }

  if(modify_this_peptide)
    {
      std::vector<unsigned int> position_list;
      getModificationPositionList(
        position_list, peptide_sp_original.get(), mp_mod, m_modificationCount);

      // std::vector< unsigned int > position_list =
      // peptide_sp_original.get()->getAaPositionList(_aamp_modification_list);
      // std::string s = "12345";
      // no AA modification :
      if(m_minNumberMod == 0)
        {
          m_sink->setPeptideSp(sequence_database_id,
                               protein_sp,
                               is_decoy,
                               peptide_sp_original,
                               start,
                               is_nter,
                               missed_cleavage_number,
                               semi_enzyme);
        }

      unsigned int nb_pos = position_list.size();
      if(nb_pos > 0)
        {
          // loop to find 1 to n-1 AA modification combinations
          unsigned int comb_size = 1;
          while((comb_size < nb_pos) && (comb_size <= m_maxNumberMod))
            {
              do
                {
                  // std::cout << std::string(being,begin + comb_size) <<
                  // std::endl;
                  Peptide new_peptide(*(peptide_sp_original.get()));
                  for(unsigned int i = 0; i < comb_size; i++)
                    {
                      // new_peptide.addAaModification(mp_mod,position_list[i]);
                      this->replaceModificationsAtPosition(new_peptide,
                                                           position_list[i]);
                    }
                  PeptideSp new_peptide_sp = new_peptide.makePeptideSp();
                  m_sink->setPeptideSp(sequence_database_id,
                                       protein_sp,
                                       is_decoy,
                                       new_peptide_sp,
                                       start,
                                       is_nter,
                                       missed_cleavage_number,
                                       semi_enzyme);
                }
              while(next_combination(position_list.begin(),
                                     position_list.begin() + comb_size,
                                     position_list.end()));
              comb_size++;
            }

          if(nb_pos <= m_maxNumberMod)
            {
              // the last combination : all aa are modified :
              Peptide new_peptide(*(peptide_sp_original.get()));
              for(unsigned int i = 0; i < nb_pos; i++)
                {
                  // new_peptide.addAaModification(mp_mod,position_list[i]);

                  this->replaceModificationsAtPosition(new_peptide,
                                                       position_list[i]);
                }
              PeptideSp new_peptide_sp = new_peptide.makePeptideSp();
              m_sink->setPeptideSp(sequence_database_id,
                                   protein_sp,
                                   is_decoy,
                                   new_peptide_sp,
                                   start,
                                   is_nter,
                                   missed_cleavage_number,
                                   semi_enzyme);
            }
        }
    }
  else
    {
      // no modification
      m_sink->setPeptideSp(sequence_database_id,
                           protein_sp,
                           is_decoy,
                           peptide_sp_original,
                           start,
                           is_nter,
                           missed_cleavage_number,
                           semi_enzyme);
    }
}

} // namespace pappso
