/*******************************************************************************
 * 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 <QStringList>
#include "peptidestrparser.h"
#include "../obo/filterobopsimodtermlabel.h"
#include "../obo/filterobopsimodsink.h"

namespace pappso
{


QRegularExpression PeptideStrParser::_mod_parser("\\([^)]*\\)");
QRegularExpression PeptideStrParser::_rx_psimod("MOD:[0-9]+");
QRegularExpression PeptideStrParser::_rx_modmass("[-+]?[0-9]+\\.?[0-9]*");

void
PeptideStrParser::parseStringToPeptide(const QString &pepstr, Peptide &peptide)
{
  // Peptide
  // peptide2("C(MOD:00397+MOD:01160)C(MOD:00397)AADDKEAC(MOD:00397)FAVEGPK");
  // CCAADDKEACFAVEGPK
  /*
  <psimod position="1"  accession="MOD:00397"/>
    <psimod position="2"  accession="MOD:00397"/>
    <psimod position="10"  accession="MOD:00397"/>
    <psimod position="1"  accession="MOD:01160"/>
    */
  int matched_length_cumul = 0;
  int pos                  = 0;

  QRegularExpressionMatch match_mod = _mod_parser.match(pepstr, pos);

  while(match_mod.hasMatch())
    {
      pos              = match_mod.capturedStart(0);
      QString captured = match_mod.captured(0);
      qDebug() << " captured=" << captured << " pos=" << pos
               << " match_mod.lastCapturedIndex()=" << match_mod.lastCapturedIndex();
      QStringList mod_list =
        captured.mid(1, captured.size() - 2).split(QRegularExpression("[+,\\,]"));
      for(QString &mod : mod_list)
        {
          qDebug() << "PeptideStrParser::parseString mod " << mod;
          QRegularExpressionMatch match_psimod = _rx_psimod.match(mod);
          if(match_psimod.hasMatch())
            {
              qDebug() << "PeptideStrParser::parseString pos-1 "
                       << (pos - 1 - matched_length_cumul);
              peptide.addAaModification(AaModification::getInstance(mod),
                                        pos - 1 - matched_length_cumul);
            }
          else if(mod.startsWith("internal:Nter_"))
            {
              peptide.setCleavageNterModification(AaModification::getInstance(mod));
            }
          else if(mod.startsWith("internal:Cter_"))
            {
              peptide.setCleavageCterModification(AaModification::getInstance(mod));
            }
          else if(mod.startsWith("C13N15:"))
            {
              qDebug() << "PeptideStrParser::parseString pos-1 "
                       << (pos - 1 - matched_length_cumul);
              peptide.addAaModification(AaModification::getInstance(mod),
                                        pos - 1 - matched_length_cumul);
            }
          else
            {
              qDebug() << "mod=" << mod;
              QRegularExpressionMatch match_modmass = _rx_modmass.match(mod);
              if(match_modmass.hasMatch())
                {
                  // number
                  qDebug() << "number mod=" << mod << " cap=" << match_modmass.captured(0);
                  if(!mod.contains("."))
                    {
                      // integer
                      qDebug() << "integer mod=" << mod;
                      mod = "MOD:0000" + mod;
                      while(mod.size() > 9)
                        {
                          mod = mod.replace(4, 1, "");
                        }
                      peptide.addAaModification(AaModification::getInstance(mod),
                                                pos - 1 - matched_length_cumul);
                    }
                  else
                    {
                      qDebug() << "double mod=" << mod;
                      peptide.addAaModification(
                        AaModification::getInstanceCustomizedMod(mod.toDouble()),
                        pos - 1 - matched_length_cumul);
                    }
                }
              else
                {
                  qDebug() << "not a number mod=" << mod;
                  FilterOboPsiModSink term_list;
                  FilterOboPsiModTermLabel filter_label(term_list, mod);

                  OboPsiMod psimod(filter_label);

                  peptide.addAaModification(AaModification::getInstance(term_list.getFirst()),
                                            pos - 1 - matched_length_cumul);
                }
            }
        }
      qDebug();
      matched_length_cumul += captured.size();
      match_mod = _mod_parser.match(pepstr, pos + 1);
      qDebug();
    }
}

PeptideSp
PeptideStrParser::parseString(const QString &pepstr)
{

  qDebug();
  // QMutexLocker locker(&_mutex);
  Peptide peptide(QString(pepstr).replace(_mod_parser, ""));
  PeptideStrParser::parseStringToPeptide(pepstr, peptide);

  return (peptide.makePeptideSp());
}

NoConstPeptideSp
PeptideStrParser::parseNoConstString(const QString &pepstr)
{

  qDebug() << pepstr;
  QString new_pep = QString(pepstr).replace(_mod_parser, "");
  qDebug() << new_pep;
  // QMutexLocker locker(&_mutex);
  Peptide peptide(new_pep);
  qDebug();
  PeptideStrParser::parseStringToPeptide(pepstr, peptide);

  return (peptide.makeNoConstPeptideSp());
}
} // namespace pappso
