/**
 * \file /core/masschroq_run/masschroqbatchprocess.cpp
 * \date 2/11/2020
 * \author Thomas Renne
 * \brief handles execution of a bunch of MassChroQ process
 */

/*******************************************************************************
 * Copyright (c) 2020 Thomas Renne <thomas.renne@u-psud.fr>.
 *
 * This file is part of XTPcpp.
 *
 *     XTPcpp 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.
 *
 *     XTPcpp 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 XTPcpp.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#include "masschroqbatchprocess.h"
#include "../../utils/utils.h"
#include <pappsomspp/exception/exceptioninterrupted.h>

MassChroQBatchProcess::MassChroQBatchProcess(
  MainWindow *p_main_window, WorkMonitorInterface *p_monitor,
  const MassChroQRunBatch masschroq_batch_param)
{
  mp_mainWindow       = p_main_window;
  mp_monitor          = p_monitor;
  m_masschroqRunBatch = masschroq_batch_param;
}

MassChroQBatchProcess::~MassChroQBatchProcess()
{
}

void
MassChroQBatchProcess::run()
{
  m_mcqErrorString = "";
  mp_monitor->setTotalSteps(1);

  // Check if the bin exist and is executable then check the masschroqml file
  mp_monitor->message(QObject::tr("running MassChroQ checks \n"), 0);
  m_checkMcqTempDir =
    !(m_masschroqRunBatch.masschroq_temporary_dir_path.isEmpty());
  checkMassChroQRunBatch();
  checkMassChroQMLValidity();
  qDebug() << "checks finished";

  // Set the maschroq bin and the arguments
  mp_monitor->message(QObject::tr("running MassChroQ on %1\n")
                        .arg(m_masschroqRunBatch.masschroqml_path),
                      1);
  QStringList arguments;
  QString masschroq_path;
  qDebug();
  masschroq_path = m_masschroqRunBatch.masschroq_bin_path;

  arguments << "-c" << QString::number(m_masschroqRunBatch.number_cpu);
  if(!m_masschroqRunBatch.masschroq_temporary_dir_path.isEmpty())
    {
      arguments << "-t" << m_masschroqRunBatch.masschroq_temporary_dir_path;
    }
  if(m_masschroqRunBatch.on_disk)
    {
      arguments << "--ondisk";
    }
  if(m_masschroqRunBatch.parse_peptide)
    {
      arguments << "--parse-peptides";
    }
  arguments << m_masschroqRunBatch.masschroqml_path;

  qDebug();
  // Run MassChroQ with the given arguments and the masschroqml
  mpa_mcqProcess = new QProcess();


  qDebug();
  connect(mpa_mcqProcess, &QProcess::readyReadStandardOutput, this,
          &MassChroQBatchProcess::readyReadStandardOutput);
  connect(mpa_mcqProcess, &QProcess::readyReadStandardError, this,
          &MassChroQBatchProcess::readyReadStandardError);

  qDebug();
  mpa_mcqProcess->start(masschroq_path, arguments);

  qDebug();
  if(!mpa_mcqProcess->waitForStarted())
    {
      QString err = QObject::tr("Could not start MassChroQ process "
                                "'%1' with arguments '%2': %3")
                      .arg(masschroq_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)
    {
      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)));
    }

  // check if MassChroQ did not return an error
  if(!m_mcqErrorString.isEmpty())
    {
      throw pappso::PappsoException(
        QObject::tr("MassChroQ was stopped due to an issue :\n%1")
          .arg(m_mcqErrorString));
    }

  mp_monitor->finished(QObject::tr("%1 MassChroQ job(s) finished").arg(1));
}

void
MassChroQBatchProcess::checkMassChroQRunBatch()
{
  // Check the MassChroQ version format
  try
    {
      Utils::checkMassChroQVersion(m_masschroqRunBatch.masschroq_bin_path);
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(error);
    }

  // Check if the masschroqml exist then check if is readable
  QFileInfo masschroqml_file_info(m_masschroqRunBatch.masschroqml_path);
  if(!masschroqml_file_info.exists())
    {
      throw pappso::PappsoException(
        QObject::tr("%1 doesn't exist!\nPlease check your masschroqml file")
          .arg(m_masschroqRunBatch.masschroqml_path));
    }
  if(!masschroqml_file_info.isReadable())
    {
      throw pappso::PappsoException(
        QObject::tr("%1 isn't readable please check the file rights!")
          .arg(m_masschroqRunBatch.masschroqml_path));
    }

  // Check if the given masschroq temp dir exist and is a directory (only if a
  // temp dir is given)
  if(m_checkMcqTempDir)
    {
      QFileInfo masschroq_temp_dir(
        m_masschroqRunBatch.masschroq_temporary_dir_path);
      if(!masschroq_temp_dir.exists() || !masschroq_temp_dir.isDir())
        {
          throw pappso::PappsoException(
            QObject::tr(
              "%1 doesn't exist or is not a directory.\nPlease change "
              "the directory path or create it!")
              .arg(m_masschroqRunBatch.masschroq_temporary_dir_path));
        }
      qDebug() << masschroq_temp_dir.absoluteDir().absolutePath();
      if(!masschroq_temp_dir.absoluteDir().isReadable())
        {
          throw pappso::PappsoException(
            QObject::tr(
              "%1 is not readable!\nPlease check the directory rights")
              .arg(m_masschroqRunBatch.masschroq_temporary_dir_path));
        }
    }
}

void
MassChroQBatchProcess::checkMassChroQMLValidity()
{
  // set the masschroq bin and the arguments
  QString masschroq_path = m_masschroqRunBatch.masschroq_bin_path;
  QStringList arguments;
  QStringList results;

  arguments << "--validate" << m_masschroqRunBatch.masschroqml_path;

  // Run MassChroQ with the validate arguments
  QProcess *mcq_process = new QProcess();
  mcq_process->start(masschroq_path, arguments);

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

  while(mcq_process->waitForFinished(1000) == false)
    {
      //_p_monitor->appendText(xt_process->readAll().data());
      // data.append(xt_process->readAll());
      if(mp_monitor->shouldIstop())
        {
          mcq_process->kill();
          delete mcq_process;
          mcq_process = nullptr;
          throw pappso::ExceptionInterrupted(
            QObject::tr("MassChroQ stopped by the user"));
        }
    }


  // check if masschroq exit normally
  QProcess::ExitStatus Status = mcq_process->exitStatus();
  delete mcq_process;
  if(Status != 0)
    {
      mcq_process->kill();
      delete mcq_process;
      throw pappso::PappsoException(
        QObject::tr("error executing MassChroQ Status != 0 : %1 %2\n%3")
          .arg(m_masschroqRunBatch.masschroq_bin_path)
          .arg(arguments.join(" ").arg(results.join("\n"))));
    }
  qDebug();
}


void
MassChroQBatchProcess::readyReadStandardOutput()
{
  QString message(mpa_mcqProcess->readAllStandardOutput());
  mp_monitor->appendText(message);

  if(mp_monitor->shouldIstop())
    {
      qDebug() << "killing";
      mpa_mcqProcess->kill();
      delete mpa_mcqProcess;
      mpa_mcqProcess = nullptr;
      throw pappso::ExceptionInterrupted(
        QObject::tr("MassChroQ stopped by the user"));
    }
}

void
MassChroQBatchProcess::readyReadStandardError()
{
  QString message(mpa_mcqProcess->readAllStandardError());
  mp_monitor->appendText(message);
  m_mcqErrorString += message;
  if(mp_monitor->shouldIstop())
    {
      qDebug() << "killing";
      mpa_mcqProcess->kill();
      delete mpa_mcqProcess;
      mpa_mcqProcess = nullptr;
      throw pappso::ExceptionInterrupted(
        QObject::tr("MassChroQ stopped by the user"));
    }
}
