/**
 * \file gui/export/export_masschroq_dialog/exportmasschroqdialog.cpp
 * \date 25/01/2019
 * \author Olivier Langella
 * \brief choose ODS export options
 */

/*******************************************************************************
 * Copyright (c) 2019 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/>.
 *
 ******************************************************************************/

#include "ui_masschroq_run_dialog.h"
#include "masschroqrundialog.h"
#include <QDebug>
#include <QSettings>
#include <QMessageBox>
#include <QFileDialog>
#include <pappsomspp/msrun/alignment/msrunretentiontime.h>
#include <pappsomspp/msfile/msfileaccessor.h>
#include <pappsomspp/pappsoexception.h>
#include "../mainwindow.h"
#include "../../utils/utils.h"

MassChroqRunDialog::MassChroqRunDialog(MainWindow *parent,
                                       WorkerThread *p_worker)
  : QDialog(parent), ui(new Ui::MassChroqRunDialog)
{
  qDebug();
  mp_main = parent;
  ui->setupUi(this);
  this->setModal(true);

  ui->listWidget->clear();
  ui->msrun_list_combo_box->clear();

  ui->label_msrun_not_found->setHidden(true);
  ui->toolButton_2->setHidden(true);
  ui->label_check->setHidden(true);
  ui->label_msrun_not_found->setStyleSheet("QLabel { color : red; }");

  QSettings settings;
  ui->use_ht_condor_group->setChecked(
    settings.value("masschroq/use_htcondor", "false").toBool());
  ui->ht_condor_memory_spin->setValue(
    settings.value("masschroq/htcondor_memory", "5000").toInt());

  setMassChroQRunParamTab();
  mp_poModel = new QStandardItemModel(ui->group_listView);

  connect(this,
          &MassChroqRunDialog::accepted,
          mp_main,
          &MainWindow::doAcceptedMassChroqRunDialog);
  connect(this,
          &MassChroqRunDialog::operateAcceptedMassChroqRunDialog,
          mp_main,
          &MainWindow::doAcceptedMassChroqRunDialog);

  connect(this,
          &MassChroqRunDialog::operateFindBestMsrunForAlignment,
          p_worker,
          &WorkerThread::doFindBestMsrunForAlignment);
  connect(p_worker,
          &WorkerThread::findingBestMsrunForAlignmentFinished,
          this,
          &MassChroqRunDialog::setBestMsrunForAlignment);


  connect(this,
          &MassChroqRunDialog::operateCheckingMsrunFilePath,
          p_worker,
          &WorkerThread::doCheckMsrunFilePath);
  connect(p_worker,
          &WorkerThread::checkingMsrunFilePathFinished,
          this,
          &MassChroqRunDialog::setCheckMsrunFilePathOk);


  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
}

MassChroqRunDialog::~MassChroqRunDialog()
{
  delete ui;
}

void
MassChroqRunDialog::setProjectSPtr(ProjectSp p_project)
{
  msp_project = p_project;
}

void
MassChroqRunDialog::setMasschroqFileParameters(
  const MasschroqFileParameters &params)
{
  ZivyParams zivy_params;
  zivy_params.loadSettings();

  ui->zivyParamWidget->setZivyParams(zivy_params);

  ui->outputFileFormatComboBox->setCurrentText("ODS");
  if(params.result_file_format == TableFileFormat::tsv)
    {
      ui->outputFileFormatComboBox->setCurrentText("TSV");
    }

  ui->compar_radioButton->setChecked(params.export_compar_file);

  ui->timeCorrectionGroupBox->setChecked(params.write_alignment_times);
  ui->timeCorrectionDirectoryEdit->setText(params.alignment_times_directory);

  ui->ms2TendencySpinBox->setValue(params.ms2_tendency_half_window);
  ui->ms2SmoothingSpinBox->setValue(params.ms2_smoothing_half_window);
  ui->ms1SmoothingSpinBox->setValue(params.ms1_smoothing_half_window);

  ui->xicRangeWidget->setPrecision(params.xic_extraction_range);
}


MasschroqFileParameters
MassChroqRunDialog::getMasschroqFileParameters() const
{
  MasschroqFileParameters params;

  params.result_file_format = TableFileFormat::ods;
  if(ui->outputFileFormatComboBox->currentText() == "TSV")
    {
      params.result_file_format = TableFileFormat::tsv;
    }
  for(int i = 0; i < mp_poModel->rowCount(); i++)
    {
      qDebug() << mp_poModel->item(i, 0)->checkState();
      if(mp_poModel->item(i, 0)->checkState() == Qt::CheckState(Qt::Checked))
        {
          params.alignment_groups.push_back(msp_alignmentGroups.at(i));
        }
    }

  params.export_compar_file = ui->compar_radioButton->isChecked();

  params.write_alignment_times     = ui->timeCorrectionGroupBox->isChecked();
  params.alignment_times_directory = ui->timeCorrectionDirectoryEdit->text();

  params.ms2_tendency_half_window  = ui->ms2TendencySpinBox->value();
  params.ms2_smoothing_half_window = ui->ms2SmoothingSpinBox->value();
  params.ms1_smoothing_half_window = ui->ms1SmoothingSpinBox->value();

  params.xic_extraction_range = ui->xicRangeWidget->getPrecision();

  params.xic_extraction_method =
    ui->xic_extraction_method_widget->getXicExtractionMethod();

  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
           << (int)params.xic_extraction_method;
  return params;
}


void
MassChroqRunDialog::reject()
{
  msp_project = nullptr;
  QDialog::reject();
}

void
MassChroqRunDialog::accept()
{
  QString error_message;
  if(ui->timeCorrectionGroupBox->isChecked())
    {
      if(ui->timeCorrectionDirectoryEdit->text().isEmpty())
        {
          error_message = QString(tr(
            "the directory name to write alignment corrections must be set"));
        }
    }

  if((ui->xicRangeWidget->getPrecision()->unit() ==
      pappso::PrecisionUnit::ppm) ||
     (ui->xicRangeWidget->getPrecision()->unit() ==
      pappso::PrecisionUnit::dalton))
    { // ok
    }
  else
    {
      error_message =
        QString(tr("MassChroQ can only work with ppm or dalton units. Please "
                   "change the XIC extraction precision unit."));
    }

  // check if at least one group is checked
  int count = 0;
  for(int i = 0; i < mp_poModel->rowCount(); i++)
    {
      if(mp_poModel->item(i, 0)->checkState() == Qt::CheckState(Qt::Checked))
        {
          count++;
        }
    }
  if(count == 0)
    {
      error_message =
        QString(tr("You have to select at least one alignment group to run "
                   "MasschroQ or to save the MassChroQml!"));
    }

  if(error_message.isEmpty())
    {
      ZivyParams zivy_params = ui->zivyParamWidget->getZivyParams();
      zivy_params.saveSettings();
      msp_project = nullptr;
      QDialog::accept();
    }
  else
    {
      QMessageBox msgBox;
      msgBox.setWindowTitle(tr("MassChroQ parameter problem"));
      msgBox.setText(error_message);
      msgBox.setIcon(QMessageBox::Critical);
      msgBox.exec();
    }
}


void
MassChroqRunDialog::doCheckMsrunFilepath()
{

  mp_main->showWaitingMessage(tr("Checking MSrun files path"));
  emit operateCheckingMsrunFilePath(msp_project);
}

void
MassChroqRunDialog::doBrowseMsrunDirectory()
{

  QSettings settings;
  QString path     = settings.value("path/mzdatadir", "").toString();
  QString filename = QFileDialog::getExistingDirectory(
    this, tr("Choose directory to look for MS runs"), QString("%1").arg(path));

  if(!filename.isEmpty())
    {
      QDir parent(filename);
      // parent.cdUp();
      settings.setValue("path/mzdatadir", parent.canonicalPath());
      doCheckMsrunFilepath();
      qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
               << parent.absolutePath();
    }
}


void
MassChroqRunDialog::doFindBestMsrunForAlignment()
{
  if(msp_selected_group != nullptr)
    {
      mp_main->showWaitingMessage(tr("Looking for MSrun reference"));

      emit operateFindBestMsrunForAlignment(msp_project, msp_selected_group);
    }
  else
    {
      QMessageBox::warning(
        this,
        "Select a group",
        "The reference is linked to a group.\n You have to select one.");
    }
}

void
MassChroqRunDialog::setBestMsrunForAlignment(MsRunSp best_msrun_sp)
{

  mp_main->hideWaitingMessage();
  if(best_msrun_sp != nullptr)
    {
      qDebug() << best_msrun_sp.get();

      int index = 0;
      for(MsRunSp ms_run : msp_selected_group->getMsRunsInAlignmentGroup())
        {
          if(ms_run == best_msrun_sp)
            {
              ui->msrun_list_combo_box->setCurrentIndex(index);
              msp_selected_group->setMsRunReference(best_msrun_sp);
            }
          index++;
        }
    }
}

void
MassChroqRunDialog::setCheckMsrunFilePathOk(MsRunSp msrun_sp)
{
  mp_main->hideWaitingMessage();
  if(msrun_sp == nullptr)
    {
      ui->label_check->setHidden(false);
      ui->label_msrun_not_found->setHidden(true);
      ui->toolButton_2->setHidden(true);
    }
  else
    {
      ui->label_msrun_not_found->setText(
        tr("\"%1\" not found : Please choose the directory")
          .arg(msrun_sp.get()->getFileName()));
      ui->label_msrun_not_found->setHidden(false);
      ui->toolButton_2->setHidden(false);
    }
}

void
MassChroqRunDialog::setAlignmentGroups()
{
  // ui->listWidget_2->clear();
  msp_alignmentGroups = msp_project->getMsRunAlignmentGroupList();
  int i               = 0;
  for(MsRunAlignmentGroupSp group : msp_alignmentGroups)
    {
      QStandardItem *new_item =
        new QStandardItem(group->getMsRunAlignmentGroupName());
      new_item->setCheckable(true);
      new_item->setData(Qt::Unchecked, Qt::CheckStateRole);
      mp_poModel->setItem(i, new_item);
      i++;
    }
  ui->group_listView->setModel(mp_poModel);
}

void
MassChroqRunDialog::doShowMsRunsInAlignmentGroup(QModelIndex index)
{
  ui->listWidget->clear();
  ui->msrun_list_combo_box->clear();
  msp_selected_group = msp_alignmentGroups.at(index.row());
  ui->groupBox_5->setTitle("Ms runs in " +
                           msp_selected_group->getMsRunAlignmentGroupName());
  for(MsRunSp ms_run : msp_selected_group->getMsRunsInAlignmentGroup())
    {
      ui->listWidget->addItem(ms_run->getSampleName());
      ui->msrun_list_combo_box->addItem(ms_run->getSampleName());
    }
  if(msp_selected_group->getMsRunReference() != nullptr)
    {
      int index = 0;
      for(MsRunSp ms_run : msp_selected_group->getMsRunsInAlignmentGroup())
        {
          if(ms_run == msp_selected_group->getMsRunReference())
            {
              ui->msrun_list_combo_box->setCurrentIndex(index);
            }
          index++;
        }
    }
  else
    {
      ui->msrun_list_combo_box->setCurrentIndex(-1);
    }
}

void
MassChroqRunDialog::doUpdateReferenceInSelectedGroup(int index)
{
  int temp_index = 0;
  for(MsRunSp ms_run : msp_selected_group->getMsRunsInAlignmentGroup())
    {
      if(temp_index == index)
        {
          msp_selected_group->setMsRunReference(ms_run);
        }
      temp_index++;
    }
  qDebug() << index;
}

void
MassChroqRunDialog::doRunMassChroQ()
{
  m_runMassChroqAsked = true;
  QSettings settings;
  settings.setValue("masschroq/use_htcondor",
                    ui->use_ht_condor_group->isChecked());
  settings.setValue("masschroq/htcondor_memory",
                    ui->ht_condor_memory_spin->value());
  accept();
}

void
MassChroqRunDialog::doSaveMassChroQML()
{
  m_runMassChroqAsked = false;
  accept();
}

void
MassChroqRunDialog::doBrowseMassChroQBin()
{
  QSettings settings;
  QString path = settings.value("masschroq/bin_path", "").toString();

  QString filename = QFileDialog::getOpenFileName(
    this, tr("Select the MassCHroQ executable"), tr("%1").arg(path));

  if(!filename.isEmpty())
    {
      ui->masschroq_bin_path_line->setText(filename);
      settings.setValue("masschroq/bin_path", filename);
    }
}

void
MassChroqRunDialog::doBrowseTempDir()
{
  QSettings settings;
  QString path = settings.value("masschroq/tmp_dir_path", "").toString();

  QString filename = QFileDialog::getExistingDirectory(
    this, tr("Select the MassCHroQ executable"), tr("%1").arg(path));

  if(!filename.isEmpty())
    {
      ui->temporary_directory_line->setText(filename);
      settings.setValue("masschroq/tmp_dir_path", filename);
    }
}


bool
MassChroqRunDialog::getMassChroqRunStatus()
{
  return m_runMassChroqAsked;
}

MassChroQRunBatch
MassChroqRunDialog::getMassChroqRunBatchParam()
{
  return m_masschroqBatchParam;
}

void
MassChroqRunDialog::setMassChroqRunBatchParam(QString masschroqml_file)
{
  QSettings settings;
  m_masschroqBatchParam.masschroq_bin_path =
    ui->masschroq_bin_path_line->text().trimmed();
  settings.setValue("masschroq/bin_path",
                    m_masschroqBatchParam.masschroq_bin_path);
  m_masschroqBatchParam.masschroq_temporary_dir_path =
    ui->temporary_directory_line->text().trimmed();
  settings.setValue("masschroq/tmp_dir_path",
                    m_masschroqBatchParam.masschroq_temporary_dir_path);
  m_masschroqBatchParam.number_cpu = ui->cpu_spinbox->value();
  settings.setValue("masschroq/nbr_cpu", ui->cpu_spinbox->value());
  m_masschroqBatchParam.masschroqml_path = masschroqml_file;
  m_masschroqBatchParam.on_disk          = ui->temp_checkbox->isChecked();
  settings.setValue("masschroq/on_disk", ui->temp_checkbox->isChecked());
  m_masschroqBatchParam.parse_peptide = ui->peptide_checkbox->isChecked();
  settings.setValue("masschroq/parse_peptide",
                    ui->peptide_checkbox->isChecked());
}

void
MassChroqRunDialog::setMassChroQRunParamTab()
{
  QSettings settings;
  ui->masschroq_bin_path_line->setText(
    settings.value("masschroq/bin_path").toString());
  ui->temporary_directory_line->setText(
    settings.value("masschroq/tmp_dir_path").toString());
  ui->cpu_spinbox->setMaximum(QThread::idealThreadCount());
  if(settings.value("masschroq/nbr_cpu").toInt() <= QThread::idealThreadCount())
    {
      ui->cpu_spinbox->setValue(settings.value("masschroq/nbr_cpu").toInt());
    }
  else
    {
      ui->cpu_spinbox->setValue(1);
    }
  ui->temp_checkbox->setChecked(
    settings.value("masschroq/on_disk", "false").toBool());
  ui->peptide_checkbox->setChecked(
    settings.value("masschroq/parse_peptide", "false").toBool());
}
