//
// File: test_peptide.cpp
// Created by: Olivier Langella
// Created on: 7/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 6,6"
// ./tests/catch2-only-tests [Peptide] -s


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


#include <pappsomspp/mzrange.h>
#include <pappsomspp/amino_acid/aa.h>
#include <pappsomspp/peptide/peptide.h>
#include <pappsomspp/peptide/peptidestrparser.h>
#include <pappsomspp/peptide/peptideproformaparser.h>
#include <iostream>
#include <QDebug>
#include <QString>
#include <pappsomspp/exception/exceptionnotpossible.h>

using namespace pappso;
using namespace std;

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

  SECTION("..:: Test ProForma parser ::..", "[proforma]")
  {
    REQUIRE_THROWS_AS(PeptideProFormaParser::parseString(
      "C[MOD:00397][MOD:01160]C[MOD:00397]AADDKEAC[FAVEGPK"),
                      pappso::ExceptionNotPossible);
    PeptideSp peptide_from_str = PeptideProFormaParser::parseString(
      "C[MOD:00397][MOD:01160]C[MOD:00397]AADDKEAC[MOD:00397]FAVEGPK");
    REQUIRE(peptide_from_str.get()->getMass() == Catch::Approx(1909.764470427));

    REQUIRE(peptide_from_str.get()->toProForma().toStdString() ==
            "C[MOD:00397][MOD:01160]C[MOD:00397]AADDKEAC[MOD:00397]FAVEGPK");

    PeptideSp peptide_from_str2 = PeptideProFormaParser::parseString(
      "C[MOD:00397][MOD:01160]C[MOD:00397]AADDK[-18.02]EAC[MOD:00397]FAVEGPK");
    /*REQUIRE(peptide_from_str2.get()->toProForma().toStdString() ==
            "C[MOD:00397][MOD:01160]C[MOD:00397]AADDK[-18.0200]EAC[MOD:00397]"
            "FAVEGPK");*/
    REQUIRE(peptide_from_str2.get()->getMass() ==
            Catch::Approx(1891.744470427));


    REQUIRE(peptide_from_str2.get()->toProForma().toStdString() ==
            "C[MOD:00397][MOD:01160]C[MOD:00397]AADDK[-18.0200]EAC[MOD:00397]FAVEGPK");
  }


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

    std::cout << std::endl << "..:: peptide init ::.." << std::endl;
    Peptide peptide("LA");
    std::cout << std::endl << "..:: peptide LI ::.." << std::endl;
    std::cout << peptide.getSequence().toStdString() << " "
              << peptide.getSequenceLi().toStdString() << std::endl;
    MzRange mz_range(peptide.getMass(), PrecisionFactory::getPpmInstance(10));
    REQUIRE(mz_range.contains(Aa('L').getMass() + Aa('A').getMass() + MASSH2O));
    // 202.13179
    // http://db.systemsbiology.net:8080/proteomicsToolkit/FragIonServlet?sequence=LA&massType=monoRB&charge=1&bCB=1&yCB=1&nterm=0.0&cterm=0.0&addModifType=&addModifVal=
    MzRange mz_range_very_precise(peptide.getMass(),
                                  PrecisionFactory::getPpmInstance(0.5));
    REQUIRE(mz_range_very_precise.contains(202.13179));


    Peptide peptide2("CCAADDKEACFAVEGPK");
    // 1756.73395
    MzRange mz_range_very_preciseb(peptide2.getMz(1),
                                   PrecisionFactory::getPpmInstance(0.5));
    REQUIRE(mz_range_very_preciseb.contains(1756.73395));
    /*
    <psimod position="1"  accession="MOD:00397"/>
      <psimod position="2"  accession="MOD:00397"/>
      <psimod position="10"  accession="MOD:00397"/>
      <psimod position="1"  accession="MOD:01160"/>
      */

    pappso::AaModificationP aaModcarba =
      AaModification::getInstance("MOD:00397");
    /*
    pappso::AaModificationP aaModcarbab =
      AaModification::getInstance("MOD:00397");
    AaModificationP met_oxy = AaModification::getInstance("MOD:00719");*/
    peptide2.addAaModification(aaModcarba, 0);
    peptide2.addAaModification(aaModcarba, 1);
    peptide2.addAaModification(aaModcarba, 9);
    peptide2.addAaModification(AaModification::getInstance("MOD:01160"), 0);

    std::cerr << peptide2.getFormula(1).toStdString().c_str() << std::endl;

    MzRange mz_range2(peptide2.getMz(1), PrecisionFactory::getPpmInstance(10));
    REQUIRE(mz_range2.contains(1910.7722));


    PeptideSp peptide_from_str = PeptideStrParser::parseString(
      "C(MOD:00397+MOD:01160)C(MOD:00397)AADDKEAC(MOD:00397)FAVEGPK");
    REQUIRE(peptide_from_str.get()->getMass() == peptide2.getMass());

    PeptideSp peptide_from_str2 = PeptideStrParser::parseString(
      "C(Carbamidomethyl+MOD:01160)C(MOD:00397)AADDKEAC(57.021464)FAVEGPK");
    PeptideSp peptide_from_str3 = PeptideStrParser::parseString(
      "C(Carbamidomethyl+MOD:01160)C(397)AADDKEAC(57.021464)FAVEGPK");

    REQUIRE(peptide_from_str2.get()->getMass() ==
            peptide_from_str3.get()->getMass());

    // SUCCESS
    Peptide copy_str2(*peptide_from_str2.get());
    copy_str2.rotate();
    std::cerr << copy_str2.toAbsoluteString().toStdString() << std::endl;
    REQUIRE(peptide_from_str2.get()->getMass() == copy_str2.getMass());


    // testing isotope labels
    //[Term]
    // id: MOD:00582
    // name: 6x(13)C,2x(15)N labeled L-lysine
    std::cout << std::endl
              << "..:: Test peptide isotope labels::.." << std::endl;
    PeptideSp peptide_normal =
      PeptideStrParser::parseString("CCAALDDKEACFAVEGPK");
    PeptideSp peptide_lys_label =
      PeptideStrParser::parseString("CCAAL(MOD:00582)DDKEACFAVEGPK");
    REQUIRE(peptide_normal.get()->getNumberOfAtom(AtomIsotopeSurvey::C) ==
            peptide_lys_label.get()->getNumberOfAtom(AtomIsotopeSurvey::C));

    REQUIRE(peptide_normal.get()->getNumberOfIsotope(Isotope::C13) == 0);
    REQUIRE(peptide_lys_label.get()->getNumberOfIsotope(Isotope::C13) == 6);
    // xref: DiffMono: "8.014199"
    MzRange mz_range_lys(8.014199, PrecisionFactory::getPpmInstance(10));
    REQUIRE(mz_range_lys.contains(peptide_lys_label.get()->getMz(1) -
                                  peptide_normal.get()->getMz(1)));

    REQUIRE_FALSE(peptide_normal.get()->toString().toStdString() ==
                  peptide_lys_label.get()->toString().toStdString());
    REQUIRE_FALSE(peptide_normal.get()->toString().toStdString() <
                  peptide_lys_label.get()->toString().toStdString());

    PeptideSp peptide_lys_label_bis =
      PeptideStrParser::parseString("CCAAL(MOD:00582)DDKEACFAVEGPK");

    REQUIRE(peptide_lys_label_bis.get()->toString().toStdString() ==
            peptide_lys_label.get()->toString().toStdString());

    std::cout << std::endl << "..:: peptide palindrome ::.." << std::endl;
    Peptide peptide_pal_a("ALA");

    REQUIRE(peptide_pal_a.isPalindrome());

    REQUIRE_FALSE(peptide_normal.get()->isPalindrome());


    std::cout << std::endl << "..:: peptide dimethyl ::.." << std::endl;
    //"Q(internal:Nter_hydrolytic_cleavage_H,MOD:00429)SLPSLSS(MOD:00696)FLNR(internal:Cter_hydrolytic_cleavage_HO)"
    Peptide peptide_dimethyl("QSLPSLSSFLNR");
    pappso::AaModificationP aaModDimethyl =
      AaModification::getInstance("MOD:00429");
    pappso::AaModificationP aaModDimethyl2 =
      AaModification::getInstance("MOD:00696");
    peptide_dimethyl.addAaModification(aaModDimethyl, 0);
    peptide_dimethyl.addAaModification(aaModDimethyl2, 7);
    std::cout << "Before " << peptide_dimethyl.toAbsoluteString().toStdString();
    std::cout << std::endl << "remove AaModif" << std::endl;
    peptide_dimethyl.removeAaModification(aaModDimethyl);
    REQUIRE(
      peptide_dimethyl.toAbsoluteString().toStdString() ==
      "Q(internal:Nter_hydrolytic_cleavage_H)SLPSLSS(MOD:00696)FLNR(internal:"
      "Cter_hydrolytic_cleavage_HO)");
    std::cout << "Finish " << peptide_dimethyl.toAbsoluteString().toStdString();
  }
}
