/**
 * \file gui/mcqr_run_view/mcqr_sds_widget/mcqrsdswidget.cpp
 * \date 30/06/2021
 * \author Thomas Renne
 * \brief widget to run SDS script from MCQR
 */

/*******************************************************************************
 * Copyright (c) 2021 Thomas Renne <thomas.renne@e.email>.
 *
 * 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:
 *     Thomas Renne <thomas.renne@e.email> - initial API and
 *implementation
 ******************************************************************************/

#include "mcqrsdswidget.h"
#include "ui_mcqr_sds_widget.h"

#include <QFileInfo>
#include <QDir>
#include <pappsomspp/pappsoexception.h>
#include <pappsomspp/utils.h>

#include "../mcqrrunview.h"
#include <QMessageBox>
#include <QFileDialog>

McqrSdsWidget::McqrSdsWidget(McqrRunView *mcqr_window,
                             const McqrExperimentSp &p_mcqr_experiment)
  : McqrParamWidget(mcqr_window, p_mcqr_experiment), ui(new Ui::McqrSdsWidget)
{
  qDebug() << "Open SDS parameters widget";
  ui->setupUi(this);

  mp_factorsColorModel = new QStandardItemModel(ui->factors_color_view);
  mp_factorsLabelModel = new QStandardItemModel(ui->factors_label_view);
  mp_factorsListModel  = new QStandardItemModel(ui->factors_list_view);

  mp_msrunRemoveModel = new QStandardItemModel(ui->msrun_list_view);
  qDebug() << (std::int8_t)m_ongoingMcqrStep;
  disableFutureStepsInToolBox();
  addFactorsToListViews();
  initGrantleeEngine();
}

McqrSdsWidget::~McqrSdsWidget()
{
}

void
McqrSdsWidget::disableFutureStepsInToolBox()
{
  int number_of_pages = ui->toolBox->count();
  for(int i = 1; i < number_of_pages; i++)
    {
      ui->toolBox->setItemEnabled(i, false);
    }
}

void
McqrSdsWidget::addFactorsToListViews()
{
  int i = 0;
  for(QString factor : getMcqrExperimentSpLoaded().get()->getmetadataColumns())
    {
      QStandardItem *new_factor_color = new QStandardItem(factor);
      new_factor_color->setCheckable(true);
      new_factor_color->setData(Qt::Unchecked, Qt::CheckStateRole);
      mp_factorsColorModel->setItem(i, new_factor_color);

      QStandardItem *new_factor_label = new QStandardItem(factor);
      new_factor_label->setCheckable(true);
      new_factor_label->setData(Qt::Unchecked, Qt::CheckStateRole);
      mp_factorsLabelModel->setItem(i, new_factor_label);

      QStandardItem *new_factor_item = new QStandardItem(factor);
      new_factor_item->setCheckable(true);
      new_factor_item->setData(Qt::Unchecked, Qt::CheckStateRole);
      mp_factorsListModel->setItem(i, new_factor_item);

      i++;
    }
  ui->factors_color_view->setModel(mp_factorsColorModel);
  ui->factors_label_view->setModel(mp_factorsLabelModel);
  ui->factors_list_view->setModel(mp_factorsListModel);

  ui->factors_list_widget->setVisible(true);
  ui->toolBox->adjustSize();
  //   ui->toolBox->setMinimumHeight(ui->quality_page->height() + 250);
}

void
McqrSdsWidget::changeToolBoxHeight(int tab_selected)
{
  //   ui->toolBox->setMinimumHeight(ui->toolBox->widget(tab_selected)->height()
  //   +
  //                                 250);
  ui->toolBox->adjustSize();
  ui->scrollAreaWidgetContents->updateGeometry();
  ui->scrollArea->update();

  for(int i = 0; i < mp_factorsListModel->rowCount(); i++)
    {
      mp_factorsListModel->item(i, 0)->setCheckState(Qt::Unchecked);
      mp_factorsLabelModel->item(i, 0)->setCheckState(Qt::Unchecked);
      mp_factorsColorModel->item(i, 0)->setCheckState(Qt::Unchecked);
    }
  switch(tab_selected)
    {
      case(int)SdsAnalysisStep::analyzing_sc:
        ui->factors_color_widget->setVisible(true);
        ui->factors_label_widget->setVisible(true);
        ui->factors_list_widget->setVisible(true);
        break;
      case(int)SdsAnalysisStep::filtering_sc:
        ui->factors_color_widget->setVisible(false);
        ui->factors_label_widget->setVisible(false);
        ui->factors_list_widget->setVisible(true);
        break;
      case(int)SdsAnalysisStep::heatmap_abundance:
        ui->factors_color_widget->setVisible(true);
        ui->factors_label_widget->setVisible(false);
        ui->factors_list_widget->setVisible(true);
        break;
      case(int)SdsAnalysisStep::protein_clustering:
        ui->factors_color_widget->setVisible(false);
        ui->factors_label_widget->setVisible(false);
        ui->factors_list_widget->setVisible(true);
        break;
      case(int)SdsAnalysisStep::protein_anova:
        ui->factors_color_widget->setVisible(false);
        ui->factors_label_widget->setVisible(false);
        ui->factors_list_widget->setVisible(true);
        break;
      case(int)SdsAnalysisStep::protein_abundance:
        ui->factors_color_widget->setVisible(true);
        ui->factors_label_widget->setVisible(false);
        ui->factors_list_widget->setVisible(true);
        break;
      case(int)SdsAnalysisStep::protein_fc_abundance:
        ui->factors_color_widget->setVisible(false);
        ui->factors_label_widget->setVisible(false);
        ui->factors_list_widget->setVisible(false);
        break;
      default:
        ui->factors_color_widget->setVisible(false);
        ui->factors_label_widget->setVisible(false);
        ui->factors_list_widget->setVisible(false);
        break;
    }
}

void
McqrSdsWidget::initGrantleeEngine()
{
  mp_grantleeEngine = new Grantlee::Engine();
  auto loader = QSharedPointer<Grantlee::FileSystemTemplateLoader>::create();
  loader->setTemplateDirs({":/templates/resources/templates/mcqr_scripts"});
  mp_grantleeEngine->addTemplateLoader(loader);

  msp_rscriptTemplate = mp_grantleeEngine->loadByName("mcqr_sds_analysis.R");
  if(!msp_rscriptTemplate->errorString().isEmpty())
    {
      throw pappso::PappsoException(
        QObject::tr("An error happened during the template file loading :\n%1")
          .arg(msp_rscriptTemplate->errorString()));
    }
}

void
McqrSdsWidget::analyseQualityData()
{
  m_ongoingMcqrStep = SdsAnalysisStep::analyzing_sc;

  QStringList factors_color;
  QStringList factors_label;
  QStringList factors_list;
  for(int i = 0; i < mp_factorsColorModel->rowCount(); i++)
    {
      QStandardItem *color_item = mp_factorsColorModel->item(i, 0);
      if(color_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_color << color_item->text();
        }
      QStandardItem *label_item = mp_factorsLabelModel->item(i, 0);
      if(label_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_label << label_item->text();
        }
      QStandardItem *list_item = mp_factorsListModel->item(i, 0);
      if(list_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_list << list_item->text();
        }
    }

  if(factors_color.size() == 0 || factors_label.size() == 0 ||
     factors_list.size() == 0)
    {
      QMessageBox::warning(
        this,
        tr("Parameter selection error"),
        tr("You have to select at least one factor in the factor to color list "
           "and in the factor as label list"));
    }
  else
    {
      Grantlee::Context grantlee_context;
      grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
      grantlee_context.insert(
        "mcqr_load_data_mode",
        (std::int8_t)getMcqrExperimentSpLoaded().get()->getMcqrLoadDataMode());
      grantlee_context.insert(
        "mcqr_working_directory",
        QDir(getMcqrExperimentSpLoaded().get()->getMcqrWorkingDirectory())
          .path());
      grantlee_context.insert(
        "rdata_path", getMcqrExperimentSpLoaded().get()->getRdataFilePath());
      grantlee_context.insert("specific_peptides",
                              pappso::Utils::booleanToString(
                                ui->specific_peptide_switch->getSwitchValue()));
      grantlee_context.insert("tmp_path", getOutputTmpPath());
      qDebug() << " factors_color.join()=" << factors_color.join("\", \"");
      grantlee_context.insert("factors_color", factors_color.join("\", \""));
      qDebug() << " factors_label.join()=" << factors_label.join("\", \"");
      grantlee_context.insert("factors_label", factors_label.join("\", \""));
      qDebug() << " factors_list.join()=" << factors_list.join("\", \"");
      grantlee_context.insert("factors_list", factors_list.join("\", \""));


      getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
        "analyzing_sc", msp_rscriptTemplate->render(&grantlee_context));
    }
}

void
McqrSdsWidget::filteringData()
{
  m_ongoingMcqrStep = SdsAnalysisStep::filtering_sc;

  QStringList factors;
  for(int i = 0; i < mp_factorsListModel->rowCount(); i++)
    {
      QStandardItem *item = mp_factorsListModel->item(i, 0);
      if(item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors << item->text();
        }
    }

  QStringList msrun_outliers;
  for(int i = 0; i < mp_msrunRemoveModel->rowCount(); i++)
    {
      QStandardItem *item = mp_msrunRemoveModel->item(i, 0);
      if(item->checkState() == Qt::CheckState(Qt::Checked))
        {
          msrun_outliers << item->text();
        }
    }

  if(factors.size() == 0)
    {
      QMessageBox::warning(
        this,
        tr("Parameter selection error"),
        tr("You have to select at least one factor in the factor list "
           "to perform the foldchange cutoff"));
    }
  else
    {
      Grantlee::Context grantlee_context;
      grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
      grantlee_context.insert("msrun_to_remove", msrun_outliers.join("\", \""));
      grantlee_context.insert("prot_cutoff", ui->prot_cutoff_spinbox->value());
      grantlee_context.insert("foldchange_cutoff",
                              ui->fc_cutoff_spinbox->value());
      grantlee_context.insert("factors_list", factors.join("\", \""));

      getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
        "filtering_sc", msp_rscriptTemplate->render(&grantlee_context));
    }
}

void
McqrSdsWidget::plotProteinHeatmapAbundance()
{
  m_ongoingMcqrStep = SdsAnalysisStep::heatmap_abundance;

  QStringList factors_list;
  QStringList factors_color;
  for(int i = 0; i < mp_factorsListModel->rowCount(); i++)
    {
      QStandardItem *list_item = mp_factorsListModel->item(i, 0);
      if(list_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_list << list_item->text();
        }
      QStandardItem *color_item = mp_factorsColorModel->item(i, 0);
      if(color_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_color << color_item->text();
        }
    }

  if(factors_color.size() == 0 || factors_list.size() == 0)
    {
      QMessageBox::warning(
        this,
        tr("Parameter selection error"),
        tr("You have to select at least one factor in the factor to color list "
           "and in the factor as label list"));
    }
  else
    {
      bool colors_in_list = true;
      for(QString factor_color : factors_color)
        {
          if(!factors_list.contains(factor_color))
            {
              colors_in_list = false;
            }
        }
      if(colors_in_list)
        {
          Grantlee::Context grantlee_context;
          grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
          grantlee_context.insert("tmp_path", getOutputTmpPath());
          grantlee_context.insert("factors_list", factors_list.join("\", \""));
          grantlee_context.insert("factors_color",
                                  factors_color.join("\", \""));
          grantlee_context.insert("distance_fun",
                                  ui->distfun_combobox->currentText());
          grantlee_context.insert("agg_method",
                                  ui->agg_method_combobox->currentText());

          getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
            "heatmap_abundance",
            msp_rscriptTemplate->render(&grantlee_context));
        }
      else
        {
          QMessageBox::warning(this,
                               tr("Parameter selection error"),
                               tr("The factors to color selected must be "
                                  "selected in the factor list too."));
        }
    }
}

void
McqrSdsWidget::runProteinClustering()
{
  m_ongoingMcqrStep = SdsAnalysisStep::protein_clustering;

  QStringList factors_list;
  for(int i = 0; i < mp_factorsListModel->rowCount(); i++)
    {
      QStandardItem *list_item = mp_factorsListModel->item(i, 0);
      if(list_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_list << list_item->text();
        }
    }

  if(factors_list.size() == 0)
    {
      QMessageBox::warning(
        this,
        tr("Parameter selection error"),
        tr("You have to select at least one factor in the factor to color list "
           "and in the factor as label list"));
    }
  else
    {
      Grantlee::Context grantlee_context;
      grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
      grantlee_context.insert("tmp_path", getOutputTmpPath());
      grantlee_context.insert("factor_list", factors_list.join("\", \""));
      grantlee_context.insert("nb_cluster", ui->cluster_spin->value());

      getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
        "protein_clustering", msp_rscriptTemplate->render(&grantlee_context));
    }
}

void
McqrSdsWidget::runProteinAnova()
{
  m_ongoingMcqrStep = SdsAnalysisStep::protein_anova;

  QStringList factors_list;
  for(int i = 0; i < mp_factorsListModel->rowCount(); i++)
    {
      QStandardItem *list_item = mp_factorsListModel->item(i, 0);
      if(list_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_list << list_item->text();
        }
    }

  if(factors_list.size() == 0)
    {
      QMessageBox::warning(
        this,
        tr("Parameter selection error"),
        tr("You have to select at least one factor in the factor list"));
    }
  else
    {
      Grantlee::Context grantlee_context;
      grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
      grantlee_context.insert("tmp_path", getOutputTmpPath());
      grantlee_context.insert("factor_list", factors_list.join("\", \""));
      if(ui->interaction_switch->getSwitchValue())
        {
          grantlee_context.insert("interaction", "TRUE");
        }
      else
        {
          grantlee_context.insert("interaction", "FALSE");
        }

      getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
        "protein_anova", msp_rscriptTemplate->render(&grantlee_context));
    }
}

void
McqrSdsWidget::runProteinAbundance()
{
  m_ongoingMcqrStep = SdsAnalysisStep::protein_abundance;

  QStringList factors_list;
  QStringList factors_color;
  for(int i = 0; i < mp_factorsListModel->rowCount(); i++)
    {
      QStandardItem *list_item = mp_factorsListModel->item(i, 0);
      if(list_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_list << list_item->text();
        }
      QStandardItem *color_item = mp_factorsListModel->item(i, 0);
      if(color_item->checkState() == Qt::CheckState(Qt::Checked))
        {
          factors_color << color_item->text();
        }
    }

  if(factors_list.size() == 0 || factors_color.size() == 0)
    {
      QMessageBox::warning(this,
                           tr("Parameter selection error"),
                           tr("You have to select at least one factor in the "
                              "factor list and one factor as color"));
    }
  else
    {
      Grantlee::Context grantlee_context;
      grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
      grantlee_context.insert("tmp_path", getOutputTmpPath());
      grantlee_context.insert("factors_list", factors_list);
      grantlee_context.insert("factor_color", factors_color.join("\", \""));
      grantlee_context.insert("factors_list_join", factors_list.join("\", \""));
      if(ui->padjust_switch->getSwitchValue())
        {
          grantlee_context.insert("padjust", "TRUE");
        }
      else
        {
          grantlee_context.insert("padjust", "FALSE");
        }
      grantlee_context.insert("alpha", ui->alpha_spin->value());

      getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
        "protein_abundance", msp_rscriptTemplate->render(&grantlee_context));
    }
}

void
McqrSdsWidget::runProteinFcAbundance()
{
  m_ongoingMcqrStep = SdsAnalysisStep::protein_fc_abundance;

  Grantlee::Context grantlee_context;
  grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
  grantlee_context.insert("tmp_path", getOutputTmpPath());
  grantlee_context.insert("fc_factor", ui->factor_combobox->currentText());
  grantlee_context.insert("num", ui->numerator_combobox->currentText());
  grantlee_context.insert("denom", ui->denominator_combobox->currentText());

  getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
    "protein_fc_abundance", msp_rscriptTemplate->render(&grantlee_context));
}

void
McqrSdsWidget::saveFinalRData()
{
  m_ongoingMcqrStep = SdsAnalysisStep::last;


  QString file_name = QFileDialog::getSaveFileName(
    this,
    tr("Save RData results"),
    QFileInfo(getMcqrExperimentSpLoaded().get()->getRdataFilePath())
        .absoluteDir()
        .absolutePath() +
      "/untitled.RData",
    tr("RData (*.RData)"));

  Grantlee::Context grantlee_context;
  grantlee_context.insert("mcqr_step", (std::int8_t)m_ongoingMcqrStep);
  grantlee_context.insert("rdata_file", file_name);

  getMcqrRunParentView()->getRProcessRunning()->executeMcqrStep(
    "last", msp_rscriptTemplate->render(&grantlee_context));
}

void
McqrSdsWidget::fillFactorsInComboboxForFC()
{
  for(QString factor : getMcqrExperimentSpLoaded().get()->getmetadataColumns())
    {
      ui->factor_combobox->addItem(factor);
    }
}

void
McqrSdsWidget::changeStepAfterEndTag(QString end_name)
{
  if(end_name == "MCQREnd: analyzing_sc")
    {
      configureFilteringProteinTab();
    }
  else if(end_name == "MCQREnd: filtering")
    {
      ui->toolBox->setItemEnabled(2, true);
      ui->toolBox->setCurrentIndex(2);
      ui->toolBox->update();
    }
  else if(end_name == "MCQREnd: heatmap_abundance")
    {
      ui->toolBox->setItemEnabled(3, true);
      ui->toolBox->setCurrentIndex(3);
      ui->toolBox->update();
    }
  else if(end_name == "MCQREnd: protein_clustering")
    {
      ui->toolBox->setItemEnabled(4, true);
      ui->toolBox->setCurrentIndex(4);
      ui->toolBox->update();
    }
  else if(end_name == "MCQREnd: protein_anova")
    {
      ui->padjust_switch->setSwitchValue(true);
      ui->toolBox->setItemEnabled(5, true);
      ui->toolBox->setCurrentIndex(5);
      ui->toolBox->update();
    }
  else if(end_name == "MCQREnd: protein_abundance")
    {
      fillFactorsInComboboxForFC();
      ui->toolBox->setItemEnabled(6, true);
      ui->toolBox->setCurrentIndex(6);
      ui->toolBox->update();
    }
  else if(end_name == "MCQREnd: protein_fc_abundance")
    {
      ui->toolBox->setItemEnabled(7, true);
      ui->toolBox->setCurrentIndex(7);
      ui->toolBox->update();
    }
}

void
McqrSdsWidget::configureFilteringProteinTab()
{
  int i = 0;
  for(McqrMetadata *metadata :
      getMcqrExperimentSpLoaded().get()->getmetadataInfoVector())
    {
      QStandardItem *new_item = new QStandardItem(metadata->m_msrunId);
      new_item->setCheckable(true);
      new_item->setData(Qt::Unchecked, Qt::CheckStateRole);
      mp_msrunRemoveModel->setItem(i, new_item);
      i++;
    }
  ui->msrun_list_view->setModel(mp_msrunRemoveModel);
  ui->toolBox->setItemEnabled(1, true);
  ui->toolBox->setCurrentIndex(1);
  ui->toolBox->update();
}

void
McqrSdsWidget::doFactorComboboxChanged(QString factor)
{
  ui->numerator_combobox->clear();
  ui->denominator_combobox->clear();
  QStringList factors_list;
  for(McqrMetadata *metadata :
      getMcqrExperimentSpLoaded().get()->getmetadataInfoVector())
    {
      if(!factors_list.contains(metadata->m_otherData[factor].toString()))
        {
          factors_list << metadata->m_otherData[factor].toString();
        }
    }
  for(QString factor_value : factors_list)
    {
      ui->denominator_combobox->addItem(factor_value);
      ui->numerator_combobox->addItem(factor_value);
    }
}

void
McqrSdsWidget::writeMcqrResultInRightFile(QString mcqr_result)
{
  switch(m_ongoingMcqrStep)
    {
      case SdsAnalysisStep::analyzing_sc:
        m_analysingScResult = mcqr_result;
        break;
      case SdsAnalysisStep::filtering_sc:
        m_filteringResult = mcqr_result;
        break;
        //       case SdsAnalysisStep::protein_abundance_sc:
        //         m_proteinAbundanceResult = mcqr_result;
        //         break;
      default:
        break;
    }
}
