
/*******************************************************************************
 * Copyright (c) 2019 Olivier Langella <Olivier.Langella@u-psud.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/>.
 *
 ******************************************************************************/


// make test ARGS="-V -I 1,1"

// ./tests/catch2-only-tests [alignment] -s

// cmake .. -DCMAKE_BUILD_TYPE=Debug  -DMAKE_TEST=1  -DUSEPAPPSOTREE=1

#include <catch2/catch_test_macros.hpp>


#include <iostream>
// #include <odsstream/tsvreader.h>
#include <odsstream/odsdocreader.h>
#include <odsstream/odsexception.h>
#include <odsstream/tsvoutputstream.h>

#include <pappsomspp/pappsoexception.h>
#include <pappsomspp/msrun/alignment/msrunretentiontime.h>
#include <pappsomspp/msfile/msfileaccessor.h>
#include <QDebug>
#include <QtCore>
#include <QFile>
#include "config.h"
#include "common.h"

using namespace std;


void
writeTrace(const QString &filename, const pappso::Trace &trace)
{
  QFile file(filename);
  qDebug() << QFileInfo(filename).absoluteFilePath();
  file.open(QIODevice::WriteOnly);
  QTextStream textstream(&file);
  TsvOutputStream writer(textstream);

  for(auto &data_point : trace)
    {
      writer.writeCell(data_point.x);
      writer.writeCell(data_point.y);
      writer.writeLine();
    }
  writer.close();
}

class PeptideTableHandler : public OdsDocHandlerInterface
{
  public:
  PeptideTableHandler(pappso::MsRunRetentionTime<QString> &rt1,
                      pappso::MsRunRetentionTime<QString> &rt2)
    : m_rt1(rt1), m_rt2(rt2)
  {
    qDebug();
  }
  /**
   * callback that indicates the begining of a data sheet. Override it in
   * order to retrieve information about the current data sheet.
   *
   */
  virtual void
  startSheet(const QString &sheet_name [[maybe_unused]]) override
  {
    qDebug();
  };

  /**
   * callback that indicates the end of the current data sheet. Override it if
   * needed
   */
  virtual void
  endSheet() override
  {
    qDebug() << "endSheet";
  };

  /**
   * callback that indicates a new line start. Override it if needed.
   */

  virtual void
  startLine() override
  {

    qDebug() << m_sample;
    if(m_sample == "20120906_balliau_extract_1_A01_urnb-1")
      {
        m_rt1.addPeptideAsSeamark(m_peptideId, m_scan - 1);
      }
    if(m_sample == "20120906_balliau_extract_1_A02_urzb-1")
      {
        m_rt2.addPeptideAsSeamark(m_peptideId, m_scan - 1);
      }

    m_peptideId  = "";
    m_sample     = "";
    m_scan       = 0;
    m_sequenceLi = "";

    qDebug();
  };

  /**
   * callback that indicates a line ending. Override it if needed.
   */

  virtual void
  endLine() override
  {
    qDebug() << "() _is_title=" << _is_title;
    m_col = 0;
    if(!_is_title)
      {
      }
    _is_title = false;
    qDebug() << " _is_title = " << _is_title;
  };

  /**
   * callback that report the content of the current cell in a dedicated Cell
   * object. Override it if you need to retrieve cell content.
   */
  virtual void
  setCell(const OdsCell &cell) override
  {

    qDebug() << m_col;
    if(_is_title)
      return;
    m_col++;
    // Peptide ID,sample,scan,Sequence (top)
    if(m_col == 1)
      {
        if(!cell.isString())
          return;
        m_peptideId = cell.getStringValue();
      }
    if(m_col == 2)
      {
        if(!cell.isString())
          return;
        m_sample = cell.getStringValue();
      }
    if(m_col == 3)
      {
        if(!cell.isDouble())
          return;
        m_scan = (std::size_t)cell.getDoubleValue();
      }
    if(m_col == 4)
      {
        if(!cell.isString())
          return;
        m_sequenceLi = cell.getStringValue();
      }

    qDebug();
  };

  /**
   * callback that report the end of the ODS document. Override it if you need
   * to know that reading is finished.
   */
  virtual void
  endDocument() override
  {
    qDebug();
  };

  private:
  bool _is_title = true;
  std::size_t m_col;
  pappso::MsRunRetentionTime<QString> &m_rt1;
  pappso::MsRunRetentionTime<QString> &m_rt2;

  QString m_peptideId;
  QString m_sample;
  std::size_t m_scan;
  QString m_sequenceLi;
};


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

  SECTION("..:: Test MSrun alignment ::..", "[alignment]")
  {

    QTime timer;

#if USEPAPPSOTREE == 1
    std::cout << std::endl
              << "..:: Test MSrun alignment starts ::.." << std::endl;
    pappso::MsFileAccessor file_access_A01(
      "/gorgone/pappso/data_extraction_pappso/mzXML/"
      //"/home/langella/data1/mzxml/"
      "20120906_balliau_extract_1_A01_urnb-1.mzXML",
      "runa1");

    pappso::MsRunReaderSPtr msrunA01 =
      file_access_A01.getMsRunReaderSPtrByRunId("", "runa01");

    WARN("reading 20120906_balliau_extract_1_A01_urnb ::..");
    pappso::MsRunRetentionTime<QString> rt_msrunA01(msrunA01);


    pappso::MsFileAccessor file_access_A02(
      "/gorgone/pappso/data_extraction_pappso/mzXML/"
      //"/home/langella/data1/mzxml/"
      "20120906_balliau_extract_1_A02_urzb-1.mzXML",
      "runa1");

    pappso::MsRunReaderSPtr msrunA02 =
      file_access_A02.getMsRunReaderSPtrByRunId("", "runa02");

    WARN("..:: reading 20120906_balliau_extract_1_A02_urzb ::..");
    pappso::MsRunRetentionTime<QString> rt_msrunA02(msrunA02);
    rt_msrunA02.setMs2MedianFilter(pappso::FilterMorphoMedian(10));
    rt_msrunA02.setMs2MeanFilter(pappso::FilterMorphoMean(15));
    rt_msrunA02.setMs1MeanFilter(pappso::FilterMorphoMean(1));


    QFile realfile(QString(CMAKE_SOURCE_DIR)
                     .append("/tests/data/alignment/peptide_table.ods"));
    PeptideTableHandler handler_rt(rt_msrunA01, rt_msrunA02);
    OdsDocReader realreader_prm(handler_rt);
    // realreader_prm.setSeparator(TsvSeparator::tab);


    WARN("..:: reading peptide table ::..");
    REQUIRE_NOTHROW(realreader_prm.parse(&realfile));

    realfile.close();

    rt_msrunA01.computeSeamarks();

    REQUIRE(rt_msrunA01.getSeamarks().size() == 5227);


    rt_msrunA02.computeSeamarks();


    REQUIRE(rt_msrunA02.getSeamarks().size() == 5342);


    qDebug() << rt_msrunA01.getSeamarks()[0].entityHash << " "
             << rt_msrunA01.getSeamarks()[0].retentionTime << " | "
             << rt_msrunA02.getSeamarks()[0].entityHash << " "
             << rt_msrunA02.getSeamarks()[0].retentionTime;

    pappso::Trace rt_align;
    REQUIRE_NOTHROW(rt_align = rt_msrunA02.align(rt_msrunA01));


    pappso::Trace common_delta_rt =
      rt_msrunA02.getCommonDeltaRt(rt_msrunA01.getSeamarks());


    writeTrace("delta_rt.tsv", common_delta_rt);
    writeTrace("rt_align.tsv", rt_align);
    std::cout << std::endl
              << "rt_msrunA02 seamarks in common with rt_msrunA01 "
              << common_delta_rt.size() << std::endl;

    REQUIRE(common_delta_rt.size() == 4251);

    /*
        for(auto rt : rt_align)
          {
            // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "() "
       <<
            // rt.x
            //         << " " << rt.y;
          }
    */
    qDebug() << " first=" << rt_msrunA01.getMs1RetentionTimeVector().front()
             << " last=" << rt_msrunA01.getMs1RetentionTimeVector().back();
    std::cerr << "corrected values " << rt_msrunA02.getNumberOfCorrectedValues()
              << " " << std::endl;


    REQUIRE(
      compareTextFiles("rt_align.tsv",
                       QString(CMAKE_SOURCE_DIR)
                         .append("/tests/data/alignment/result_rt_align.tsv")));


    double aligned = rt_msrunA02.translateOriginal2AlignedRetentionTime(1200);

    REQUIRE(rt_msrunA02.translateAligned2OriginalRetentionTime(aligned) ==
            1200);

#endif
  }
}
