/**
 * \file /gui/tandem_run_dialog/tandem_run_dialog.cpp
 * \date 31/8/2017
 * \author Olivier Langella
 * \brief dialog window to launch tandem process
 */

/*******************************************************************************
 * Copyright (c) 2017 Olivier Langella <olivier.langella@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/>.
 *
 * Contributors:
 *     Olivier Langella <olivier.langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/
#include "tandemrundialog.h"

#include "ui_tandem_run_dialog.h"
#include <QDebug>
#include <QSettings>
#include <QFileDialog>
#include <QTreeView>
#include <QMessageBox>
#include <QStandardPaths>
#include <QDesktopServices>
#include <pappsomspp/pappsoexception.h>
#include "../../files/tandemparametersfile.h"
#include "../../utils/utils.h"

// Q_DECLARE_METATYPE(QFileInfo)

TandemRunDialog::TandemRunDialog(QWidget *parent)
  : QDialog(parent), ui(new Ui::TandemRunDialog)
{
  qDebug();
  ui->setupUi(this);
  this->setModal(true);
  _p_fasta_file_list = new QStringListModel();
  _p_mz_file_list    = new QStringListModel();
  ui->fasta_file_listview->setModel(_p_fasta_file_list);
  ui->mz_file_listview->setModel(_p_mz_file_list);
  ui->exe_group_widget->setVisible(false);

  QSettings settings;

  ui->use_htcondor_groupbox->setChecked(
    settings.value("tandem/use_HTCondor", "false").toBool());
  ui->request_memory_edit->setText(
    settings.value("tandem/condor_request_memory", "5000").toString());

  settings.value("condor/tmp_dir", QStandardPaths::TempLocation);

#if QT_VERSION >= 0x050000
  // Qt5 code
#else
  // Qt4 code

#endif
  reset();
  fillPresetComboBox();
  qDebug() << "TandemRunDialog::TandemRunDialog end";
}

TandemRunDialog::~TandemRunDialog()
{
  delete ui;
  delete _p_fasta_file_list;
  delete _p_mz_file_list;
}


void
TandemRunDialog::exeGroupBoxClicked(bool clicked)
{
  qDebug() << "TandemRunDialog::exeGroupBoxClicked begin";
  ui->exe_group_widget->setVisible(false);
  if(clicked)
    {
      ui->exe_group_widget->setVisible(true);
    }
  qDebug() << "TandemRunDialog::exeGroupBoxClicked end";
}

void
TandemRunDialog::setPresetName(QString preset_name)
{
  qDebug() << "TandemRunDialog::setPresetName begin";
  if(!preset_name.isEmpty() && !preset_name.isNull())
    {

      qDebug() << "TandemRunDialog::setPresetName not null";
      // test if this is an X!Tandem preset file:
      // get presets :
      TandemParametersFile param_file(
        ui->preset_combobox->itemData(ui->preset_combobox->currentIndex())
          .value<QString>());

      if(param_file.isTandemPresetFile())
        {
          QSettings settings;
          settings.setValue("tandem/preset_name", preset_name);


          if(_previous_preset_file != param_file.getAbsoluteFilePath())
            {
              _previous_preset_file = param_file.getAbsoluteFilePath();
              try
                {
                  ui->thread_spin_box->setValue(param_file.getTandemParameters()
                                                  .getValue("spectrum, threads")
                                                  .toInt());
                }
              catch(pappso::PappsoException &error)
                {

                  QMessageBox::warning(
                    this,
                    tr("Error reading X!Tandem parameter file"),
                    tr("Error reading parameter file \"%1\":\n%2")
                      .arg(param_file.getAbsoluteFilePath())
                      .arg(error.qwhat()));
                }
            }
        }
    }

  qDebug() << "TandemRunDialog::setPresetName end";
}
void
TandemRunDialog::fillPresetComboBox()
{
  qDebug() << "TandemRunDialog::fillPresetComboBox begin";
  ui->preset_combobox->clear();
  QSettings settings;
  QString default_preset_location =
    settings.value("path/tandemrun_preset_directory", "").toString();
  QString default_preset_name =
    settings.value("tandem/preset_name", "").toString();

  qDebug() << "TandemRunDialog::fillPresetComboBox default_preset_location="
           << default_preset_location;
  qDebug() << "TandemRunDialog::fillPresetComboBox default_preset_name="
           << default_preset_name;
  QDir preset_dir(default_preset_location);
  QStringList filters;
  filters << "*.xml";
  preset_dir.setNameFilters(filters);
  for(QFileInfo file_info : preset_dir.entryInfoList())
    {
      TandemParametersFile param_file(file_info.absoluteFilePath());
      if(param_file.isTandemPresetFile())
        {
          ui->preset_combobox->addItem(file_info.baseName(),
                                       QVariant(file_info.absoluteFilePath()));
        }
    }
  int index = ui->preset_combobox->findText(default_preset_name);
  if(index != -1)
    { // -1 for not found
      ui->preset_combobox->setCurrentIndex(index);
    }
}
void
TandemRunDialog::reset()
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
  QSettings settings;
  QString default_output_location =
    settings.value("path/identificationfiles", "").toString();
  ui->output_directory_label->setText(default_output_location);

  QString tandem_bin_path = settings.value("path/tandem_bin", "").toString();
  fillTandemBinPath(tandem_bin_path, false);

  _p_fasta_file_list->stringList().clear();
  _p_mz_file_list->stringList().clear();
  /*
  if (filenames.size() > 0) {
      settings.setValue("path/identificationfiles",
  QFileInfo(filenames[0]).absolutePath());
  }*/
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
}

void
TandemRunDialog::selectPresetDirectory()
{
  try
    {
      QSettings settings;
      QString default_preset_location =
        settings.value("path/tandemrun_preset_directory", "").toString();

      QString directory = QFileDialog::getExistingDirectory(
        this, tr("Choose preset directory"), default_preset_location);

      if(!directory.isEmpty() && !directory.isNull())
        {
          settings.setValue("path/tandemrun_preset_directory", directory);
          fillPresetComboBox();
        }
    }
  catch(pappso::PappsoException &error)
    {
      // QMessageBox::warning(this,
      //                  tr("Error choosing identification result files :
      //                  %1").arg(error.qwhat()), error);
    }
}

void
TandemRunDialog::editPresets()
{
  QSettings settings;
  QString default_preset_location =
    settings.value("path/tandemrun_preset_directory", "").toString();


  if(_p_preset_dialog == nullptr)
    {
      _p_preset_dialog = new EditTandemPresetDialog(this);
    }
  _p_preset_dialog->setTandemParametersFile(TandemParametersFile(
    ui->preset_combobox->itemData(ui->preset_combobox->currentIndex())
      .value<QString>()));
  _p_preset_dialog->show();


#if QT_VERSION >= 0x050000
  // Qt5 code
  connect(_p_preset_dialog,
          &EditTandemPresetDialog::accepted,
          this,
          &TandemRunDialog::acceptPresetEdit);
  connect(_p_preset_dialog,
          &EditTandemPresetDialog::rejected,
          this,
          &TandemRunDialog::rejectPresetEdit);
#else
  // Qt4 code

#endif
}
void
TandemRunDialog::rejectPresetEdit()
{
  fillPresetComboBox();
}
void
TandemRunDialog::acceptPresetEdit()
{
  TandemParametersFile param_file = _p_preset_dialog->getTandemParametersFile();
  QSettings settings;
  settings.setValue("path/tandemrun_preset_directory",
                    param_file.getAbsoluteDir().absolutePath());
  settings.setValue("tandem/preset_name", param_file.getMethodName());


  fillPresetComboBox();
}

void
TandemRunDialog::selectOutputDirectory()
{
  try
    {
      QSettings settings;
      QString default_output_location =
        settings.value("path/identificationfiles", "").toString();

      QString directory = QFileDialog::getExistingDirectory(
        this, tr("Choose output directory"), default_output_location);

      if(!directory.isEmpty())
        {
          settings.setValue("path/identificationfiles", directory);
          ui->output_directory_label->setText(directory);
        }
    }
  catch(pappso::PappsoException &error)
    {
      // QMessageBox::warning(this,
      //                  tr("Error choosing identification result files :
      //                  %1").arg(error.qwhat()), error);
    }
}

void
TandemRunDialog::clearFastaFiles()
{
  _p_fasta_file_list->removeRows(0, _p_fasta_file_list->rowCount());
}

void
TandemRunDialog::selectFastaFiles()
{
  try
    {
      QSettings settings;
      QString default_fasta_location =
        settings.value("path/tandemrun_fastafiles_directory", "").toString();

      QStringList filenames = QFileDialog::getOpenFileNames(
        this,
        tr("FASTA files"),
        default_fasta_location,
        tr("FASTA files (*.fasta);;all files (*)"));

      if(filenames.size() > 0)
        {
          settings.setValue("path/tandemrun_fastafiles_directory",
                            QFileInfo(filenames[0]).absolutePath());
        }
      QStringList file_list = _p_fasta_file_list->stringList();
      file_list.append(filenames);
      _p_fasta_file_list->setStringList(file_list);
    }
  catch(pappso::PappsoException &error)
    {
      // QMessageBox::warning(this,
      //                  tr("Error choosing identification result files :
      //                  %1").arg(error.qwhat()), error);
    }
}

void
TandemRunDialog::selectXtandemExe()
{
  try
    {
      QSettings settings;
      QString tandem_bin_path =
        settings.value("path/tandem_bin", "").toString();


      QString filename =
        QFileDialog::getOpenFileName(this,
                                     tr("select X!Tandem executable"),
                                     QDir(tandem_bin_path).absolutePath(),
                                     tr("all files (*);;exe files (*.exe)"));
      fillTandemBinPath(filename, true);
    }
  catch(pappso::PappsoException &error)
    {
      // QMessageBox::warning(this,
      //                  tr("Error choosing identification result files :
      //                  %1").arg(error.qwhat()), error);
    }
}

void
TandemRunDialog::selectMzFiles()
{
  try
    {
      QSettings settings;
      QString default_mz_location =
        settings.value("path/tandemrun_mzfiles_directory", "").toString();

      QStringList filenames = QFileDialog::getOpenFileNames(
        this,
        tr("select peak list files"),
        default_mz_location,
        tr("any mz files (*.mzXML *.mzxml *.mzML *.mzml *.mgf *.tdf);;mzXML "
           "(*.mzXML "
           "*.mzxml);;mzML (*.mzML *.mzml);;MGF (*.mgf);; tdf (*.tdf);;all "
           "files (*)"));

      if(filenames.size() > 0)
        {
          settings.setValue("path/tandemrun_mzfiles_directory",
                            QFileInfo(filenames[0]).absolutePath());
        }
      QStringList file_list = _p_mz_file_list->stringList();
      file_list.append(filenames);
      _p_mz_file_list->setStringList(file_list);
    }
  catch(pappso::PappsoException &error)
    {
      // QMessageBox::warning(this,
      //                  tr("Error choosing identification result files :
      //                  %1").arg(error.qwhat()), error);
    }
}

void
TandemRunDialog::selectTdfFolder()
{
  try
    {
      // Input select folders
      QSettings settings;
      QString default_tdf_location =
        settings.value("path/tandemrun_tdf_directory", "/").toString();
      QFileDialog directories_dialog;
      directories_dialog.setDirectory(default_tdf_location);
      directories_dialog.setFileMode(QFileDialog::DirectoryOnly);
      directories_dialog.setOption(QFileDialog::DontUseNativeDialog, true);
      directories_dialog.setWindowTitle("Select the timsTOF folders");
      QListView *lView = directories_dialog.findChild<QListView *>("listView");
      if(lView)
        lView->setSelectionMode(QAbstractItemView::MultiSelection);
      QTreeView *tView = directories_dialog.findChild<QTreeView *>();
      if(tView)
        tView->setSelectionMode(QAbstractItemView::MultiSelection);
      directories_dialog.exec();

      QStringList directories_names;
      if(directories_dialog.result() == QDialog::Accepted)
        {
          directories_names = directories_dialog.selectedFiles();
        }

      if(directories_names.size() > 1)
        {
          settings.setValue("path/tandemrun_tdf_directory",
                            QFileInfo(directories_names[0]).absolutePath());
          directories_names.pop_front();
        }

      // Input select wich type between mgf and TDF
      QMessageBox msgBox;
      QPushButton *mgf_button =
        msgBox.addButton(tr("MGF file"), QMessageBox::ActionRole);
      QPushButton *tdf_button =
        msgBox.addButton(tr("TDF file"), QMessageBox::ActionRole);
      msgBox.addButton(QMessageBox::Discard);

      msgBox.setText("Which file do you want to use ?");
      msgBox.setInformativeText("Choose between MGF and TDF format");
      msgBox.setDefaultButton(QMessageBox::Discard);
      msgBox.exec();

      if(msgBox.clickedButton() == mgf_button)
        {
          // Use the MGF file for identification
          for(QString &directory_name : directories_names)
            {
              QDir dir = QDir(directory_name);

              QStringList filters;
              filters << "*.mgf";
              dir.setNameFilters(filters);
              QFileInfoList results = dir.entryInfoList(dir.nameFilters());
              qDebug() << results;

              if(results.size() == 0)
                {
                  throw pappso::PappsoException(
                    tr("The directory %1/ does not contain the mandatory "
                       "mgf file")
                      .arg(directory_name));
                }
              else if(results.size() > 1)
                {
                  throw pappso::PappsoException(
                    tr("The directory %1/ contains multiple mgf files\nPlease "
                       "correct the ambigous situation\n")
                      .arg(directory_name));
                }
              else
                {
                  directory_name = results[0].absoluteFilePath();
                }
            }

          QStringList file_list = _p_mz_file_list->stringList();
          file_list.append(directories_names);
          _p_mz_file_list->setStringList(file_list);
        }
      else if(msgBox.clickedButton() == tdf_button)
        {
          // Use analysis.tdf file for identification
          for(QString &directory_name : directories_names)
            {
              directory_name = directory_name + "/analysis.tdf";
              if(!QFileInfo(directory_name).exists())
                {
                  throw pappso::PappsoException(
                    tr("The directory %1/ does not contain the mandatory "
                       "analysis.tdf file")
                      .arg(directory_name));
                }
            }

          QStringList file_list = _p_mz_file_list->stringList();
          file_list.append(directories_names);
          _p_mz_file_list->setStringList(file_list);
        }
    }
  catch(pappso::PappsoException &error)
    {
      QMessageBox::warning(
        this, tr("Error choosing identification result files"), error.qwhat());
    }
}


void
TandemRunDialog::clearMzFiles()
{
  _p_mz_file_list->removeRows(0, _p_mz_file_list->rowCount());
}
TandemRunBatch
TandemRunDialog::getTandemRunBatch() const
{
  TandemRunBatch tandem_run_batch;
  tandem_run_batch._tandem_bin_path = ui->tandem_bin_label->text();
  tandem_run_batch._mz_file_list    = _p_mz_file_list->stringList();
  tandem_run_batch._fasta_file_list = _p_fasta_file_list->stringList();
  // tandem_run_batch._preset_file =
  // ui->preset_combobox->itemData(ui->preset_combobox->currentIndex()).value<QFileInfo>().absoluteFilePath();
  tandem_run_batch._preset_file =
    ui->preset_combobox->itemData(ui->preset_combobox->currentIndex())
      .value<QString>();
  tandem_run_batch._output_directory  = ui->output_directory_label->text();
  tandem_run_batch._number_of_threads = ui->thread_spin_box->value();
  return tandem_run_batch;
}


void
TandemRunDialog::done(int r)
{

  if(QDialog::Accepted == r) // ok was pressed
    {

      QSettings settings;
      settings.setValue("tandem/use_HTCondor", "false");
      if(ui->use_htcondor_groupbox->isChecked())
        {
          settings.setValue("tandem/use_HTCondor", "true");
        }

      // QString condor_tmp_dir =
      // QString("%1/xtpcpp").arg(settings.value("condor/tmp_dir",
      // "/tmp").toString()); _p_tmp_dir = new QTemporaryDir(condor_tmp_dir);
      //_p_tmp_dir->setAutoRemove(settings.value("condor/tmp_dir_autoremove",
      // true).toBool()); _condor_submit_command =
      // settings.value("condor/submit", "/usr/bin/condor_submit").toString();
      //_condor_q_command = settings.value("condor/condor_q",
      //"/usr/bin/condor_q").toString(); _condor_rm_command =
      // settings.value("condor/condor_rm", "/usr/bin/condor_rm").toString();
      settings.setValue("tandem/condor_request_memory",
                        ui->request_memory_edit->text());

      if(checkXtandemBin())
        {
          QDialog::done(r);
        }
      else
        {
          QDialog::reject();
        }
      return;
    }
  else // cancel, close or exc was pressed
    {
      QDialog::done(r);
      return;
    }
}


void
TandemRunDialog::fillTandemBinPath(const QString &tandem_bin_path_in,
                                   bool popup_firefox)
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
           << tandem_bin_path_in;
  QSettings settings;
  if(tandem_bin_path_in.isEmpty())
    {
      // try to find default X!Tandem, depending on platform
      ui->tandem_bin_label->setText("");
      if(QFileInfo("/usr/bin/tandem").exists())
        {
          fillTandemBinPath("/usr/bin/tandem", false);
        }
      else
        {
          ui->tandem_version_label->setText(
            "<font color=\"red\">Please select the tandem.exe file "
            "path</font>");
          ui->exe_groupbox->setChecked(true);
        }
    }
  else
    {
      QFileInfo tandem_bin(tandem_bin_path_in);
      QString tandem_bin_path = tandem_bin.absoluteFilePath();

      if(tandem_bin.isExecutable())
        {
          ui->tandem_bin_label->setText(tandem_bin_path);
          settings.setValue("path/tandem_bin", tandem_bin_path);


          try
            {
              if(tandem_bin.baseName() == "xtpcpp")
                {

                  settings.setValue("path/tandem_bin", "");
                  throw new pappso::PappsoException(
                    "X!TandemPipeline is not X!Tandem. Please install "
                    "tandem.exe from https://www.thegpm.org/tandem/ on your "
                    "computer and select the tandem.exe binary");
                }
              ui->tandem_version_label->setText(
                Utils::checkXtandemVersion(tandem_bin_path));
            }

          catch(pappso::PappsoException &error)
            {
              ui->tandem_version_label->setText(
                QString("<font color=\"red\">%1</font>").arg(error.qwhat()));
              ui->exe_groupbox->setChecked(true);
              if(popup_firefox)
                {
                  QDesktopServices::openUrl(
                    QUrl("https://www.thegpm.org/tandem/"));
                }
              ui->exe_group_widget->setHidden(false);
            }
        }
      else
        {
          if(popup_firefox)
            {
              QDesktopServices::openUrl(QUrl("https://www.thegpm.org/tandem/"));
            }
          QMessageBox::warning(
            this,
            tr("Wrong tandem.exe file"),
            tr("%1 is not executable.").arg(tandem_bin_path));
        }
    }
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
}


bool
TandemRunDialog::checkXtandemBin()
{
  QString tandem_bin_path = ui->tandem_bin_label->text();
  QString tandem_install_text =
    "Please check that X!Tandem is "
    "installed on your computer.\nIt is available at "
    ":\nhttps://www.thegpm.org/tandem/\nOnce it is installed, "
    "please "
    "set the correct path to the tandem.exe file";
  QFileInfo tandem_bin(tandem_bin_path);
  if((tandem_bin_path.isEmpty()) || (tandem_bin.baseName() == "xtpcpp"))
    {
      QMessageBox::warning(
        this,
        tr("Wrong X!Tandem configuration"),
        tr("X!Tandem .exe file is not set.\n%1").arg(tandem_install_text));

      QDesktopServices::openUrl(QUrl("https://www.thegpm.org/tandem/"));
    }
  else
    {

      if(tandem_bin.isExecutable())
        {
          try
            {
              Utils::checkXtandemVersion(tandem_bin_path);

              return true;
            }

          catch(pappso::PappsoException &error)
            {
              QMessageBox::warning(
                this,
                tr("Wrong X!Tandem exe file"),
                tr("%1 does not seem to be a valid X!Tandem version.\n%2")
                  .arg(tandem_bin.absoluteFilePath())
                  .arg(tandem_install_text));

              QDesktopServices::openUrl(QUrl("https://www.thegpm.org/tandem/"));
            }
        }
      else
        {
          QMessageBox::warning(this,
                               tr("Wrong X!Tandem exe file"),
                               tr("%1 is not executable.\n%2")
                                 .arg(tandem_bin_path)
                                 .arg(tandem_install_text));
        }
    }


  return false;
}
