/**
 * \file gui/mcqr_run_view/mcqrrunview.cpp
 * \date 30/04/2021
 * \author Thomas Renne
 * \brief widget to run 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 "mcqrrunview.h"
#include "ui_mcqr_run_view.h"

#include <pappsomspp/pappsoexception.h>
#include <QFile>
#include <QPrinter>
// #include <QPageSize>
#include <QFileInfo>
#include <QDir>
#include <QScrollBar>
#include <QFileDialog>
#include <QMessageBox>

#include "../../utils/utils.h"
#include "mcqr_sds_widget/mcqrsdswidget.h"
#include "mcqr_sds_xic_widget/mcqrsdsxicwidget.h"
#include "../mainwindow.h"


McqrRunView::McqrRunView(MainWindow *parent,
                         const McqrExperimentSp &p_mcqr_experiment)
  : QWidget(), ui(new Ui::McqrRunView)
{
  ui->setupUi(this);
  msp_mcqrExperiment = p_mcqr_experiment;
  setWindowTitle("MCQR run window");
  mp_main = parent;
  // Create the output page
  mp_documentText = new QTextDocument();
  ui->mcqr_result_browser->setDocument(mp_documentText);
  loadSpecificMcqrParameterWidget();

  // Set the Loading icon
  mp_loadingIcon = new QMovie(":icons/resources/icons/icon_wait.gif");
  ui->spining_label->setMovie(mp_loadingIcon);
  ui->spining_label->setVisible(false);
  mp_loadingIcon->setScaledSize(QSize(20, 20));
  mp_loadingIcon->start();


  // Create R Process and begin MCQR
  mp_rProcess = new McqrQProcess();
  mp_rProcess->startRprocess();
  checkLibrariesInstalled();

  connect(mp_rProcess,
          &QProcess::readyReadStandardOutput,
          this,
          &McqrRunView::updateMcqrResultsBrowser);
  connect(mp_rProcess,
          &QProcess::readyReadStandardError,
          this,
          &McqrRunView::handleMcqrMessages);
  connect(this,
          &McqrRunView::saveRscriptAndRdata,
          this,
          &McqrRunView::saveRunRscript);
  connect(this,
          &McqrRunView::closeMcqrRunView,
          mp_main,
          &MainWindow::doCloseMcqrRunView);
}

McqrRunView::~McqrRunView()
{
  qDebug() << "Close MCQR";
  mp_rProcess->stopRprocess();
  delete mp_mcqrParam;
  delete mp_loadingIcon;
  delete mp_documentText;
  delete mp_rProcess;
  qDebug() << "R process closed";
}

void
McqrRunView::closeEvent(QCloseEvent *event)
{
  qDebug() << "Close MCQR window";
  emit closeMcqrRunView();
  event->accept();
}

void
McqrRunView::checkLibrariesInstalled()
{
  Grantlee::Engine *engine_p = new Grantlee::Engine();
  auto loader = QSharedPointer<Grantlee::FileSystemTemplateLoader>::create();
  loader->setTemplateDirs({":/templates/resources/templates/mcqr_scripts"});
  engine_p->addTemplateLoader(loader);
  Grantlee::Template rscript_template_sp =
    engine_p->loadByName("mcqr_packages_handler.R");
  Grantlee::Context empty_context;
  mp_rProcess->executeOnTheRecord(rscript_template_sp->render(&empty_context));
}

void
McqrRunView::loadSpecificMcqrParameterWidget()
{
  if(msp_mcqrExperiment.get()->getMcqrExperimentType() ==
     McqrExperimentType::xic)
    {
      mp_mcqrParam = new McqrSdsXicWidget(this, msp_mcqrExperiment);
    }
  else
    {
      mp_mcqrParam = new McqrSdsWidget(this, msp_mcqrExperiment);
    }
  ui->mcqr_param_layout->addWidget(mp_mcqrParam);
}

McqrQProcess *
McqrRunView::getRProcessRunning()
{
  qDebug() << "mp_rProcess->state()=" << mp_rProcess->state();

  if(mp_rProcess->state() == QProcess::NotRunning)
    {
      mp_rProcess->startRprocess();
    }
  return mp_rProcess;
}

void
McqrRunView::updateMcqrResultsBrowser()
{
  QString mcqr_process_results = mp_rProcess->readAllStandardOutput();
  mcqr_process_results         = mcqr_process_results.trimmed();
  Utils::transformPlainNewLineToHtmlFormat(mcqr_process_results);

  m_documentString.append(mcqr_process_results);
  // QString content = mp_documentText->toHtml() + mcqr_process_results;
  qDebug() << "mcqr_process_results=" << mcqr_process_results;

  qDebug() << "m_documentString=" << m_documentString;
  mp_documentText->setHtml(
    QString("<html><head><link rel='stylesheet' type='text/css' "
            "href=':/style/resources/templates/mcqr_stylesheet.css'></"
            "head><body>%1</body></html>")
      .arg(m_documentString));

  QTextCursor textCursor = ui->mcqr_result_browser->textCursor();
  textCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor, 1);
  ui->mcqr_result_browser->setTextCursor(textCursor);

  // ui->mcqr_result_browser->update();
}


void
McqrRunView::handleMcqrMessages()
{
  QString mcqr_message = mp_rProcess->readAllStandardError();
  mcqr_message         = mcqr_message.trimmed();
  qDebug() << mcqr_message;
  QStringList mcqr_messages = mcqr_message.split(QChar::LineSeparator);
  for(QString message : mcqr_messages)
    {
      message = message.trimmed();
      Utils::transformPlainNewLineToHtmlFormat(message);
      QRegExp mcqr_info_regex("^MCQRInfo: (.*)");
      QRegExp mcqr_begin_regex("^MCQRBegin: (.*)");
      QRegExp mcqr_end_regex("^MCQREnd: (.*)");
      QRegExp mcqr_error_regex("^Err(eu|o)r (in|:) (.*)");

      if(mcqr_info_regex.exactMatch(
           message)) // Manually added message to MCQR execution
        {
          ui->mcqr_log_browser->append(message);
        }
      else if(mcqr_begin_regex.exactMatch(
                message)) // MCQR message at the file begining
        {
          ui->spining_label->setVisible(true);
        }
      else if(mcqr_end_regex.exactMatch(
                message)) // MCQR message at the end of an execution
        {
          ui->spining_label->setVisible(false);
          mp_mcqrParam->changeStepAfterEndTag(message);
        }
      else if(mcqr_error_regex.exactMatch(message))
        {
          ui->spining_label->setVisible(false);
          handleMcqrErrors(mcqr_message);
          /*
                    if(mp_rProcess->state() == QProcess::NotRunning)
                      {
                        startRProcess();
                      }
                      */
        }
      else // Other messages
        {
          ui->mcqr_log_browser->append("<p style=\"color:darkred;\">" +
                                       message + "</p>");
        }
    }
}

void
McqrRunView::handleMcqrErrors(QString error_message)
{
  QMessageBox message_box;
  message_box.setIcon(QMessageBox::Critical);
  message_box.setWindowTitle(tr("MCQR error"));
  message_box.setText(
    tr("MCQR has been stopped due to an error!!\n%1").arg(error_message));
  message_box.setInformativeText(
    tr("Do you want to download the RScript and the RData"));
  message_box.setStandardButtons(QMessageBox::SaveAll | QMessageBox::Close);
  int btn_clicked = message_box.exec();
  switch(btn_clicked)
    {
      case QMessageBox::SaveAll:
        emit saveRscriptAndRdata();
        break;
      case QMessageBox::Close:
        // emit closeMcqrRunView();
        break;
    }
}

void
McqrRunView::printToPdf()
{
  QString filename = QFileDialog::getSaveFileName(
    this, tr("Save Mcqr result File"), "~/untitled.pdf", tr("PDF (*.pdf)"));
  qDebug() << "Begin PDF printing";
  QPrinter printer(QPrinter::PrinterResolution);
  printer.setOutputFormat(QPrinter::PdfFormat);
  // printer.setPageSize(QPageSize(QPageSize::A4));
  printer.setOutputFileName(filename);
  mp_documentText->print(&printer);
  qDebug() << "PDF printing finished";
}

void
McqrRunView::saveRunRscript()
{
  QString filename = QFileDialog::getSaveFileName(
    this, tr("Save Mcqr script run"), "~/untitled.R", tr("R Script (*.R)"));
  QFile qFile(filename);
  if(qFile.open(QIODevice::WriteOnly))
    {
      QTextStream out(&qFile);
      out << *(mp_rProcess->getRScriptRun().string());
      qFile.close();
    }
}

void
McqrRunView::saveRData()
{
  QString file_name = QFileDialog::getSaveFileName(
    this, tr("Save RData file"), "~/untitled.RData", tr("RData (*.Rdata)"));

  mp_mcqrParam->saveModifiedRData(file_name);
}
