//
// File: test_aa.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 5,5"

#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#include <QDebug>
#include <QString>
#include <pappsomspp/mzrange.h>
#include <pappsomspp/amino_acid/aa.h>
#include <iostream>
#include <pappsomspp/obo/obopsimod.h>
#include <pappsomspp/obo/filterobopsimodtermlabel.h>
#include <pappsomspp/obo/filterobopsimodsink.h>
#include <pappsomspp/obo/filterobopsimodtermdiffmono.h>
#include <pappsomspp/exception/exceptionnotfound.h>

using namespace pappso;
using namespace std;


TEST_CASE("Amino Acid test suite.", "[Aa]")
{
  // Set the debugging message formatting pattern.
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));

  SECTION("..:: AA init ::..", "[Aa]")
  {
    // cout << endl << "..:: AA init ::.." << endl;
    //   OboPsiMod test;
    Aa leucine('L');
    MzRange mz_range(leucine.getMass(), PrecisionFactory::getPpmInstance(1));
    cout << "leucine: "
         << QString::number(leucine.getMass(), 'g', 10).toStdString() << endl;
    cout << "leucine number of N15 : "
         << leucine.getNumberOfIsotope(Isotope::N15) << endl;
    cout << mz_range.toString().toStdString() << endl;
    /*
    if(!mz_range.contains(pappso_double(131.094635) - MASSH2O))
      {
        cerr << QString::number(leucine.getMass(), 'g', 10).toStdString()
             << " != 131.094635 - H2O";
        return 1;
      }
      */
    REQUIRE(mz_range.contains(pappso_double(131.094635) - MASSH2O));

    Aa alanine('A');
    /*
    if(!MzRange(alanine.getMass(), PrecisionFactory::getPpmInstance(1))
          .contains(pappso_double(89.047676 - MASSH2O)))
      {
        cerr << QString::number(alanine.getMass(), 'g', 10).toStdString()
             << " != " << (89.047676 - MASSH2O);
        return 1;
      }
      */
    REQUIRE(MzRange(alanine.getMass(), PrecisionFactory::getPpmInstance(1))
              .contains(pappso_double(89.047676 - MASSH2O)));


    alanine.addAaModification(
      AaModification::getInstanceCustomizedMod(18.022316354654));
    // SUCCESS

    // qDebug() << alanine.getModificationList();
    alanine.addAaModification(AaModification::getInstance("MOD:00397"));
    // alanine.addAaModification(AaModification::getInstance("fdgMOD:00397"));


    FilterOboPsiModSink term_list;
    FilterOboPsiModTermLabel filter_label(term_list, QString("Carba*"));

    OboPsiMod psimod(filter_label);

    cout << "term_list.size= " << term_list.size() << endl;
    REQUIRE(term_list.size() == 12);


    MzRange range(pappso_double(57.02),
                  PrecisionFactory::getDaltonInstance(pappso_double(0.02)));
    cout << range.getMz() << endl;

    cout << "choses "
         << MzRange(pappso_double(57.02),
                    PrecisionFactory::getDaltonInstance(pappso_double(0.02)))
              .toString()
              .toStdString()
         << endl;
    FilterOboPsiModSink term_listb;
    FilterOboPsiModTermDiffMono filter_labelb(
      term_listb,
      MzRange(pappso_double(57.02),
              PrecisionFactory::getDaltonInstance(pappso_double(0.02))));

    OboPsiMod psimodb(filter_labelb);

    for(auto term : term_listb.getOboPsiModTermList())
      {
        // cout << term._accession.toStdString() << " " << mz(term._diff_mono)
        // << endl;
      }
    cout << "term_listb.size= " << term_listb.size() << endl;
    REQUIRE(term_listb.size() == 9);

    Aa alaninebis('A');

    alaninebis.addAaModification(AaModification::getInstance("MOD:00397"));

    alaninebis.addAaModification(
      AaModification::getInstanceCustomizedMod(18.022316354654));
    // SUCCESS

    REQUIRE_FALSE(alanine < alaninebis);

    REQUIRE_FALSE(alaninebis < alanine);

    REQUIRE(alanine == alaninebis);


    Aa alanineter('A');
    qDebug() << "TEST";
    alanineter.addAaModification(AaModification::getInstance("MOD:00397"));

    REQUIRE_FALSE(alanine == alanineter);
    REQUIRE_FALSE(alanine < alanineter);
  }
  SECTION("..:: Test Modifications ::..")
  {
    AaModificationP mod = AaModification::getInstance("MOD:00397");
    cout << " MOD:00397 mass="
         << QString::number(mod->getMass(), 'g', 15).toStdString() << endl;
    // 57.021464

    // MOD:00429
    mod = AaModification::getInstance("MOD:00429");
    cout << " MOD:00429 mass="
         << QString::number(mod->getMass(), 'g', 15).toStdString() << endl;
    // 28.0313


    // MOD:00382
    mod = AaModification::getInstance("MOD:00382");
    cout << " MOD:00382 mass="
         << QString::number(mod->getMass(), 'g', 15).toStdString() << endl;
    //-20.026215
    REQUIRE(mod->getMass() == Approx(-20.026215));

    // MOD:00234
    mod = AaModification::getInstance("MOD:00234");
    cout << " MOD:00234 mass="
         << QString::number(mod->getMass(), 'g', 15).toStdString() << endl;
    // 305.068156

    // MOD:00838
    mod = AaModification::getInstance("MOD:00838");
    cout << " MOD:00838 mass="
         << QString::number(mod->getMass(), 'g', 15).toStdString() << endl;


    for(auto amino_acid : pappso::Aa::getAminoAcidCharList())
      {
        pappso::Aa aa_enumi(amino_acid);
        cout << " " << (char)amino_acid << " "
             << QString::number(aa_enumi.getMass(), 'g', 15).toStdString()
             << endl;
      }
    /*
     * A 71.037113785565
5:  R 156.101111025652
5:  C 103.009184785565
5:  D 115.026943024685
5:  E 129.042593089167
5:  F 147.068413914529
5:  G 57.021463721083
5:  H 137.058911859647
5:  I 113.084063979011
5:  K 128.094963016052
5:  L 113.084063979011
5:  M 131.040484914529
5:  N 114.042927442166
5:  P 97.052763850047
5:  Q 128.058577506648
5:  R 156.101111025652
5:  S 87.032028405125
5:  T 101.047678469607
5:  V 99.068413914529
5:  W 186.07931295157
5:  Y 163.063328534089
5:  U 168.964198469607
5:  O 255.158291550141
*/
    REQUIRE(pappso::Aa('A').getMass() == Approx(71.0371137856));
    REQUIRE(pappso::Aa('R').getMass() == Approx(156.101111025652));
    REQUIRE(pappso::Aa('C').getMass() == Approx(103.009184785565));
    REQUIRE(pappso::Aa('D').getMass() == Approx(115.026943024685));

    // AaModification::getInstance("MOD:00397_wrong");
    REQUIRE_THROWS_AS(AaModification::getInstance("MOD:00397_wrong"),
                      pappso::ExceptionNotFound);
  }

  /*

  return 0;
  */
}
