//
// File: test_peptidenaturalisotopelist.cpp
// Created by: Olivier Langella
// Created on: 9/3/2015
//
/*******************************************************************************
 * 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
 ******************************************************************************/
// make test ARGS="-V -I 7,7"
// ./tests/catch2-only-tests [peptidenaturalisotope] -s

#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_approx.hpp>

#include <pappsomspp/precision.h>
#include <pappsomspp/peptide/peptidenaturalisotopelist.h>
#include <pappsomspp/peptide/peptidenaturalisotopeaverage.h>
#include <pappsomspp/peptide/peptidefragmention.h>
#include <pappsomspp/peptide/peptidefragmentionlistbase.h>
#include <pappsomspp/peptide/peptidestrparser.h>
#include <iostream>
#include <QDebug>
#include <QString>

using namespace pappso;
using namespace std;

TEST_CASE("Test peptidenaturalisotope", "[peptidenaturalisotope]")
{
  // Set the debugging message formatting pattern.
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));

  SECTION("..:: Test peptidenaturalisotope ::..", "[peptidenaturalisotope]")
  {

    std::cout << std::endl << "..:: peptide init ::.." << std::endl;
    std::cout << std::endl
              << "..:: peptide natural isotope list init ::.." << std::endl;
    Peptide peptide("LA");

    PeptideNaturalIsotopeList isotopeList(peptide.makePeptideSp());
    std::cout << std::endl
              << "isotope list OK" << isotopeList.size() << std::endl;

    PeptideNaturalIsotopeList::const_iterator it(isotopeList.begin());

    while(it != isotopeList.end())
      {
        // qDebug() <<  it->getIntensityRatio();
        std::cout << std::endl << it->get()->getSequence().toStdString();
        std::cout.flush();
        std::cout << "..:: " << it->get()->getFormula(1).toStdString();
        std::cout.flush();
        std::cout << " C13=" << it->get()->getNumberOfIsotope(Isotope::C13);
        std::cout.flush();
        std::cout << " mass=" << it->get()->getMz(1);
        std::cout.flush();
        std::cout << " mz(2)=" << it->get()->getMz(2);
        std::cout.flush();

        std::cout << " ratio=" << it->get()->getIntensityRatio(1) << " ::.."
                  << std::endl;
        it++;
      }
    std::cout << std::endl << "print isotope list OK" << std::endl;
    // MassRange mz_range(peptide.getMass(), ppm_precision(10));
    // if (!mz_range.contains(Aa('L').getMass()+Aa('A').getMass()))
    //    return 1;
    //    Peptide peptideb ("TAPSDVLAVELLQR");
    //   PeptideNaturalIsotopeList isotopeListb(peptideb.getPeptideSp());
    // http://pappso.inra.fr/protic/proticprod/angular/#/peptide_hits/947229
    // http://pappso.inra.fr/protic/proticprod/angular/#/peptide_hits/947252

    // AIADGSLLDLLR
    // http://prospector.ucsf.edu/prospector/cgi-bin/mssearch.cgi

    Peptide peptideb("AIADGSLLDLLR");
    peptideb.addAaModification(AaModification::getInstance("MOD:00397"), 0);
    pappso::pappso_double mass_before = peptideb.getMass();

    PeptideSp peptideSp = peptideb.makePeptideSp();
    PeptideNaturalIsotopeList isotopeListb(peptideSp);


    it = isotopeListb.begin();

    while(it != isotopeListb.end())
      {
        if(it->get()->getIsotopeNumber() == 0)
          {
            REQUIRE(it->get()->getMass() == Catch::Approx(mass_before));
          }
        REQUIRE(it->get()->size() == peptideb.size());
        // C55 H98 N15 O18 + C2 H3 N1 O1
        REQUIRE(it->get()->getNumberOfAtom(AtomIsotopeSurvey::C) == 57);
        REQUIRE(it->get()->getNumberOfAtom(AtomIsotopeSurvey::H) == 100);
        REQUIRE(it->get()->getNumberOfAtom(AtomIsotopeSurvey::N) == 16);
        REQUIRE(it->get()->getNumberOfAtom(AtomIsotopeSurvey::O) == 19);
        // qDebug() <<  it->getIntensityRatio();
        std::cout << std::endl
                  << it->get()->getSequence().toStdString()
                  << "..:: " << it->get()->getFormula(1).toStdString()
                  << " C13=" << it->get()->getNumberOfIsotope(Isotope::C13)
                  << " mass=" << it->get()->getMz(1)
                  << " mz(2)=" << it->get()->getMz(2)
                  << " ratio=" << it->get()->getIntensityRatio(1) << " ::.."
                  << std::endl;
        it++;
      }

    std::map<unsigned int, pappso_double> map_isotope_number =
      isotopeListb.getIntensityRatioPerIsotopeNumber();

    std::cout << "isotope levels" << std::endl;
    for(unsigned int i = 0; i < map_isotope_number.size(); i++)
      {
        std::cout << "isotope " << i << " " << map_isotope_number[i]
                  << std::endl;
      }

    std::cout << std::endl
              << "..:: peptide natural isotope list init test on fragment ::.."
              << std::endl;

    std::list<PeptideIon> cid_ion = PeptideFragmentIonListBase::getCIDionList();
    PeptideFragmentIonListBase fragmentation_cid(peptideSp, cid_ion);
    PeptideFragmentIonSp pepfrag_sp =
      fragmentation_cid.getPeptideFragmentIonSp(PeptideIon::y, 3);
    PeptideNaturalIsotopeList isotopeListFrag(pepfrag_sp);
    map_isotope_number = isotopeListFrag.getIntensityRatioPerIsotopeNumber();

    std::cout << "isotope levels" << std::endl;
    for(unsigned int i = 0; i < map_isotope_number.size(); i++)
      {
        std::cout << "frag isotope " << i << " " << map_isotope_number[i]
                  << std::endl;
      }

    std::vector<PeptideNaturalIsotopeAverageSp> naturalIsotopeAverageList =
      isotopeListFrag.getByIntensityRatio(
        1, PrecisionFactory::getPpmInstance(2), 0.99);

    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        naturalIsotopeAverageList)
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }
    // SUCCESS


    std::cout << "test with a big peptide at 10ppm" << std::endl;
    PeptideSp peptide_from_str = PeptideStrParser::parseString(
      "M(internal:Nter_hydrolytic_cleavage_H,0.00163028)"
      "GGTTQYTVNNQMVNATLMNIADNPTNVQLPGMYNK(internal:Cter_hydrolytic_cleavage_"
      "HO)");
    PeptideNaturalIsotopeList isotopeListBig(peptide_from_str);
    std::vector<pappso::PeptideNaturalIsotopeAverageSp>
      natural_isotope_average_list = isotopeListBig.getByIntensityRatio(
        3, PrecisionFactory::getPpmInstance(10), 0.6);
    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        natural_isotope_average_list)
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }


    std::cout << "test with a big peptide at 5ppm" << std::endl;
    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        isotopeListBig.getByIntensityRatio(
          3, PrecisionFactory::getPpmInstance(5), 0.6))
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }


    std::cout << "test with a big peptide at 3ppm" << std::endl;
    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        isotopeListBig.getByIntensityRatio(
          3, PrecisionFactory::getPpmInstance(3), 0.6))
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }


    std::cout << "test with a big peptide at 2ppm" << std::endl;
    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        isotopeListBig.getByIntensityRatio(
          3, PrecisionFactory::getPpmInstance(2), 0.6))
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }


    std::cout << "test with a big peptide at 1ppm" << std::endl;
    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        isotopeListBig.getByIntensityRatio(
          3, PrecisionFactory::getPpmInstance(1), 0.6))
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }


    std::cout << std::endl
              << "..:: peptide natural isotope list from labeled peptide ::.."
              << std::endl;
    PeptideSp peptide_lys_label =
      PeptideStrParser::parseString("CCAAL(MOD:00582)DDKEACFAVEGPK");

    PeptideNaturalIsotopeList isotopeList_lys(peptide_lys_label);
    std::cout << std::endl
              << "isotope list OK" << isotopeList_lys.size() << std::endl;

    map_isotope_number = isotopeList_lys.getIntensityRatioPerIsotopeNumber();

    std::cout << "isotope levels" << std::endl;
    for(unsigned int i = 0; i < map_isotope_number.size(); i++)
      {
        std::cout << "frag isotope " << i << " " << map_isotope_number[i]
                  << std::endl;
      }

    std::cout
      << std::endl
      << "..:: get 80 % intensity of natural isotope average PPM = 2 ::.."
      << std::endl;
    naturalIsotopeAverageList = isotopeList_lys.getByIntensityRatio(
      1, PrecisionFactory::getPpmInstance(2), 0.8);

    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        naturalIsotopeAverageList)
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }

    std::cout << std::endl << "print lys isotope list OK" << std::endl;

    std::cout
      << std::endl
      << "..:: get 10 % intensity of small peptide natural isotope average "
         "dalton = 0.2 ::.."
      << std::endl;
    naturalIsotopeAverageList = isotopeList_lys.getByIntensityRatio(
      1, PrecisionFactory::getDaltonInstance(0.2), 0.1);

    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        naturalIsotopeAverageList)
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }
    REQUIRE(naturalIsotopeAverageList.size() == 1);
    REQUIRE(naturalIsotopeAverageList.at(0).get()->getIsotopeNumber() == 0);

    std::cout
      << std::endl
      << "..:: get 10 % intensity of big peptide natural isotope average "
         "dalton = 0.2 ::.."
      << std::endl;
    naturalIsotopeAverageList = isotopeListBig.getByIntensityRatio(
      1, PrecisionFactory::getDaltonInstance(0.2), 0.1);

    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        naturalIsotopeAverageList)
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
      }
    REQUIRE(naturalIsotopeAverageList.size() == 1);
    REQUIRE(naturalIsotopeAverageList.at(0).get()->getIsotopeNumber() == 2);


    std::cout << std::endl << "..:: peptide rank test ::.." << std::endl;

    PeptideSp peptide_ratio_test = PeptideStrParser::parseString("DPTLAVVAYR");
    PeptideNaturalIsotopeList isotopeListRatioTest(peptide_ratio_test, 0.001);
    std::vector<pappso::PeptideNaturalIsotopeAverageSp>
      natural_isotope_average_list_ratio_test =
        isotopeListRatioTest.getByIntensityRatio(
          4, PrecisionFactory::getPpmInstance(10), 0.999);
    for(PeptideNaturalIsotopeAverageSp isotopeAverageSp :
        natural_isotope_average_list_ratio_test)
      {
        std::cout << "average isotope "
                  << isotopeAverageSp.get()->getIntensityRatio()
                  << " average mz=" << isotopeAverageSp.get()->getMz()
                  << " number=" << isotopeAverageSp.get()->getIsotopeNumber()
                  << " rank=" << isotopeAverageSp.get()->getIsotopeRank()
                  << std::endl;
        /*
              if(isotopeAverageSp.get()->getIsotopeRank() == 3)
                {
                  std::cerr << "isotopeAverageSp.get()->getIsotopeRank()== 3
           ERROR, not " "possible with 10ppm"
                       << std::endl;
                  return 1;
                }
                */
      }
  }
}
