/**
 * \file /gui/run/mcqr_spectral_count/mcqrscrunview.h
 * \date 21/12/2023
 * \author Olivier Langella
 * \brief dialog window to run MCQR spectral count process
 */

/*********************MsStatsRunView**********************************************************
 * Copyright (c) 2023 Olivier Langella
 *<Olivier.Langella@universite-paris-saclay.fr>.
 *
 * This file is part of i2MassChroQ.
 *
 *     i2MassChroQ 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.
 *
 *     i2MassChroQ 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 i2MassChroQ.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#include "mcqrscrunview.h"
#include "../../mainwindow.h"
#include "ui_mcqr_sc_run_view.h"
#include <QDebug>
#include <pappsomspp/core/exception/exceptionnotpossible.h>
#include <pappsomspp/core/exception/exceptionnotfound.h>
#include "../../../output/mcqrspectralcount.h"
#include "../../../output/mcqr/mcqrmetadataods.h"
#include <odsstream/tsvoutputstream.h>
#include <odsstream/odsdocwriter.h>
#include <odsstream/odsexception.h>


McqrScRunView::McqrScRunView(MainWindow *parent)
  : RworkflowRunViewBase(parent), ui(new Ui::McqrScRunView)
{
  ui->setupUi(this);

  msp_project = parent->getProjectSp();
  qDebug();
  m_rviewName = "MCQR Spectral Count";

  ui->a1_all_protein_radioButton->setChecked(true);
  checkInstall();
}

McqrScRunView::~McqrScRunView()
{
}

WidgetRprocess *
McqrScRunView::getWidgetRprocess() const
{
  return (ui->widgetRprocess);
}

void
McqrScRunView::checkInstall()
{

  Cutelee::Engine *engine_p = new Cutelee::Engine();
  auto loader = std::shared_ptr<Cutelee::FileSystemTemplateLoader>(
    new Cutelee::FileSystemTemplateLoader());
  loader->setTemplateDirs({":/templates/resources/templates/mcqr_scripts"});
  engine_p->addTemplateLoader(loader);
  Cutelee::Template rscript_template_sp =
    engine_p->loadByName("mcqr_packages_handler.R");
  Cutelee::Context empty_context;
  ui->widgetRprocess->executeOnTheRecord(
    rscript_template_sp->render(&empty_context));

  qDebug();

  executeStep("libraries");
}

void
McqrScRunView::doA2A2McqrPca()
{
  executeStep("a2a2_mcqr_pca");
}

void
McqrScRunView::doA3A1McqrRemoveMsrun()
{
  executeStep("a3a1_mcqr_remove_msrun");
}

void
McqrScRunView::doA5McqrHeatmap()
{
  executeStep("a5_mcqr_heatmap");
}

void
McqrScRunView::doA4McqrProteinFilter()
{
  executeStep("a4_mcqr_filter_protein");
}

void
McqrScRunView::doA6McqrCluster()
{
  executeStep("a6_mcqr_cluster");
}

void
McqrScRunView::doA7McqrAnova()
{
  executeStep("a7_mcqr_anova");
}

void
McqrScRunView::doA8McqrPlotProteinAbundance()
{
  executeStep("a8_mcqr_plot_protein_abundance");
}

void
McqrScRunView::doA9McqrProteinAbundanceFoldChange()
{
  executeStep("a9_mcqr_protein_abundance_fold_change");
}

void
McqrScRunView::executeStep(const QString &step)
{
  qDebug() << step;

  Cutelee::Engine *engine_p = new Cutelee::Engine();
  auto loader = std::shared_ptr<Cutelee::FileSystemTemplateLoader>(
    new Cutelee::FileSystemTemplateLoader());
  loader->setTemplateDirs({":/templates/resources/templates/mcqr_scripts"});
  engine_p->addTemplateLoader(loader);
  Cutelee::Template rscript_template_sp =
    engine_p->loadByName("mcqr_spectral_count_analysis.R");
  Cutelee::Context context;
  context.insert("step", step);

  if(step != "libraries")
    {
      if(m_workingDirectory.isEmpty())
        {
          warning("Error : working directory is not set.");
          return;
        }
      else
        {
          if(ui->widgetRprocess->isFinished())
            {
              executeStep("libraries");
            }
          context.insert(
            "tmp_path",
            QDir(m_workingDirectory).absoluteFilePath(" ").trimmed());


          context.insert(
            "tmp_path",
            QDir(m_workingDirectory).absoluteFilePath(" ").trimmed());
          if(step == "load")
            {
              context.insert("spectral_count_tsv_file", "spectral_count.tsv");
              context.insert("specific_peptides", "FALSE");
            }

          else if(step == "merge_metadata")
            {
            }
          else if(step == "a2a2_mcqr_pca")
            {
              if(!fileExists("sc.rdata"))
                {
                  warning("Error : metadata file not uploaded.");
                  return;
                }

              // factors_color
              if(!getColorListString().isEmpty())
                {
                  context.insert("factors_color", getColorListString());
                }
              // factors_label
              context.insert("factors_label", getLabelListString());

              //{{ factors_color }}), labels=c({{ factors_label }}
            }
          else if(step == "a3a1_mcqr_remove_msrun")
            {
              context.insert("msrun_list_drop",
                             ui->msrunListView->getMsrunListString());

              if(!fileExists("sc.rdata"))
                {
                  warning("Error : metadata file not uploaded.");
                  return;
                }
            }

          else if(step == "a4_mcqr_filter_protein")
            {
              // prot_cutoff
              context.insert("prot_cutoff",
                             ui->a4_spectra_cutoff_spin->value());
              // foldchange_cutoff
              context.insert("foldchange_cutoff",
                             ui->a4_fc_doubleSpinBox->value());
              // factors_list
              context.insert("factors_list", getFactorListString());
              if(!fileExists("sc.rdata"))
                {
                  warning("Error : metadata file not uploaded.");
                  return;
                }
            }
          else if(step == "a5_mcqr_heatmap")
            {
              qDebug() << step;
              if(!fileExists("sc.rdata"))
                {
                  warning("Error : missing previous steps.");
                  return;
                }

              if(getFactorListString().isEmpty())
                {
                  warning("Error : please select at least one factor.");
                  return;
                }
              // factors_list
              context.insert("factors_list", getFactorListString());
              // factors_color
              context.insert("factors_color", getColorListString());
              // distance_fun
              context.insert("distance_fun",
                             ui->distfun_combobox->currentText());
              // agg_method
              context.insert("agg_method",
                             ui->agg_method_combobox->currentText());
            }
          else if(step == "a6_mcqr_cluster")
            {
              qDebug() << step;

              if(!fileExists("sc.rdata"))
                {
                  warning("Error : missing previous steps.");
                  return;
                }


              if(getFactorListString().isEmpty())
                {
                  warning("Error : please select at least one factor.");
                  return;
                }

              // factor_list
              context.insert("factors_list", getFactorListString());
              // nb_cluster
              context.insert("nb_cluster", ui->cluster_spin->value());
              // cluster_method
              context.insert("cluster_method",
                             ui->cluster_method_comboBox->currentText());
            }
          else if(step == "a7_mcqr_anova")
            {
              qDebug() << step;
              if(!fileExists("sc.rdata"))
                {
                  warning("Error : missing previous steps.");
                  return;
                }

              // factor_list
              context.insert("factors_list", getFactorListString());
              // fc_cutoff
              context.insert("fc_cutoff", ui->anova_fc_cutoff_spin->value());
              // inter_bool
              context.insert(
                "inter_bool",
                toRboolean(ui->interaction_anova_switch->getSwitchValue()));
            }

          else if(step == "a8_mcqr_plot_protein_abundance")
            {
              qDebug() << step;
              if(getFactorListString().size() == 0)
                {
                  warning("Error : you have to choose at least one factor.");
                  return;
                }
              if(!fileExists("sc_anova.rdata"))
                {
                  warning("Error : missing previous steps.");
                  return;
                }

              // factors_list
              context.insert("factors_string_list",
                             ui->factorListView->getQStringList());
              // factors_list_join
              context.insert("factors_list_join", getFactorListString());
              // padjust
              context.insert("padjust",
                             toRboolean(ui->padjust_switch->getSwitchValue()));
              // alpha
              context.insert("alpha", ui->alpha_spin->value());
              // factors_color
              context.insert("factors_color", getColorListString());
            }
          else if(step == "a9_mcqr_protein_abundance_fold_change")
            {
              qDebug() << step;
              if(!fileExists("sc_selected.rdata"))
                {
                  warning("Error : missing previous steps.");
                  return;
                }
              // fc_factor
              context.insert("fc_factor",
                             ui->factorFoldChangeCombobox->currentText());
              // num
              context.insert("num",
                             ui->numeratorFoldChangeCombobox->currentText());
              // denom
              context.insert("denom",
                             ui->denominatorFoldChangeCombobox->currentText());
            }
          else
            {
              throw pappso::PappsoException(
                tr("MCQR step %1 does not exists").arg(step));
            }
        }
    }
  try
    {
      ui->widgetRprocess->executeStepOnTheRecord(
        step, rscript_template_sp->render(&context));
    }
  catch(pappso::ExceptionNotPossible &error)
    {
      warning(error.qwhat());
    }
}

void
McqrScRunView::setWorkingDirectoryLabel()
{
  ui->wdLabel->setText(m_workingDirectory);

  // write spectral count tables in the directory

  QDir directory(m_workingDirectory);
  try
    {

      qDebug() << directory.absoluteFilePath("spectral_count.tsv");
      QFile outFile;
      outFile.setFileName(directory.absoluteFilePath("spectral_count.tsv"));
      outFile.open(QIODevice::WriteOnly);
      QTextStream *p_outputStream = new QTextStream(&outFile);
      TsvOutputStream *p_writer   = new TsvOutputStream(*p_outputStream);
      p_writer->setNoSheetName(true);
      McqrSpectralCountProteinSet protein_set =
        McqrSpectralCountProteinSet::allGroupedProteins;
      if(ui->a1_all_protein_subgroups_radioButton->isChecked())
        {
          protein_set = McqrSpectralCountProteinSet::allProteinSubgroups;
        }
      McqrSpectralCount spectra_sheet(p_writer, msp_project.get(), protein_set);
      spectra_sheet.writeSheet();

      p_writer->close();
      delete p_writer;
      delete p_outputStream;
      outFile.close();


      if(QFileInfo(directory.absoluteFilePath("metadata.ods")).exists())
        {
          try
            {
              updateMetadataFactorListView();
            }
          catch(pappso::ExceptionNotFound &not_found)
            {
            }
        }
    }
  catch(pappso::PappsoException &error)
    {
      warning(error.qwhat());
    }


  if(!QFileInfo(directory.absoluteFilePath("sc.rdata")).exists())
    {
      while(getWidgetRprocess()->isWorking())
        {
          // sleep(100);
          QThread::msleep(100);
        }
      executeStep("load");
    }
}

void
McqrScRunView::doGetMetadataTemplateFile()
{

  McqrMetadataSet metadata_set = msp_project.get()->getMcqrMetadataSet();

  metadata_set.addColumn("Condition");
  metadata_set.addColumn("BioReplicate");


  QSettings settings;
  QString metadata_template_path =
    QFileDialog::getSaveFileName(this,
                                 tr("Save the template"),
                                 "metadata_template.ods",
                                 tr("Spreadsheet (*.ods)"));
  if(!metadata_template_path.isEmpty())
    {
      try
        {
          qDebug() << metadata_template_path;
          CalcWriterInterface *p_writer =
            new OdsDocWriter(metadata_template_path);
          qDebug();
          McqrMetadataOds mcqr_metadata_ods(p_writer, metadata_set);

          qDebug();
          p_writer->close();
          settings.setValue("mcqr/metadata_path", metadata_template_path);

          launchDesktopSoftwareOnFile(metadata_template_path);
          qDebug();
        }
      catch(OdsException &error)
        {
          qDebug() << tr("error while writing metadata template:\n%1")
                        .arg(error.qwhat());
        }
      catch(pappso::PappsoException &error)
        {
          qDebug() << tr("error while downloading the metadata template:\n%1")
                        .arg(error.qwhat());
        }
    }
}

void
McqrScRunView::doGetSpectrumCountTable()
{

  QSettings settings;

  QDir dir(settings.value("path/export_ods", "").toString());
  QString sc_table_path =
    QFileDialog::getSaveFileName(this,
                                 tr("Save spectrum count table in ODS file"),
                                 dir.absoluteFilePath("spectrum_count.ods"),
                                 tr("Spreadsheet (*.ods);;All files (*.*)"));
  settings.setValue("path/export_ods", QDir(sc_table_path).absolutePath());
  if(!sc_table_path.isEmpty())
    {
      try
        {
          QFile outFile;
          outFile.setFileName(QFileInfo(sc_table_path).absoluteFilePath());
          outFile.open(QIODevice::WriteOnly);
          OdsDocWriter writer(&outFile);
          // p_writer->setNoSheetName(true);
          McqrSpectralCountProteinSet protein_set =
            McqrSpectralCountProteinSet::allGroupedProteins;
          if(ui->a1_all_protein_subgroups_radioButton->isChecked())
            {
              protein_set = McqrSpectralCountProteinSet::allProteinSubgroups;
            }
          McqrSpectralCount spectra_sheet(
            &writer, msp_project.get(), protein_set);
          spectra_sheet.writeSheet();

          writer.close();
          outFile.close();

          launchDesktopSoftwareOnFile(
            QFileInfo(sc_table_path).absoluteFilePath());
        }
      catch(pappso::PappsoException &error)
        {
          warning(QObject::tr("Cannot write spectral count table ods file: %1")
                    .arg(error.qwhat()));
        }
    }
}

void
McqrScRunView::doUploadMetadataFile()
{


  QSettings settings;

  QString metadata_path = QFileDialog::getOpenFileName(
    this,
    tr("select the metadata file"),
    settings.value("mcqr/metadata_path", "/").toString(),
    tr("Spreadsheet (*.ods)"));
  qDebug() << QFileInfo(metadata_path).absoluteFilePath();
  if(!metadata_path.isEmpty())
    {
      try
        {
          QDir directory(m_workingDirectory);

          qDebug() << directory.absoluteFilePath("metadata.ods");
          if(directory.absoluteFilePath("metadata.ods") ==
             QFileInfo(metadata_path).absoluteFilePath())
            {
              throw pappso::PappsoException(
                QObject::tr("Unable to read metadata file : %1\n Please "
                            "prepare your metadata file in an other directory")
                  .arg(directory.absoluteFilePath("metadata.ods")));
            }

          if(QFileInfo(directory.absoluteFilePath("metadata.ods")).exists())
            {

              if(QFile::remove(directory.absoluteFilePath("metadata.ods")))
                {
                  // OK
                }
              else
                {
                  throw pappso::PappsoException(
                    QObject::tr("Unable to remove existing file : %1\n Please "
                                "check for file system permissions")
                      .arg(directory.absoluteFilePath("metadata.ods")));
                }
            }
          if(QFile::copy(metadata_path,
                         directory.absoluteFilePath("metadata.ods")))
            {
              // OK
            }
          else
            {
              throw pappso::PappsoException(
                QObject::tr("Unable write file : %1\nPlease check for file "
                            "system permissions")
                  .arg(directory.absoluteFilePath("metadata.ods")));
            }


          try
            {
              updateMetadataFactorListView();
            }
          catch(pappso::ExceptionNotFound &not_found)
            {
            }

          QFile::remove(directory.absoluteFilePath("sc_nometadata.rdata"));
          QFile::remove(directory.absoluteFilePath("sc.rdata"));

          while(getWidgetRprocess()->isWorking())
            {
              // sleep(100);
              QThread::msleep(100);
            }
          executeStep("load");

          while(getWidgetRprocess()->isWorking())
            {
              // sleep(100);
              QThread::msleep(100);
            }
          executeStep("merge_metadata");
        }
      catch(pappso::PappsoException &error)
        {
          warning(QObject::tr("Cannot load metadata ods file: %1")
                    .arg(error.qwhat()));
        }
      qDebug();
    }
}

void
McqrScRunView::updateMetadataFactorListView()
{

  m_metadataSet = readMetadata();
  ui->colorListView->setMcqrMetadataSet(m_metadataSet);
  ui->factorListView->setMcqrMetadataSet(m_metadataSet);
  ui->labelListView->setMcqrMetadataSet(m_metadataSet);
  ui->factorFoldChangeCombobox->setMcqrMetadataSet(m_metadataSet);
  ui->msrunListView->setMcqrMetadataSet(m_metadataSet);
  // ui->numeratorFoldChangeCombobox->setMcqrMetadataSet(metadata_set);
  // ui->denominatorFoldChangeCombobox->setMcqrMetadataSet(metadata_set);

  doFactorProteinFoldSelected(ui->factorFoldChangeCombobox->currentText());
}


QString
McqrScRunView::getColorListString() const
{
  QString color_list;
  if(ui->colorListView->getQStringList().size() > 0)
    {
      color_list = QString("\"%1\"").arg(
        ui->colorListView->getQStringList().join("\",\""));
    }
  return color_list;
}

QString
McqrScRunView::getFactorListString() const
{
  QString color_list;
  if(ui->factorListView->getQStringList().size() > 0)
    {
      color_list = QString("\"%1\"").arg(
        ui->factorListView->getQStringList().join("\",\""));
    }
  return color_list;
}

QString
McqrScRunView::getLabelListString() const
{
  QString color_list;
  if(ui->labelListView->getQStringList().size() > 0)
    {
      color_list = QString("\"%1\"").arg(
        ui->labelListView->getQStringList().join("\",\""));
    }
  return color_list;
}

void
McqrScRunView::doFactorProteinFoldSelected(QString factor)
{

  qDebug() << factor;
  ui->numeratorFoldChangeCombobox->setMcqrMetadataSetFactorValues(m_metadataSet,
                                                                  factor);
  ui->denominatorFoldChangeCombobox->setMcqrMetadataSetFactorValues(
    m_metadataSet, factor);
}
