/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright (C) 2009--2020 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the msXpertSuite project.
 *
 * The msXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * This program 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.
 *
 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


/////////////////////// Qt includes
#include <QObject>
#include <QDebug>
#include <QWidget>
#include <QMessageBox>
#include <QSettings>
#include <QLineEdit>


/////////////////////// Local includes
#include "../nongui/globals.hpp"
#include "XicExtractionWnd.hpp"
#include "ProgramWindow.hpp"
#include "Application.hpp"


namespace msxps
{
namespace minexpert
{


XicExtractionWnd::XicExtractionWnd(ProgramWindow *program_window_p,
                                   const QString &title,
                                   const QString &settings_title)
  : QMainWindow(dynamic_cast<QWidget *>(program_window_p)),
    mp_programWindow(program_window_p),
    m_title(title),
    m_settingsTitle(settings_title)
{
  // qDebug();

  if(program_window_p == nullptr)
    qFatal("Pointer cannot be nullptr.");

  m_ui.setupUi(this);

  initialize();
}


XicExtractionWnd::~XicExtractionWnd()
{
  writeSettings();
}


void
XicExtractionWnd::initialize()
{
  // The precision widget required to specify the precursor m/z values
  // search tolerance.
  mp_precisionWidget = new pappso::PrecisionWidget(this);
  m_ui.precisionWidgetHorizontalLayout->addWidget(mp_precisionWidget);
  mp_precisionWidget->setToolTip(
    "Set the tolerance with which the m/z value match is performed.");

  connect(mp_precisionWidget,
          &pappso::PrecisionWidget::precisionChanged,
          [this](pappso::PrecisionPtr precision_p) {
            qDebug();
            mp_precision = precision_p;
          });

  connect(m_ui.runPushButton, &QPushButton::clicked, [this]() {
    runPushButtonClicked();
  });

  connect(m_ui.abortPushButton,
          &QPushButton::clicked,
          this,
          &XicExtractionWnd::abortPushButtonClicked);

  connect(m_ui.closePushButton,
          &QPushButton::clicked,
          this,
          &XicExtractionWnd::closePushButtonClicked);
}


void
XicExtractionWnd::readSettings()
{
  QSettings settings(static_cast<Application *>(QCoreApplication::instance())
                       ->getUserConfigSettingsFilePath(),
                     QSettings::IniFormat);
  settings.beginGroup("XicExtractionWnd");

  // Also restore the geometry of the window.
  restoreGeometry(settings.value("geometry").toByteArray());

  bool wasVisible = settings.value("visible").toBool();
  setVisible(wasVisible);

  settings.endGroup();
}


void
XicExtractionWnd::writeSettings()
{
  QSettings settings(static_cast<Application *>(QCoreApplication::instance())
                       ->getUserConfigSettingsFilePath(),
                     QSettings::IniFormat);
  settings.beginGroup("XicExtractionWnd");

  settings.setValue("geometry", saveGeometry());

  settings.setValue("visible", isVisible());

  settings.endGroup();
}


void
XicExtractionWnd::runPushButtonClicked()
{
  bool ok   = false;
  double mz = m_ui.mzValueLineEdit->text().toDouble(&ok);
  if(!ok)
    {
      statusBar()->showMessage("Please enter a valid m/z value and try again",
                               2000);

      return;
    }

  double delta = mp_precision->delta(mz);

  double mz_start = mz - delta;
  double mz_end   = mz + delta;

  // At this point, get the list of all the mass data files that have their
  // item selected in the OpenSpectraDlg window.

  std::vector<MsRunDataSetCstSPtr> vector_of_ms_run_data_set_csp =
    mp_programWindow->allSelectedOrUniqueMsRunDataSet();

  if(!vector_of_ms_run_data_set_csp.size())
    {
      QMessageBox::information(this,
                               "XIC chromatogram extraction",
                               "Please select at least one MS run data set as "
                               "described in the instructions text above.");

      return;
    }

  // Craft a 2D selection polygon that will be used to specify the RT and MZ
  // ranges.

  pappso::SelectionPolygon selection_polygon;

  for(auto &&ms_run_data_set_csp : vector_of_ms_run_data_set_csp)
    {
      ProcessingFlow processing_flow(ms_run_data_set_csp);

      ProcessingStep *processing_step_p = new ProcessingStep();

      processing_step_p->setSrcProcessingType(pappso::Axis::x, "RT");
      processing_step_p->setSrcProcessingType(pappso::Axis::y, "DATA_XIC_MZ");

      processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::rt);
      processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::mz);

      double rt_start = ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr()
                          ->getRootNodes()
                          .front()
                          ->getQualifiedMassSpectrum()
                          ->getRtInMinutes();
      double rt_end = ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr()
                        ->getRootNodes()
                        .back()
                        ->getQualifiedMassSpectrum()
                        ->getRtInMinutes();

      // Craft the selection polygon as a 2D rectangle with x:RT and y:MZ.
      selection_polygon.set2D(QPointF(rt_start, mz_end),
                              QPointF(rt_end, mz_end),
                              QPointF(rt_end, mz_start),
                              QPointF(rt_start, mz_start));

      processing_step_p->setDestProcessingType("RT");

      processing_step_p->setSelectionPolygon(selection_polygon);

      processing_flow.push_back(processing_step_p);

      mp_programWindow->integrateToRt(nullptr, nullptr, processing_flow);
    }

  return;
}


void
XicExtractionWnd::closePushButtonClicked()
{
  QMainWindow::close();
}


void
XicExtractionWnd::abortPushButtonClicked()
{
  qDebug() << "emit cancelOperationSignal();";
  emit cancelOperationSignal();
}

void
XicExtractionWnd::showWindow()
{
  activateWindow();
  raise();
  show();
}


} // namespace minexpert

} // namespace msxps
