/**
 * \file pappsomspp/processing/tandemwrapper/tandemwrapperrun.h
 * \date 25/01/2020
 * \author Olivier Langella
 * \brief actually does really run tandem directly on Bruker's data
 */

/*******************************************************************************
 * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>.
 *
 * This file is part of PAPPSOms-tools.
 *
 *     PAPPSOms-tools 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-tools 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-tools.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#pragma once

#include <QDebug>
#include <QObject>
#include <QProcess>
#include <QTemporaryDir>
#include <QMutex>

#include "../filters/filtersuitestring.h"
#include "../uimonitor/uimonitorinterface.h"
#include "pappsomspp/core/pappsoexception.h"
#include "../../types.h"
#include "pappsomspp/export-import-config.h"

/**
 * @todo write docs
 */
namespace pappso
{
class XtandemError : public PappsoException
{
  public:
  XtandemError(const QString &message) throw() : PappsoException(message)
  {
  }

  virtual QException *
  clone() const override
  {
    return new XtandemError(*this);
  }
};

class PMSPP_LIB_DECL TandemWrapperRun : public QObject
{
  Q_OBJECT
  public:
  /** @brief prepare a tandem run
   * @param tandem_binary file path to tandem.exe if not set, a default value is
   * given in QSettings
   * @param tmp_dir temporary directory, where to write mzXML file conversion if
   * not set, a default value is given in QSettings
   */
  TandemWrapperRun(const QString &tandem_binary, const QString &tmp_dir);

  /** @brief run a tandem job
   *
   * The tandem input file *should* contain an additional input parameter called
   * "spectrum, timstof MS2 filters". The value of this parameters *must*
   * contain a string describing the FilterSuiteString to apply on TimsTOF MS2.
   * A default value of "chargeDeconvolution|0.02dalton" is recommended for this
   * additional tandem input parameter
   *
   * @param monitor user interface monitor
   * @param tandem_input_file tandem xml input file
   */
  void run(UiMonitorInterface &monitor, const QString &tandem_input_file);

  void readTandemPresetFile(const QString &tandem_preset_file);

  /** @brief gets the list of filters used on MS2 spectrum
   *
   * @return string describing filters and associated parameters
   */
  QString getMs2FilterSuiteString() const;

  /**
   * Destructor
   */
  ~TandemWrapperRun();

  signals:
  void tandemProgressMessage(QString message);


  private:
  void setTandemBinaryPath(const QString &tandem_binary_path);
  const QString checkXtandemVersion(const QString &tandem_bin_path);
  void wrapTandemInputFile(const QString &tandem_input_file);

  bool convertOrginalMsData2mzXmlData(const QString &origin,
                                      const QString &target);


  /** @brief run a tandem job
   * @param tandem_input_file tandem xml input file
   */
  void runTandem(const QString &tandem_input_file);

  /** @brief tandem output modification
   * tandem output is modified to contain the Bruker's file as input and
   * centroidization parameters
   * @param tmp_tandem_output raw tandem output filename
   * @param final_tandem_output final destination file for modified tandem
   * output
   */
  void writeFinalTandemOutput(const QString &tmp_tandem_output,
                              const QString &final_tandem_output,
                              const QString &original_msdata_file_name);


  private slots:
  void readyReadStandardOutput();
  void readyReadStandardError();

  private:
  UiMonitorInterface *mp_monitor;
  QString m_tandemBinary;
  QString m_tandemVersion;
  QString m_tmpDir;
  int m_maxTandemRunTimeMs =
    1000; // If msecs is -1, this function will not time out.
  QProcess *m_xtProcess = nullptr;

  std::shared_ptr<FilterSuiteString> msp_ms2FilterSuiteString = nullptr;

  QTemporaryDir *mpa_temporaryDirectory = nullptr;

  bool m_convertMzDataUsingSpectrumIndex = false;

  Enums::MsDataFormat m_mzFormat = Enums::MsDataFormat::unknown;

  qint64 m_conversionTime = 0;
};
} // namespace pappso
