/**
 * \file /gui/workerthread.cpp
 * \date 8/5/2017
 * \author Olivier Langella
 * \brief worker thread
 */

/*******************************************************************************
 * Copyright (c) 2017 Olivier Langella <olivier.langella@u-psud.fr>.
 *
 * This file is part of i2MassChroQ.
 *
 *     i2MassChroQ 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.
 *
 *     i2MassChroQ 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 i2MassChroQ.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <olivier.langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "workerthread.h"

#include <odsstream/odsdocwriter.h>
#include <odsstream/tsvoutputstream.h>
#include <odsstream/odsexception.h>
#include <pappsomspp/core/pappsoexception.h>
#include <QDebug>
#include <QSettings>
#include "../output/exportfastafile.h"
#include "../output/masschroqjson.h"
#include "../output/masschroqml.h"
#include "../output/masschroqprm.h"
#include "../output/proticdbml.h"
#include "../output/ods/odsexport.h"
#include "../output/xpip.h"
#include "../output/mcqrspectralcount.h"
#include "files/xpipfile.h"
#include "mainwindow.h"
#include "project_view/projectwindow.h"
#include "../core/sage_run/sagebatchprocess.h"
#include "../core/sage_run/sageslurmprocess.h"
#include "../core/tandem_run/tandembatchprocess.h"
#include "../core/tandem_run/tandemcondorprocess.h"
#include "../core/tandem_run/tandemslurmprocess.h"
#include "../core/masschroq_run/masschroqbatchprocess.h"
#include "../core/masschroq_run/masschroqslurmprocess.h"
#include "../core/tidd/tiddcomputing.h"
#include "../output/ods/xicareasheet.h"
#include "../output/ods/xicinfosheet.h"
#include "../output/tidd/tidddataoutput.h"

WorkerThread::WorkerThread(MainWindow *p_main_window)
{
  _p_main_window = p_main_window;
  qDebug();

  _p_work_monitor = new WorkMonitor(p_main_window);

  // worker message
  connect(_p_work_monitor,
          &WorkMonitor::workerMessage,
          p_main_window,
          &MainWindow::doDisplayLoadingMessage);
  connect(_p_work_monitor,
          &WorkMonitor::workerMessagePercent,
          p_main_window,
          &MainWindow::doDisplayLoadingMessagePercent);
  connect(_p_work_monitor,
          &WorkMonitor::workerPercent,
          p_main_window,
          &MainWindow::doDisplayLoadingPercent);
  connect(_p_work_monitor,
          &WorkMonitor::workerAppendQString,
          p_main_window,
          &MainWindow::doWorkerAppendQString);
  connect(_p_work_monitor,
          &WorkMonitor::workerSetText,
          p_main_window,
          &MainWindow::doWorkerSetText);
  connect(_p_work_monitor,
          &WorkMonitor::workerJobFinished,
          p_main_window,
          &MainWindow::doDisplayJobFinished);
  connect(_p_work_monitor,
          &WorkMonitor::workerJobCanceled,
          p_main_window,
          &MainWindow::doDisplayJobCanceled);
  connect(p_main_window,
          &MainWindow::operateXpipFile,
          this,
          &WorkerThread::doXpipFileLoad);
  connect(p_main_window,
          &MainWindow::operateWritingXpipFile,
          this,
          &WorkerThread::doWritingXpipFile);
  connect(this,
          &WorkerThread::projectReady,
          p_main_window,
          &MainWindow::doProjectReady);
  connect(this,
          &WorkerThread::loadingResultsFinished,
          p_main_window,
          &MainWindow::doLoadingResultsReady);

  connect(p_main_window,
          &MainWindow::operateLoadingResults,
          this,
          &WorkerThread::doLoadingResults);

  connect(p_main_window,
          &MainWindow::operateRunningXtandem,
          this,
          &WorkerThread::doRunningXtandem);
  connect(p_main_window,
          &MainWindow::operateRunningSage,
          this,
          &WorkerThread::doRunningSage);
  connect(this,
          &WorkerThread::loadingMessage,
          p_main_window,
          &MainWindow::doDisplayLoadingMessage);
  connect(this,
          &WorkerThread::projectNotReady,
          p_main_window,
          &MainWindow::doProjectNotReady);

  // grouping
  connect(p_main_window,
          &MainWindow::operateGrouping,
          this,
          &WorkerThread::doGrouping);
  connect(this,
          &WorkerThread::groupingFinished,
          p_main_window,
          &MainWindow::doGroupingFinished);
  // masschroq write
  connect(p_main_window,
          &MainWindow::operateWritingFannDataFile,
          this,
          &WorkerThread::doWritingFannDataFile);
  connect(p_main_window,
          &MainWindow::operateWritingMassChroqFile,
          this,
          &WorkerThread::doWritingMassChroqJsonFile);
  connect(p_main_window,
          &MainWindow::operateWritingMassChroqPrmFile,
          this,
          &WorkerThread::doWritingMassChroqPrmFile);
  connect(p_main_window,
          &MainWindow::operateWritingMcqrSpectralCountFile,
          this,
          &WorkerThread::doWritingMcqrSpectralCountFile);
  connect(this,
          &WorkerThread::operateWritingMassChroqFileFinished,
          p_main_window,
          &MainWindow::doWritingMassChroQmlFileFinished);
  connect(p_main_window,
          &MainWindow::operateRunningMassChroq,
          this,
          &WorkerThread::doRunningMassChroQ);

  // protic write
  connect(p_main_window,
          &MainWindow::operateWritingProticFile,
          this,
          &WorkerThread::doWritingProticFile);
  // writing ODS file :
  connect(p_main_window,
          &MainWindow::operateWritingOdsFile,
          this,
          &WorkerThread::doWritingOdsFile);
  connect(this,
          &WorkerThread::operationFailed,
          p_main_window,
          &MainWindow::doOperationFailed);
  connect(this,
          &WorkerThread::operationFinished,
          p_main_window,
          &MainWindow::doOperationFinished);
  // FASTA file write
  connect(p_main_window,
          &MainWindow::operateWritingFastaFile,
          this,
          &WorkerThread::doWritingFastaFile);
  connect(_p_work_monitor,
          &WorkMonitor::showStopButton,
          p_main_window,
          &MainWindow::doShowStopButton);

  qDebug();
}


void
WorkerThread::connectProjectWindow(ProjectWindow *p_project_window)
{
  qDebug();

  //_p_work_monitor = new WorkMonitor();

  // worker message
  connect(_p_work_monitor,
          &WorkMonitor::workerMessage,
          p_project_window,
          &ProjectWindow::doDisplayLoadingMessage);
  connect(_p_work_monitor,
          &WorkMonitor::workerMessagePercent,
          p_project_window,
          &ProjectWindow::doDisplayLoadingMessagePercent);
  connect(_p_work_monitor,
          &WorkMonitor::subTaskPercent,
          p_project_window,
          &ProjectWindow::doDisplaySubTaskPercent);
  connect(_p_work_monitor,
          &WorkMonitor::workerPercent,
          p_project_window,
          &ProjectWindow::doDisplayLoadingPercent);
  connect(this,
          &WorkerThread::loadingMessage,
          p_project_window,
          &ProjectWindow::doDisplayLoadingMessage);
  // grouping
  connect(p_project_window,
          &ProjectWindow::operateGrouping,
          this,
          &WorkerThread::doGrouping);

  connect(p_project_window,
          &ProjectWindow::operateTiddComputing,
          this,
          &WorkerThread::doTiddComputing);

  connect(this,
          &WorkerThread::groupingFinished,
          p_project_window,
          &ProjectWindow::doGroupingFinished);


  // PTM grouping on IdentificationGroup
  connect(p_project_window,
          &ProjectWindow::operatePtmGroupingOnIdentification,
          this,
          &WorkerThread::doPtmGroupingOnIdentification);
  connect(this,
          &WorkerThread::ptmGroupingOnIdentificationFinished,
          p_project_window,
          &ProjectWindow::refreshPtmGroup);

  // grouping on IdentificationGroup
  connect(p_project_window,
          &ProjectWindow::operateGroupingOnIdentification,
          this,
          &WorkerThread::doGroupingOnIdentification);
  connect(this,
          &WorkerThread::groupingOnIdentificationFinished,
          p_project_window,
          &ProjectWindow::refreshGroup);

  connect(this,
          &WorkerThread::operationFailed,
          p_project_window,
          &ProjectWindow::doOperationFailed);
  connect(this,
          &WorkerThread::operationFinished,
          p_project_window,
          &ProjectWindow::doOperationFinished);

  connect(p_project_window,
          &ProjectWindow::operateWriteXicAreaInCsv,
          this,
          &WorkerThread::doWriteXicAreaInCsv);
  connect(this,
          &WorkerThread::exportXicToCsvFinished,
          p_project_window,
          &ProjectWindow::doExportXicAreaToCsvFinished);
  connect(_p_work_monitor,
          &WorkMonitor::showStopButton,
          p_project_window,
          &ProjectWindow::doShowStopButton);
  qDebug();
}


WorkerThread::~WorkerThread()
{
  qDebug();
}

void
WorkerThread::doXpipFileLoad(QString filename)
{
  qDebug();
  try
    {
      QFileInfo new_xpip_file(filename);
      emit loadingMessage(tr("loading XPIP file"));
      qDebug() << "WorkerThread::doXpipFileLoad new_xpip_file "
               << new_xpip_file.absoluteFilePath();
      XpipFile xpip_file(new_xpip_file);
      ProjectSp project_sp = xpip_file.getProjectSp(_p_work_monitor);
      project_sp.get()->setProjectName(filename);
      emit projectReady(project_sp);
    }
  catch(pappso::PappsoException &error)
    {
      emit projectNotReady(
        tr("Error while reading XPIP file :\n%1").arg(error.qwhat()));
    }

  qDebug();
}

void
WorkerThread::doPtmGroupingOnIdentification(
  IdentificationGroup *p_identification_group, PtmMode ptm_mode)
{
  qDebug();
  try
    {
      emit loadingMessage(tr("computing PTM islands"));
      try
        {
          p_identification_group->startPtmGrouping(ptm_mode);
        }
      catch(pappso::PappsoException &exception_pappso)
        {
          emit operationFailed(tr("Error computing PTM islands : %1")
                                 .arg(exception_pappso.qwhat()));
        }
      catch(std::exception &exception_std)
        {
          emit operationFailed(
            tr("Error computing PTM islands : %1").arg(exception_std.what()));
        }
      emit loadingMessage(tr("computing PTM islands finished"));
      emit ptmGroupingOnIdentificationFinished(p_identification_group);
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while computing PTM islands :\n%1").arg(error.qwhat()));
    }
  qDebug();
}

void
WorkerThread::doGroupingOnIdentification(
  IdentificationGroup *p_identification_group,
  ContaminantRemovalMode contaminant_removal_mode,
  GroupingType grouping_type)
{
  qDebug();
  qDebug();
  try
    {
      emit loadingMessage(tr("grouping proteins"));
      try
        {
          p_identification_group->startGrouping(
            contaminant_removal_mode, grouping_type, _p_work_monitor);
        }
      catch(pappso::PappsoException &exception_pappso)
        {
          emit operationFailed(tr("Error grouping identification : %1")
                                 .arg(exception_pappso.qwhat()));
        }
      catch(std::exception &exception_std)
        {
          emit operationFailed(
            tr("Error grouping identification : %1").arg(exception_std.what()));
        }
      emit loadingMessage(tr("grouping proteins finished"));
      emit groupingOnIdentificationFinished(p_identification_group);
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(tr("Error while grouping :\n%1").arg(error.qwhat()));
    }
  qDebug();
}
void
WorkerThread::doGrouping(ProjectSp project_sp)
{
  qDebug();
  try
    {
      emit loadingMessage(tr("grouping proteins"));
      try
        {
          qDebug();
          project_sp.get()->startGrouping(_p_work_monitor);
          qDebug();
        }
      catch(pappso::PappsoException &exception_pappso)
        {
          emit operationFailed(
            tr("Error grouping project : %1").arg(exception_pappso.qwhat()));
        }
      catch(std::exception &exception_std)
        {
          emit operationFailed(
            tr("Error grouping project : %1").arg(exception_std.what()));
        }
      emit loadingMessage(tr("grouping proteins finished"));
      emit groupingFinished();
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(tr("Error while grouping :\n%1").arg(error.qwhat()));
    }
  qDebug();
}

void
WorkerThread::doTiddComputing(ProjectSp project_sp, TiddParameters tidd_params)
{
  qDebug();
  try
    {
      emit loadingMessage(tr("TIDD computing"));
      try
        {
          qDebug();

          TiddComputingSp tidd = project_sp.get()->getTiddComputingSp();
          tidd.get()->setTiddParameters(tidd_params);
          tidd.get()->run(*_p_work_monitor, project_sp.get());

          emit tiddResultText(tidd.get()->getTiddResults());
          qDebug();
        }
      catch(pappso::PappsoException &exception_pappso)
        {
          emit operationFailed(tr("Error computing TIDD probabilities : %1")
                                 .arg(exception_pappso.qwhat()));
        }
      catch(std::exception &exception_std)
        {
          emit operationFailed(tr("Error computing TIDD probabilities : %1")
                                 .arg(exception_std.what()));
        }
      emit loadingMessage(tr("computing TIDD probabilities finished"));
      emit groupingFinished();
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(tr("Error while computing TIDD probabilities :\n%1")
                             .arg(error.qwhat()));
    }
}

void
WorkerThread::doWritingXpipFile(QString filename, ProjectSp project_sp)
{

  try
    {
      emit loadingMessage(tr("writing XPIP file, please wait"));
      project_sp.get()->checkPsimodCompliance();
      Xpip xpip_file(filename);
      xpip_file.write(project_sp);
      xpip_file.close();

      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while writing XPIP file :\n%1").arg(error.qwhat()));
    }
}
void
WorkerThread::doWritingOdsFile(
  QString filename,
  QString format,
  ProjectSp project_sp,
  ExportSpreadsheetDialog *export_spreadsheet_dialog)
{

  try
    {

      qDebug();
      CalcWriterInterface *p_writer = nullptr;
      if(format == "tsv")
        {
          emit loadingMessage(tr("writing TSV files, please wait"));
          p_writer = new TsvDirectoryWriter(filename);
        }
      else
        {
          emit loadingMessage(tr("writing ODS file, please wait"));
          p_writer = new OdsDocWriter(filename);
        }

      OdsExport export_ods(project_sp);
      try
        {
          export_ods.write(
            p_writer, export_spreadsheet_dialog, _p_work_monitor);
        }
      catch(pappso::PappsoException &error)
        {
          p_writer->close();
          delete p_writer;
          throw error;
        }
      p_writer->close();
      delete p_writer;
      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {

      emit operationFailed(
        tr("Error while writing ODS file :\n%1").arg(error.qwhat()));
    }
}

void
WorkerThread::doWritingMassChroqJsonFile(QString filename, ProjectSp project_sp)
{
  try
    {
      emit loadingMessage(tr("writing JSON MassChroQ file, please wait"));

      project_sp.get()->checkPsimodCompliance();
      MassChroQjson output(project_sp);


      QJsonDocument doc;
      output.populateJsonDocument(doc);


      QFile jsonf(filename);
      if(jsonf.open(QIODevice::WriteOnly))
        {
          jsonf.write(doc.toJson());
          jsonf.close();
        }
      else
        {
          throw pappso::PappsoException(
            tr("Unable to write json file %1")
              .arg(QFileInfo(filename).absoluteFilePath()));
        }


      emit operationFinished();
      emit operateWritingMassChroqFileFinished(
        filename,
        project_sp.get()
          ->getMasschroqFileParametersSp()
          .get()
          ->alignment_groups);
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while writing JSON MassChroQ file :\n%1").arg(error.qwhat()));
    }
}


void
WorkerThread::doWritingMassChroqFile(QString filename, ProjectSp project_sp)
{

  try
    {
      emit loadingMessage(tr("writing MassChroqML file, please wait"));

      project_sp.get()->checkPsimodCompliance();
      MassChroQml output(
        filename, *(project_sp.get()->getMasschroqFileParametersSp().get()));
      output.write(project_sp);
      output.close();
      emit operationFinished();
      emit operateWritingMassChroqFileFinished(
        filename,
        project_sp.get()
          ->getMasschroqFileParametersSp()
          .get()
          ->alignment_groups);
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while writing MassChroqML file :\n%1").arg(error.qwhat()));
    }
}


void
WorkerThread::doWritingMassChroqPrmFile(QString filename, ProjectSp project_sp)
{

  try
    {
      emit loadingMessage(tr("writing MassChroqPRM file, please wait"));

      project_sp.get()->checkPsimodCompliance();
      MassChroqPrm output(filename);
      output.write(project_sp);
      output.close();
      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while writing MassChroqPRM file :\n%1").arg(error.qwhat()));
    }
}

void
WorkerThread::doWritingProticFile(QString filename, ProjectSp project_sp)
{

  try
    {
      emit loadingMessage(tr("writing PROTICdbML file, please wait"));

      project_sp.get()->checkPsimodCompliance();
      ProticdbMl output(filename);
      output.write(project_sp);
      output.close();
      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while writing PROTICdbML file :\n%1").arg(error.qwhat()));
    }
}


void
WorkerThread::doWritingMcqrSpectralCountFile(QString filename,
                                             ProjectSp project_sp)
{
  try
    {
      emit loadingMessage(
        tr("Writing %1 spectral count file for MCQR").arg(filename));
      QFile outFile;
      outFile.setFileName(filename);
      outFile.open(QIODevice::WriteOnly);
      QTextStream *p_outputStream = new QTextStream(&outFile);
      TsvOutputStream *p_writer   = new TsvOutputStream(*p_outputStream);
      p_writer->setNoSheetName(true);

      McqrSpectralCountProteinSet protein_set =
        McqrSpectralCountProteinSet::allGroupedProteins;
      McqrSpectralCount spectra_sheet(p_writer, project_sp.get(), protein_set);
      spectra_sheet.writeSheet();

      p_writer->close();
      delete p_writer;
      delete p_outputStream;
      outFile.close();
      emit operationFinished();
    }
  catch(OdsException &error)
    {
      emit operationFailed(
        tr("Error while writing spectral count file for MassChroqR :\n%1")
          .arg(error.qwhat()));
    }
  catch(pappso::PappsoException &errorb)
    {
      emit operationFailed(
        tr("Error while writing spectral count file for MassChroqR :\n%1")
          .arg(errorb.qwhat()));
    }
}


void
WorkerThread::doLoadingResults(bool is_individual,
                               AutomaticFilterParameters param,
                               QStringList file_list)
{

  qDebug();
  try
    {
      if(file_list.size() == 0)
        {
          throw pappso::PappsoException(QObject::tr("file list is empty"));
        }
      ProjectSp project_sp = Project().makeProjectSp();
      if(is_individual)
        {
          project_sp.get()->setProjectMode(ProjectMode::individual);
        }
      else
        {
          project_sp.get()->setProjectMode(ProjectMode::combined);
        }

      _p_work_monitor->setTotalSteps(file_list.size());
      int i = 0;
      for(QString filename : file_list)
        {
          _p_work_monitor->message(tr("loading result file %1 (%2 on %3)")
                                     .arg(filename)
                                     .arg(i + 1)
                                     .arg(file_list.size()),
                                   i);
          //qWarning() << "workerthread.cpp";
          project_sp.get()->readResultFile(&_p_work_monitor->getSubMonitor(),
                                           filename);
          i++;
        }
      emit loadingMessage(tr("filtering proteins"));
      project_sp.get()->updateAutomaticFilters(param);
      emit loadingResultsFinished(project_sp);
    }
  catch(pappso::PappsoException &error)
    {
      qDebug() << " " << error.qwhat();
      emit projectNotReady(
        tr("Error while reading result files :\n%1").arg(error.qwhat()));
    }
  qDebug();
}

void
WorkerThread::doRunningSage(SageRunBatch sage_run_batch)
{
  qDebug();
  try
    {
      emit loadingMessage(tr("Running Sage, please wait"));

      if(sage_run_batch.useSlurm)
        {
          SageSlurmProcess sage_process(
            _p_main_window, _p_work_monitor, sage_run_batch);
          sage_process.run();

          _p_work_monitor->finished(QObject::tr("Sage job finished"));
        }
      else
        {

          SageBatchProcess sage_process(
            _p_main_window, _p_work_monitor, sage_run_batch);
          sage_process.run();

          _p_work_monitor->finished(QObject::tr("Sage job finished"));
        }

      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      if(_p_main_window->stopWorkerThread())
        {
          _p_work_monitor->canceled(error.qwhat());
        }
      else
        {
          qDebug() << error.qwhat();
          emit operationFailed(
            tr("Error while running Sage job :\n%1").arg(error.qwhat()));
        }
    }
}


void
WorkerThread::doRunningXtandem(TandemRunBatch tandem_run_batch)
{
  qDebug();
  try
    {
      emit loadingMessage(tr("Running X!Tandem, please wait"));
      qDebug() << "WorkerThread::doRunningXtandem tandem_run_batch "
               << tandem_run_batch._tandem_bin_path;

      QSettings settings;
      bool use_htcondor =
        settings.value("tandem/use_HTCondor", "false").toBool();

      if(use_htcondor)
        {
          /*
          TandemCondorProcess xt_process(
            _p_main_window, _p_work_monitor, tandem_run_batch);
          xt_process.run();
          */
          TandemSlurmProcess xt_process(
            _p_main_window, _p_work_monitor, tandem_run_batch);
          xt_process.run();
        }
      else
        {
          TandemBatchProcess xt_process(_p_work_monitor, tandem_run_batch);
          xt_process.run();

          _p_work_monitor->finished(
            QObject::tr("%1 X!Tandem job(s) finished")
              .arg(tandem_run_batch._mz_file_list.size()));
        }

      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      if(_p_main_window->stopWorkerThread())
        {
          _p_work_monitor->canceled(error.qwhat());
        }
      else
        {
          qDebug() << error.qwhat();
          emit operationFailed(
            tr("Error while running X!Tandem job :\n%1").arg(error.qwhat()));
        }
    }
  qDebug();
}

void
WorkerThread::doRunningMassChroQ(MassChroQRunBatch masschroq_batch_param)
{
  try
    {
      emit loadingMessage(tr("Running MassChroQ, please wait"));
      qDebug();

      QSettings settings;
      bool use_htcondor =
        settings.value("masschroq/use_htcondor", "false").toBool();

      if(use_htcondor)
        {
          /*
                    MassChroQCondorProcess mcq_process(
                      _p_main_window, _p_work_monitor, masschroq_batch_param);
                    mcq_process.run();
                    */

          MassChroQSlurmProcess mcq_process(
            _p_main_window, _p_work_monitor, masschroq_batch_param);
          mcq_process.run();
        }
      else
        {
          MassChroQBatchProcess mcq_process(
            _p_main_window, _p_work_monitor, masschroq_batch_param);
          mcq_process.runQuanti();
        }

      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      qDebug() << error.qwhat();
      emit operationFailed(
        tr("Error while running MassChroQ job :\n%1").arg(error.qwhat()));
    }
  qDebug();
}


void
WorkerThread::doWritingFastaFile(QString filename,
                                 ProjectSp project_sp,
                                 ExportFastaType type)
{

  try
    {

      qDebug();
      emit loadingMessage(tr("writing FASTA file, please wait"));


      ExportFastaFile output(filename, type);
      output.write(project_sp);
      output.close();

      // emit operateXpipFile(filename);
      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while writing FASTA file :\n%1").arg(error.qwhat()));
    }
}


void
WorkerThread::doFindBestMsrunForAlignment(ProjectSp project_sp,
                                          MsRunAlignmentGroupSp alignment_group)
{
  try
    {
      qDebug();
      emit loadingMessage(
        tr("looking for the best MSrun reference for alignment, please wait"));

      _p_work_monitor->message("checking MS run file path");
      _p_work_monitor->setTotalSteps(
        alignment_group->getMsRunsInAlignmentGroup().size());

      checkMsrunFilePath(alignment_group->getMsRunsInAlignmentGroup());

      _p_work_monitor->message("preparing MS run retention times");
      try
        {
          if(!_p_main_window->stopWorkerThread())
            {
              project_sp->prepareMsrunRetentionTimesForAlignment();
            }
        }
      catch(pappso::PappsoException &error)
        {
          throw pappso::PappsoException(
            tr("Error while preparing MS run retention times :\n%1")
              .arg(error.qwhat()));
        }

      try
        {
          MsRunSp ms_run_best_reference;


          _p_work_monitor->message("choosing best msrun reference");
          if(!_p_main_window->stopWorkerThread())
            {
              ms_run_best_reference =
                chooseBestMsRun(alignment_group->getMsRunsInAlignmentGroup());

              if(ms_run_best_reference != nullptr)
                {
                  qDebug() << " " << ms_run_best_reference.get()->getXmlId();
                }
            }
          _p_work_monitor->message("done");
          // emit operateXpipFile(filename);

          if(_p_main_window->stopWorkerThread())
            {
              _p_work_monitor->canceled("Finding the best MsRun canceled!");
            }
          else
            {
              emit findingBestMsrunForAlignmentFinished(ms_run_best_reference);
            }
        }
      catch(pappso::PappsoException &error)
        {
          throw pappso::PappsoException(
            tr("Error while choosing best MS run :\n%1").arg(error.qwhat()));
        }
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error looking for the best MSrun reference for alignment :\n%1")
          .arg(error.qwhat()));
    }
}

void
WorkerThread::checkMsrunFilePath(const std::vector<MsRunSp> &msruns)
{
  std::size_t i      = 0;
  bool should_i_stop = false;
  for(auto &msrun_sp : msruns)
    {
      should_i_stop = _p_main_window->stopWorkerThread();
      if(!should_i_stop)
        {
          _p_work_monitor->message(tr("checking MS run file path for sample %1")
                                     .arg(msrun_sp->getSampleName()),
                                   i);

          qDebug();
          pappso::MsRunReaderSPtr msrunreader_sp = msrun_sp->findMsRunFile();
          msrun_sp->freeMsRunReaderSp();

          qDebug();
          if(msrunreader_sp != nullptr)
            {
            }
          else
            {
              throw pappso::PappsoException(
                tr("Error while checking MS run file path :\nMSrun \"%1\" "
                   "for "
                   "sample named \"%2\" not found")
                  .arg(msrun_sp->getXmlId())
                  .arg(msrun_sp->getSampleName()));
            }
          i++;
        }
    }
}

MsRunSp
WorkerThread::chooseBestMsRun(const std::vector<MsRunSp> &msruns)
{
  _p_work_monitor->message("choosing MS run");

  MsRunSp ms_run_best_reference;
  std::size_t best_number = 0;
  bool should_i_stop      = false;

  for(auto &msrun_ref_sp : msruns)
    {

      _p_work_monitor->message(
        tr("processing %1").arg(msrun_ref_sp.get()->getFileName()));
      should_i_stop = _p_main_window->stopWorkerThread();
      if(!should_i_stop)
        {
          if(ms_run_best_reference == nullptr)
            {
              ms_run_best_reference = msrun_ref_sp;
            }

          std::size_t min_number = std::numeric_limits<std::size_t>::max();
          for(auto &msrun_sp : msruns)
            {
              should_i_stop = _p_main_window->stopWorkerThread();
              if(!should_i_stop)
                {
                  if(msrun_sp.get() != msrun_ref_sp.get())
                    {
                      pappso::Trace trace;
                      trace =
                        msrun_sp.get()
                          ->getMsRunRetentionTimePtr()
                          ->getCommonDeltaRt(msrun_ref_sp.get()
                                               ->getMsRunRetentionTimePtr()
                                               ->getSeamarks());
                      if(trace.size() < min_number)
                        {
                          min_number = trace.size();
                        }
                    }
                }
            }

          if(min_number > best_number)
            {
              best_number = min_number;

              ms_run_best_reference = msrun_ref_sp;
            }
        }
    }
  return ms_run_best_reference;
}


void
WorkerThread::doCheckMsrunFilePath(ProjectSp msp_project)
{

  MsRunSp msrun_sp = nullptr;
  try
    {

      _p_work_monitor->setTotalSteps(
        msp_project->getIdentificationDataSourceStore()
          .getIdentificationDataSourceList()
          .size());

      std::size_t i = 0;
      for(IdentificationDataSourceSp p_ident_data_source :
          msp_project->getIdentificationDataSourceStore()
            .getIdentificationDataSourceList())
        {
          msrun_sp = p_ident_data_source->getMsRunSp();
          _p_work_monitor->message(
            tr("checking MS run file path for \"%1\", named \"%2\"")
              .arg(msrun_sp.get()->getXmlId())
              .arg(msrun_sp.get()->getSampleName()),
            i);

          qDebug();
          pappso::MsRunReaderSPtr msrunreader_sp = msrun_sp->findMsRunFile();

          qDebug();
          if(msrunreader_sp != nullptr)
            {
              // msrun_sp->checkMsRunStatistics();
              msrun_sp->freeMsRunReaderSp();
              msrun_sp = nullptr;
              qDebug() << "file found";
            }
          else
            {
              // is_ok = false;
              qDebug() << "file not found";
              break;
            }
          // msrun_sp->freeMsRunReaderSp();
          i++;
        }
    }

  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error checking MSrun files path :\n%1").arg(error.qwhat()));
    }

  emit checkingMsrunFilePathFinished(msrun_sp);
}

void
WorkerThread::doWriteXicAreaInCsv(QString filename,
                                  ProjectSp project_sp,
                                  std::vector<XicBox *> xic_boxs)
{
  CalcWriterInterface *p_writer = nullptr;
  emit loadingMessage(tr("writing TSV files, please wait"));
  QSettings settings;
  QString xic_export_file =
    settings.value("export/xic_files", "area").toString();

  p_writer = new TsvDirectoryWriter(filename);
  if(xic_export_file == "both")
    {
      XicAreaSheet(p_writer, project_sp.get()->getProjectName(), xic_boxs);
      bool all_data = true;
      XicAreaSheet(
        p_writer, project_sp.get()->getProjectName(), xic_boxs, all_data);
    }
  else if(xic_export_file == "all")
    {
      bool all_data = true;
      XicAreaSheet(
        p_writer, project_sp.get()->getProjectName(), xic_boxs, all_data);
    }
  else // xic_export_file == "area"
    {
      XicAreaSheet(p_writer, project_sp.get()->getProjectName(), xic_boxs);
    }
  XicInfoSheet(p_writer, project_sp, xic_boxs);
  p_writer->close();
  emit exportXicToCsvFinished();
}

void
WorkerThread::doWritingFannDataFile(QString filename,
                                    ProjectSp project_sp [[maybe_unused]])
{
  try
    {
      TsvDirectoryWriter *p_writer = nullptr;
      emit loadingMessage(tr("writing Fann data files, please wait"));
      QSettings settings;

      p_writer = new TsvDirectoryWriter(filename);

      // TiddDataOutput(p_writer, project_sp.get());

      p_writer->close();
      emit operationFinished();
    }
  catch(pappso::PappsoException &error)
    {
      emit operationFailed(
        tr("Error while writing Fann data file :\n%1").arg(error.qwhat()));
    }
}

void
WorkerThread::closeEvent(QCloseEvent *event)
{
  event->accept();
}
