/**
 * \file tandemwrapper.cpp
 * \date 25/01/2020
 * \author Olivier Langella
 * \brief 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/>.
 *
 ******************************************************************************/

#include "tandemwrapper.h"
#include <QCommandLineParser>
#include <QDateTime>
#include <QTimer>
#include <QFile>
#include <QFileInfo>
#include <pappsomspp/core/pappsoexception.h>
#include <pappsomspp/core/processing/tandemwrapper/tandemwrapperrun.h>
#include <pappsomspp/core/processing/uimonitor/uimonitortext.h>

TandemWrapper::TandemWrapper(QObject *parent) : QObject(parent)
{
  // get the instance of the main application
  app = QCoreApplication::instance();
  // setup everything here
  // create any global objects
  // setup debug and warning mode
}

// 10ms after the application starts this method will run
// all QT messaging is running at this point so threads, signals and slots
// will all work as expected.
void
TandemWrapper::run()
{
  // umask(0); // apply system umask
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));
  /* ./src/pt-mzxmlconverter -i
     /gorgone/pappso/fichiers_fabricants/Bruker/tims_doc/tdf-sdk/example_data/200ngHeLaPASEF_2min_compressed.d/analysis.tdf
     -o
     /gorgone/pappso/versions_logiciels_pappso/i2masschroq/bruker/200ngHeLaPASEF_2min.mzXML
     */

  //./src/pt-mzxmlconverter -i
  /// gorgone/pappso/fichiers_fabricants/Bruker/tims_doc/tdf-sdk/example_data/200ngHeLaPASEF_2min_compressed.d/analysis.tdf
  //-o /tmp/test.xml


  QTextStream errorStream(stderr, QIODevice::WriteOnly);
  QTextStream outputStream(stdout, QIODevice::WriteOnly);

  try
    {
      // qDebug();
      QCommandLineParser parser;

      // throw pappso::PappsoException("test");
      parser.setApplicationDescription(
        QString("%1 ")
          .arg(QCoreApplication::applicationName())
          .append("tandemwrapper")
          .append(" (")
          .append(i2MassChroQ_VERSION)
          .append(")")
          .append(" -- Run X!Tandem on data from Bruker's timsTOF line of "
                  "instruments"));

      parser.addHelpOption();
      parser.addVersionOption();

      QCommandLineOption tandemOption(
        QStringList() << "tandem",
        QCoreApplication::translate("tandem",
                                    "Full path to the X!Tandem executable file "
                                    "(tandem or tandem.exe) <tandem>."),
        QCoreApplication::translate("tandem", "tandem"));

      QCommandLineOption tmpDirOption(
        QStringList() << "t"
                      << "tmp",
        QCoreApplication::translate(
          "tmp",
          "Optionally set the temporary directory to store temporary data"),
        QCoreApplication::translate("tmp", "tmp"));


      parser.addOption(tandemOption);
      parser.addOption(tmpDirOption);

      parser.addPositionalArgument(
        "<config file name>",
        QCoreApplication::translate("main",
                                    "X!Tandem configuration XML file name."));

      // qDebug();

      // Process the actual command line arguments given by the user
      parser.process(*app);

      const QStringList positional_args = parser.positionalArguments();

      // qDebug() << "The position non-option arguments: " << positional_args;

      // We know that there must be a single position file: the tandemwrapper
      // xml config file.

      if(positional_args.size() > 1)
        {
          qFatal(
            "\n\n\tThere were more than one configuration file names provided. "
            "Please, "
            "provide a single "
            "XML configuration file name. Refer to the user manual.\n");
        }


      if(positional_args.size() < 1)
        {
          qFatal(
            "\n\n\tThere was no configuration file name provided. Please, "
            "provide a single "
            "XML configuration file name. Refer to the user manual.\n");
        }

      QFileInfo file_info(positional_args[0]);

      if(!file_info.exists())
        {
          QString msg = QString("\n\n\tFile %1 does not exist on disk.\n")
                          .arg(file_info.fileName());

          qFatal("\n\n\tFile '%s' not found.\n",
                 file_info.fileName().toLatin1().constData());
        }

      // QCoreApplication * app(this);
      // Add your main code here
      // qDebug();
      const QDateTime dt_begin = QDateTime::currentDateTime();
      const QStringList args   = parser.positionalArguments();


      pappso::TandemWrapperRun tandem_run(parser.value(tandemOption),
                                          parser.value(tmpDirOption));


      if(args.size() > 0)
        {
          pappso::UiMonitorText monitor(outputStream);
          tandem_run.run(monitor, args[0]);
        }

      qDebug();
    }
  catch(pappso::PappsoException &error)
    {

      errorStream << QString("Oops! an error occurred in %1. Don't Panic :\n%2")
                       .arg(QCoreApplication::applicationName())
                       .arg(error.qwhat());

      errorStream << Qt::endl << Qt::endl;

      errorStream << "Are you sure the file name you provided is a proper XML "
                     "X!Tandem config file?"
                  << Qt::endl
                  << Qt::endl;

      errorStream.flush();
      exit(1);
      app->exit(1);
    }

  catch(std::exception &error)
    {

      errorStream << QString("Oops! an error occurred in %1. Don't Panic :\n%2")
                       .arg(QCoreApplication::applicationName())
                       .arg(error.what());

      errorStream << Qt::endl << Qt::endl;

      errorStream << "Are you sure the file name you provided is a proper XML "
                     "X!Tandem config file?"
                  << Qt::endl
                  << Qt::endl;

      errorStream.flush();
      exit(1);
      app->exit(1);
    }


  // you must call quit when complete or the program will stay in the
  // messaging loop
  quit();
}

// call this routine to quit the application
void
TandemWrapper::quit()
{
  // you can do some cleanup here
  // then do emit finished to signal CoreApplication to quit
  emit finished();
}

// shortly after quit is called the CoreApplication will signal this routine
// this is a good place to delete any objects that were created in the
// constructor and/or to stop any threads
void
TandemWrapper::aboutToQuitApp()
{
  // stop threads
  // sleep(1);   // wait for threads to stop.
  // delete any objects
}


int
main(int argc, char **argv)
{
  // QTextStream consoleErr(stderr);
  // QTextStream consoleOut(stdout, QIODevice::WriteOnly);
  // ConsoleOut::setCout(new QTextStream(stdout, QIODevice::WriteOnly));
  // ConsoleOut::setCerr(new QTextStream(stderr, QIODevice::WriteOnly));
  qDebug();
  QCoreApplication app(argc, argv);
  qDebug();
  QCoreApplication::setApplicationName("tandemwrapper");
  QCoreApplication::setApplicationVersion(i2MassChroQ_VERSION);
  QLocale::setDefault(QLocale::system());

  // create the main class
  TandemWrapper myMain;
  // connect up the signals
  QObject::connect(&myMain, SIGNAL(finished()), &app, SLOT(quit()));
  QObject::connect(
    &app, SIGNAL(aboutToQuit()), &myMain, SLOT(aboutToQuitApp()));
  qDebug();


  // This code will start the messaging engine in QT and in
  // 10ms it will start the execution in the MainClass.run routine;
  QTimer::singleShot(10, &myMain, SLOT(run()));
  return app.exec();
}
