/**
 * \file core/masschroq_run/masschorqslurmprocess.cpp
 * \date 21/06/2024
 * \author Olivier Langella
 * \brief handles execution of a bunch of MassChroQ process through slurm
 * workload manager
 */

/*******************************************************************************
 * Copyright (c) 2024 Olivier Langella
 *<Olivier.Langella@universite-paris-saclay.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/>.
 *
 ******************************************************************************/

#include "masschroqslurmprocess.h"
#include <pappsomspp/core/exception/exceptioninterrupted.h>

MassChroQSlurmProcess::MassChroQSlurmProcess(
  MainWindow *p_main_window,
  WorkMonitorInterface *p_monitor,
  const MassChroQRunBatch masschroq_batch_param)
  : MassChroQBatchProcess(p_main_window, p_monitor, masschroq_batch_param),
    mp_workMonitor(p_monitor)
{
  QSettings settings;
  m_slurmRequestMemory =
    settings.value("masschroq/slurm_request_memory", "10000").toUInt();
}

MassChroQSlurmProcess::~MassChroQSlurmProcess()
{
}


void
MassChroQSlurmProcess::run()
{
  qDebug() << "begin masschroq run through Slurm";
  checkMassChroQRunBatch();
  checkMassChroQMLValidity();

  qDebug() << "Prepare and check finished";
  QStringList arguments;
  arguments
    << QString("--cpus-per-task=%1").arg(m_masschroqRunBatch.number_cpu);
  arguments << QString("--mem=%1").arg(m_slurmRequestMemory);
  arguments << "--ntasks=1"
            << "--nodes=1";
  arguments << m_masschroqRunBatch.masschroq_bin_path;
  arguments << "-c" << QString("%1").arg(m_masschroqRunBatch.number_cpu);
  if(!m_masschroqRunBatch.masschroq_temporary_dir_path.isEmpty())
    {
      arguments << "-t" << m_masschroqRunBatch.masschroq_temporary_dir_path;
    }
  if(m_masschroqRunBatch.isTrace)
    {
      arguments << "--trace";
    }
  if(m_masschroqRunBatch.isShape)
    {
      arguments << "--shape"
                << QString("%1").arg(m_masschroqRunBatch.shapeMargin);
    }
  arguments << "--cbor" << m_masschroqRunBatch.getCborFilePath();
  arguments << m_masschroqRunBatch.masschroq_json_path;

  SlurmProcess *p_slurm_process = new SlurmProcess();
  mpa_mcqProcess                = p_slurm_process;
  qDebug();
  connect(mpa_mcqProcess,
          &SlurmProcess::readyReadStandardOutput,
          this,
          &MassChroQSlurmProcess::readyReadStandardOutput);
  connect(mpa_mcqProcess,
          &SlurmProcess::readyReadStandardError,
          this,
          &MassChroQSlurmProcess::readyReadStandardError);

  p_slurm_process->srun(
    QFileInfo(m_masschroqRunBatch.getCborFilePath()).absoluteDir(), arguments);


  qDebug();
  if(!mpa_mcqProcess->waitForStarted())
    {
      QString err = QObject::tr(
                      "Could not start MassChroQ process with srun "
                      "'%1' with arguments '%2': %3")
                      .arg(m_masschroqRunBatch.masschroq_bin_path)
                      .arg(arguments.join(QStringLiteral(" ")))
                      .arg(mpa_mcqProcess->errorString());
      throw pappso::PappsoException(err);
    }

  qDebug();
  while(mpa_mcqProcess->waitForFinished(1000) == false)
    {
      // mp_monitor->appendText(mpa_mcqProcess->readAll().data());
      qDebug();
      if(mp_monitor->shouldIstop())
        {
          qDebug() << "killing";
          mpa_mcqProcess->kill();
          delete mpa_mcqProcess;
          throw pappso::ExceptionInterrupted(
            QObject::tr("MassChroQ stopped by the user"));
        }
    }
  qDebug();
  // Stop the proccess and check if the exit was good
  QProcess::ExitStatus Status = mpa_mcqProcess->exitStatus();
  qDebug() << "QProcess::ExitStatus=" << Status;
  delete mpa_mcqProcess;

  if(Status == QProcess::ExitStatus::NormalExit)
    {
    }
  else
    {
      throw pappso::PappsoException(
        QObject::tr("error executing MassChroQ Status != 0 : %1 %2\n%3")
          .arg(m_masschroqRunBatch.masschroq_bin_path)
          .arg(arguments.join(" ").arg(m_mcqErrorString)));
    }

  runExport();
  MassChroQBatchProcess::mp_monitor->finished(
    QObject::tr("1 slurm MassCHroQ job finished"));
}


void
MassChroQSlurmProcess::runExport()
{
  qDebug() << "begin masschroq export run through Slurm";

  qDebug() << "Prepare and check finished";
  QStringList arguments;
  arguments
    << QString("--cpus-per-task=%1").arg(m_masschroqRunBatch.number_cpu);
  arguments << QString("--mem=%1").arg(m_slurmRequestMemory);
  arguments << "--ntasks=1"
            << "--nodes=1";
  arguments << QString(m_masschroqRunBatch.masschroq_bin_path)
                 .replace("masschroq3", "masschroq-export");
  arguments << m_masschroqRunBatch.getCborFilePath();

  SlurmProcess *p_slurm_process = new SlurmProcess();
  mpa_mcqProcess                = p_slurm_process;
  qDebug();
  connect(mpa_mcqProcess,
          &SlurmProcess::readyReadStandardOutput,
          this,
          &MassChroQSlurmProcess::readyReadStandardOutput);
  connect(mpa_mcqProcess,
          &SlurmProcess::readyReadStandardError,
          this,
          &MassChroQSlurmProcess::readyReadStandardError);

  p_slurm_process->srun(
    QFileInfo(m_masschroqRunBatch.getCborFilePath()).absoluteDir(), arguments);


  qDebug();
  if(!mpa_mcqProcess->waitForStarted())
    {
      QString err = QObject::tr(
                      "Could not start MassChroQ export process with srun "
                      "'%1' with arguments '%2': %3")
                      .arg(m_masschroqRunBatch.masschroq_bin_path)
                      .arg(arguments.join(QStringLiteral(" ")))
                      .arg(mpa_mcqProcess->errorString());
      throw pappso::PappsoException(err);
    }

  qDebug();
  while(mpa_mcqProcess->waitForFinished(1000) == false)
    {
      // mp_monitor->appendText(mpa_mcqProcess->readAll().data());
      qDebug();
      if(mp_monitor->shouldIstop())
        {
          qDebug() << "killing";
          mpa_mcqProcess->kill();
          delete mpa_mcqProcess;
          throw pappso::ExceptionInterrupted(
            QObject::tr("MassChroQ export stopped by the user"));
        }
    }
  qDebug();
  // Stop the proccess and check if the exit was good
  QProcess::ExitStatus Status = mpa_mcqProcess->exitStatus();
  qDebug() << "QProcess::ExitStatus=" << Status;
  delete mpa_mcqProcess;

  if(Status == QProcess::ExitStatus::NormalExit)
    {
    }
  else
    {
      throw pappso::PappsoException(
        QObject::tr("error executing MassChroQ export Status != 0 : %1 %2\n%3")
          .arg(m_masschroqRunBatch.masschroq_bin_path)
          .arg(arguments.join(" ").arg(m_mcqErrorString)));
    }
}
