/**
 * \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"

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()
{
}

bool
MassChroQBatchProcess::shouldIstop()
{
  if(mp_mainWindow->stopWorkerThread())
    {
      return true;
    }
  return false;
}

void
MassChroQBatchProcess::run()
{
  mp_monitor->setProgressMaximumValue(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;

  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;

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

  if(!mcq_process->waitForStarted())
    {
      throw pappso::PappsoException(
        QObject::tr("MassChroQ process failed to start"));
    }

  while(mcq_process->waitForReadyRead())
    {
      mp_monitor->appendText(mcq_process->readAll().data());
      if(shouldIstop())
        {
          mcq_process->kill();
          delete mcq_process;
          throw pappso::PappsoException(
            QObject::tr("MassChroQ stopped by the user"));
        }
    }

  // check if MassChroQ did not return an error
  QByteArray mcq_error = mcq_process->readAllStandardError();
  if(!mcq_error.isEmpty())
    {
      throw pappso::PappsoException(
        QObject::tr("MassChroQ was stoped due to an issue :\n%1")
          .arg(mcq_error.data()));
    }

  // Stop the proccess and check if the exit was good
  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(mcq_error.data())));
    }
  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())
    {
      throw pappso::PappsoException(
        QObject::tr("MassChroQ process failed to start"));
    }

  while(mcq_process->waitForReadyRead())
    {
      results << QString(mcq_process->readAll().data()).simplified();
      mp_monitor->appendText(results.back().toLocal8Bit() + "\n");
    }

  // check if masschroq doesn't return an error'
  if(!mcq_process->readAllStandardError().isEmpty())
    {
      throw pappso::PappsoException(
        QObject::tr("The given masschroqml file isn't valid !\nThe error is %1")
          .arg(mcq_process->readAllStandardError().constData()));
    }

  // 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();
}
