/* 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
 */


/////////////////////// StdLib includes
#include <cmath>
#include <algorithm>
#include <limits> // for std::numeric_limits


/////////////////////// Qt includes
#include <QtGui>
#include <QFileDialog>

/////////////////////// pappsomspp includes
#include <pappsomspp/core/massspectrum/massspectrum.h>
#include <pappsomspp/core/processing/combiners/massspectrumpluscombiner.h>
#include <pappsomspp/core/processing/combiners/tracepluscombiner.h>
#include <pappsomspp/core/trace/trace.h>
#include <pappsomspp/core/processing/filters/filternormalizeintensities.h>

/////////////////////// Local includes
#include "MsXpS/libXpertMassCore/globals.hpp"
#include "MsXpS/libXpertMassCore/Utils.hpp"
#include "MsXpS/libXpertMassCore/MassPeakShaperConfig.hpp"
#include "MsXpS/libXpertMassCore/MassDataCborMassSpectrumHandler.hpp"

#include "MsXpS/libXpertMassGui/MassPeakShaperConfigDlg.hpp"

#include "ui_MassPeakShaperConfigDlg.h"

namespace MsXpS
{

namespace libXpertMassGui
{


/*!
\class MsXpS::libXpertMassGui::MassPeakShaperConfigDlg
\inmodule libXpertMassGui
\ingroup XpertMassGuiMassCalculations
\inheaderfile MassPeakShaperConfigDlg.hpp

\brief The MassPeakShaperConfigDlg class provides a graphical user interface
for the configuration of the mass peak shaping process.

The dialog window contains all the widgets required to fully configure the mass
peak shaping process.
*/

/*!
\variable MsXpS::libXpertMassGui::MassPeakShaperConfigDlg::mp_ui

\brief The graphical user interface definition.
*/

/*!
\variable \
MsXpS::libXpertMassGui::MassPeakShaperConfigDlg::mp_massPeakShaperConfigWidget

\brief The widget holding the configuration of the mass peak shaping procedure.
*/

/*!
\variable MsXpS::libXpertMassGui::MassPeakShaperConfigDlg::mp_parent

\brief The parent widget.
*/

/*!
\variable MsXpS::libXpertMassGui::MassPeakShaperConfigDlg::m_applicationName

\brief The name of the application.
*/

/*!
\variable MsXpS::libXpertMassGui::MassPeakShaperConfigDlg::m_config

\brief The \l{libXpertMassCore::MassPeakShaperConfig} configuration for the mass
peak shaping process.
*/


/*!
\brief Constructs a MassPeakShaperConfigDlg instance.

\list
\li \a parent_p: the parent widget.
\li \a applicationName: the name of the application, typically massXpert2 or
mineXpert2, for example.
\li \a description: the string describing what this dialog window is for (used
for the window title).
\endlist
*/
MassPeakShaperConfigDlg::MassPeakShaperConfigDlg(QWidget *parent_p,
                                                 const QString &applicationName,
                                                 const QString &description)
  : QDialog(static_cast<QWidget *>(parent_p)),
    mp_ui(new Ui::MassPeakShaperConfigDlg),
    mp_parent(parent_p),
    m_applicationName{applicationName}
{
  if(!parent_p)
    qFatal("Programming error. Program aborted.");

  mp_ui->setupUi(this);

  // Update the window title because the window title element in m_ui might be
  // either erroneous or empty.
  setWindowTitle(QString("%1 - %2").arg(applicationName).arg(description));

  setupDialog();
}

/*!
\fn MassPeakShaperConfigDlg::closeEvent([[maybe_unused]] QCloseEvent *event)
Upon closing of the dialog window writes the settings of the dialog
windows (\a event is unused).

\sa writeSettings()
*/
void
MassPeakShaperConfigDlg::closeEvent([[maybe_unused]] QCloseEvent *event)
{
  // qDebug();
  writeSettings(
    MsXpS::libXpertMassCore::Utils::configSettingsFilePath);
}

/*!
\brief Destructs this MassPeakShaperConfigDlg instance.
*/
MassPeakShaperConfigDlg::~MassPeakShaperConfigDlg()
{
  // qDebug();

  writeSettings(
    MsXpS::libXpertMassCore::Utils::configSettingsFilePath);
}

/*!
\brief Writes the settings of the dialog window to \a config_settings_file_path
for later restoration.
*/
void
MassPeakShaperConfigDlg::writeSettings(const QString &config_settings_file_path)
{
  // qDebug();

  // First save the config widget state.
  mp_massPeakShaperConfigWidget->writeSettings(config_settings_file_path);

  QSettings settings(config_settings_file_path, QSettings::IniFormat);

  settings.beginGroup("MassPeakShaperConfigDlg");

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

  settings.endGroup();
}

/*!
\brief Reads the settings of this dialog window from \a
config_settings_file_path.
*/
void
MassPeakShaperConfigDlg::readSettings(const QString &config_settings_file_path)
{
  // qDebug();

  // First read the config widget state.
  mp_massPeakShaperConfigWidget->readSettings(config_settings_file_path);

  QSettings settings(config_settings_file_path, QSettings::IniFormat);

  settings.beginGroup("MassPeakShaperConfigDlg");

  restoreGeometry(settings.value("geometry").toByteArray());

  settings.endGroup();
}

/*!
\brief Sets up this dialog window.
*/
void
MassPeakShaperConfigDlg::setupDialog()
{

  // We want to destroy the dialog when it is closed.
  // setAttribute(Qt::WA_DeleteOnClose);

  // Setup the peak shaper configuration widget inside of the frame

  QVBoxLayout *v_box_layout_p = new QVBoxLayout(this);

  // Trasmit the config member object reference so that it can be modified by
  // the configuration widget.
  mp_massPeakShaperConfigWidget =
    new MassPeakShaperConfigWidget(m_config, this);

  v_box_layout_p->addWidget(mp_massPeakShaperConfigWidget);

  mp_ui->peakShaperConfigFrame->setLayout(v_box_layout_p);

  connect(mp_massPeakShaperConfigWidget,
          &MassPeakShaperConfigWidget::updatedMassPeakShaperConfigSignal,
          [this](const libXpertMassCore::MassPeakShaperConfig &config) {
            m_config.initialize(config);
            qDebug().noquote() << "Now got the config:" << m_config.toString();
            //  Relay the config to the user of this dialog window.
            emit updatedMassPeakShaperConfigSignal(m_config);
          });

  // The values above are actually set in readSettings (with default values if
  // missing in the config settings.)
  readSettings(
    MsXpS::libXpertMassCore::Utils::configSettingsFilePath);
}

void
MassPeakShaperConfigDlg::setParameters(
  double reference_peak_mz,
  int point_count,
  libXpertMassCore::Enums::MassPeakShapeType mass_peak_shape_type,
  double resolution,
  double fwhm,
  int bin_size_divisor,
  bool should_create_bins)
{
  return mp_massPeakShaperConfigWidget->setParameters(reference_peak_mz,
                                                      point_count,
                                                      mass_peak_shape_type,
                                                      resolution,
                                                      fwhm,
                                                      bin_size_divisor,
                                                      should_create_bins);
}

MassPeakShaperConfigWidget *
MassPeakShaperConfigDlg::getConfigWidget()
{
  return mp_massPeakShaperConfigWidget;
}

void
MassPeakShaperConfigDlg::registerJsConstructor(QJSEngine *engine)

{
  if(!engine)
    {
      qDebug()
        << "Cannot register MassPeakShaperConfigDlg class: engine is null";
      return;
    }

  // Register the meta object as a constructor

  QJSValue jsMetaObject =
    engine->newQMetaObject(&MassPeakShaperConfigDlg::staticMetaObject);
  engine->globalObject().setProperty("MassPeakShaperConfigDlg", jsMetaObject);
}


} // namespace libXpertMassGui

} // namespace MsXpS
