/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2019 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


/////////////////////// Qt includes
#include <QDebug>
#include <QMainWindow>


/////////////////////// pappsomspp includes


/////////////////////// Local includes
#include "ProgramWindow.hpp"
#include "MassSpecTracePlotWnd.hpp"
#include "MassSpecTracePlotCompositeWidget.hpp"
#include "ColorSelector.hpp"
#include "../nongui/MassDataIntegratorTask.hpp"
#include "TaskMonitorCompositeWidget.hpp"
#include "TaskMonitorWnd.hpp"


namespace msxps
{
namespace minexpert
{


//! Construct an MassSpecTracePlotWnd instance.
MassSpecTracePlotWnd::MassSpecTracePlotWnd(QWidget *parent,
                                           const QString &title,
                                           const QString &description)
  : BaseTracePlotWnd(parent, title, description)
{
  extendMainMenu();
}


//! Destruct \c this MassSpecTracePlotWnd instance.
MassSpecTracePlotWnd::~MassSpecTracePlotWnd()
{
}


void
MassSpecTracePlotWnd::extendMainMenu()
{
  // Extend the tool bar menu with some mass spec-specific submenus.

  if(mp_mainMenu == nullptr)
    qFatal("Programming error.");

  // The toolbar menu button

  // The main menu in the form of a button with an icon like thoses found for
  // the menus in mobile phone applications.

  mp_deconvolutionsMenu = new QMenu("Deconvolutions");

  if(mp_beforePlotWidgetManagementSeparatorAction == nullptr)
    qFatal("Programming error.");

  QAction *menu_action_p = mp_mainMenu->insertMenu(
    mp_beforePlotWidgetManagementSeparatorAction, mp_deconvolutionsMenu);

  if(menu_action_p == nullptr)
    qFatal("Programming error.");


  QAction *mp_setMinimalChargeFractionalPartAction = new QAction(
    "Set charge minimal fractional part for all pinned-down widgets",
    dynamic_cast<QObject *>(this));
  mp_setMinimalChargeFractionalPartAction->setStatusTip(
    "Set the charge minimal fractional part for all pinned-down widget "
    "(typically 0.99)");

  connect(
    mp_setMinimalChargeFractionalPartAction, &QAction::triggered, [this]() {
      bool ok = false;

      double charge_minimal_fractional_part = QInputDialog::getDouble(
        this,
        "Set the charge minimal fractional part",
        "Charge (z) minimal fractional part (typically 0.99)",
        m_minimalFractionalPart,
        0.5,
        0.9999,
        4,
        &ok);

      if(ok)
        {
          m_minimalFractionalPart = charge_minimal_fractional_part;

          setMinimalChargeFractionalPartPinnedDownWidgets(
            m_minimalFractionalPart);
        }
    });

  mp_deconvolutionsMenu->addAction(mp_setMinimalChargeFractionalPartAction);

  QAction *mp_setMassPeakSpanAction = new QAction(
    "Set the span between two mass peaks", dynamic_cast<QObject *>(this));
  mp_setMassPeakSpanAction->setStatusTip(
    "Set the span between two peaks of a charge state envelope (typically 1 or "
    "2)");

  connect(mp_setMassPeakSpanAction, &QAction::triggered, [this]() {
    bool ok = false;

    double peak_span = QInputDialog::getInt(
      this,
      "Set the span between two peaks of a charge state envelope",
      "Span between two peaks (typically 1 or 2)",
      m_massPeakSpan,
      1,
      20,
      1,
      &ok);

    if(ok)
      {

        m_massPeakSpan = peak_span;

        setChargeStateEnvelopePeakSpanPinnedDownWidgets(m_massPeakSpan);
      }
  });

  mp_deconvolutionsMenu->addAction(mp_setMassPeakSpanAction);

  mp_mainMenu->addSeparator();
}


QCPGraph *
MassSpecTracePlotWnd::addTracePlot(
  const pappso::Trace &trace,
  [[maybe_unused]] MsRunDataSetCstSPtr ms_run_data_set_csp,
  const ProcessingFlow &processing_flow,
  const QColor &color,
  QCPAbstractPlottable *parent_plottable_p)
{
  // Allocate a mass spectrum-specific composite plot widget.

  MassSpecTracePlotCompositeWidget *composite_widget_p =
    new MassSpecTracePlotCompositeWidget(this, "m/z", "counts (a.u.)");

  return finalNewTracePlotConfiguration(
    composite_widget_p, trace, processing_flow, color, parent_plottable_p);
}


#if 0

        // Old version deemed to be removed.
        void
            MassSpecTracePlotWnd::integrateToMz(QCPAbstractPlottable *parent_plottable_p,
                    const ProcessingFlow &processing_flow)
            {

                // qDebug().noquote() << "Integrating to mz with processing flow:"
                //<< processing_flow.toString();

#if 0
                // NO BINNING
                pappso::MzIntegrationParams mz_integration_params(
                        std::numeric_limits<double>::max(), // smallest m/z
                        std::numeric_limits<double>::min(), // greatest m/z
                        pappso::BinningType::NONE,
                        -1, // decimal_places
                        pappso::PrecisionFactory::getDaltonInstance(0.05),
                        false, // apply_mz_shift
                        0.0,   // mz_shift
                        true); // remove_zero_val_data_points
#endif
#if 0
                // ARBITRARY BINNING
                pappso::MzIntegrationParams mz_integration_params(
                        std::numeric_limits<double>::max(),
                        std::numeric_limits<double>::min(),
                        pappso::BinningType::ARBITRARY,
                        -1,
                        // pappso::PrecisionFactory::getDaltonInstance(0.05),
                        pappso::PrecisionFactory::getDaltonInstance(0.1),
                        false,
                        0.0,
                        true);
#endif

                // Get the ms run data set that for the graph we are going to base the
                // integration on.
                MsRunDataSetCstSPtr ms_run_data_set_csp =
                    processing_flow.getMsRunDataSetCstSPtr();
                if(ms_run_data_set_csp == nullptr)
                    qFatal("Cannot be that the pointer is nullptr.");

                // What integration parameters are we going to use ? Since we do integrate to
                // a mass spectrum it is compulsory that the most recent step has valid mz
                // integration params.

                // Set aside an object for later use.
                const pappso::MzIntegrationParams *mz_integration_params_p =
                    processing_flow.mostRecentStep()->getMzIntegrationParamsPtr();

                if(mz_integration_params_p == nullptr || !mz_integration_params_p->isValid())
                    qFatal(
                            "Programming error. Cannot be that integration to m/z has no valid mz "
                            "integration parameters set.");

                // Allocate a mass data integrator to integrate the data.

                // Pass the integrator the flow we got as param and that describes in its most
                // recent step the integration that it should perform.
                MsRunDataSetTreeMassDataIntegratorToMz *mass_data_integrator_p =
                    new MsRunDataSetTreeMassDataIntegratorToMz(ms_run_data_set_csp,
                            processing_flow);

                // Ensure the mass data integrator messages are used.

                connect(mass_data_integrator_p,
                        &MassDataIntegrator::logTextToConsoleSignal,
                        mp_programWindow,
                        &ProgramWindow::logTextToConsole);

                // qDebug() << "the integrator pointer:" << mass_data_integrator_p;

                MassDataIntegratorTask *mass_data_integrator_task_p =
                    new MassDataIntegratorTask();

                // This signal starts the computation in the MassDataIntegratorTask object.
                connect(this,

                        static_cast<void (MassSpecTracePlotWnd::*)(
                            MsRunDataSetTreeMassDataIntegratorToMz *)>(
                                &MassSpecTracePlotWnd::integrateToMzSignal),

                        mass_data_integrator_task_p,

                        static_cast<void (MassDataIntegratorTask::*)(
                            MsRunDataSetTreeMassDataIntegratorToMz *)>(
                                &MassDataIntegratorTask::integrateToMz),

                        // Fundamental for signals that travel across QThread instances...
                        Qt::QueuedConnection);

                // Allocate the thread in which the integrator task will run.
                QThread *thread_p = new QThread;

                // Move the task to the matching thread.
                mass_data_integrator_task_p->moveToThread(thread_p);
                thread_p->start();

                // When the read task finishes, it sends a signal that we trap to go on with
                // the plot widget creation stuff.

                // Since we allocated the QThread dynamically we need to be able to destroy it
                // later, so make the connection.

                connect(mass_data_integrator_task_p,

                        static_cast<void (MassDataIntegratorTask::*)(MassDataIntegrator *)>(
                            &MassDataIntegratorTask::finishedIntegratingDataSignal),
                        this,
                        [this,
                        thread_p,
                        mass_data_integrator_p,
                        parent_plottable_p,
                        mass_data_integrator_task_p]() {
                        // Do not forget that we have to delete the MassDataIntegratorTask
                        // allocated instance.
                        mass_data_integrator_task_p->deleteLater();
                        // Once the task has been labelled to be deleted later, we can stop
                        // the thread and ask for it to also be deleted later.
                        thread_p->deleteLater(), thread_p->quit();
                        thread_p->wait();
                        this->finishedIntegratingToMz(mass_data_integrator_p,
                                parent_plottable_p);
                        });


                // Allocate a new TaskMonitorCompositeWidget that will receive all the
                // integrator's signals and provide feedback to the user about the ongoing
                // integration.

                TaskMonitorCompositeWidget *task_monitor_composite_widget_p =
                    mp_programWindow->getTaskMonitorWnd()->addTaskMonitorWidget(Qt::red);

                // Initialize the monitor composite widget's widgets and make all the
                // connections mass data integrator <--> widget.

                task_monitor_composite_widget_p->setMsRunIdText(
                        ms_run_data_set_csp->getMsRunId()->getSampleName());
                task_monitor_composite_widget_p->setTaskDescriptionText(
                        "Integrating to mass spectrum");
                task_monitor_composite_widget_p->setProgressBarMinValue(0);

                // Make the connections

                // When the integrator task instance has finished working, it will send a
                // signal that we trap to finally destroy (after a time lag of some seconds,
                // the monitor widget.

                connect(mass_data_integrator_task_p,

                        static_cast<void (MassDataIntegratorTask::*)(MassDataIntegrator *)>(
                            &MassDataIntegratorTask::finishedIntegratingDataSignal),

                        task_monitor_composite_widget_p,

                        &TaskMonitorCompositeWidget::taskFinished,

                        Qt::QueuedConnection);


                // If the user clicks the cancel button, relay the signal to the loader.
                connect(task_monitor_composite_widget_p,
                        &TaskMonitorCompositeWidget::cancelTaskSignal,
                        mass_data_integrator_p,
                        &MassDataIntegrator::cancelOperation);

                // We need to register the meta type for std::size_t because otherwise it
                // cannot be shipped though signals.

                qRegisterMetaType<std::size_t>("std::size_t");

                // Now make all the connections that will allow the integrator to provide
                // dynamic feedback to the user via the task monitor widget.
                task_monitor_composite_widget_p->makeMassDataIntegratorConnections(
                        mass_data_integrator_p);

                // qDebug() << "Going to emit integrateToMzSignal with mass data integrator:"
                //<< mass_data_integrator_p;

                emit integrateToMzSignal(mass_data_integrator_p);

                // We do not want to make signal/slot calls more than once. This is because
                // one user might well trigger more than one integration from this window to a
                // mass spectrum. Thus we do not want that *this window be still connected to
                // the specific mass_data_integrator_task_p when a new integration is
                // triggered. We want the signal/slot pairs to be contained to specific
                // objects. Each MassSpecTracePlotWnd::integrateToMz() call must be contained
                // to a this/mass_data_integrator_task_p specific signal/slot pair.
                disconnect(this,

                        static_cast<void (MassSpecTracePlotWnd::*)(
                            MsRunDataSetTreeMassDataIntegratorToMz *)>(
                                &MassSpecTracePlotWnd::integrateToMzSignal),

                        mass_data_integrator_task_p,

                        static_cast<void (MassDataIntegratorTask::*)(
                            MsRunDataSetTreeMassDataIntegratorToMz *)>(
                                &MassDataIntegratorTask::integrateToMz));
            }


        // Old version
        void
            MassSpecTracePlotWnd::finishedIntegratingToMz(
                    MsRunDataSetTreeMassDataIntegratorToMz *mass_data_integrator_p,
                    QCPAbstractPlottable *parent_plottable_p)
            {

                // This function is actually a slot that is called when the integration to mz
                // is terminated in a QThread.

                // qDebug() << "the integrator pointer:" << mass_data_integrator_p;

                // We get back the integrator that was made to work in another thread. Now get
                // the obtained data and work with them.

                // Store the MsRunDataSetSPtr for later use before deleting the integrattor.

                MsRunDataSetCstSPtr ms_run_data_set_csp =
                    mass_data_integrator_p->getMsRunDataSet();

                pappso::Trace integrated_trace =
                    mass_data_integrator_p->getMapTrace().toTrace();
                // qDebug() << "mass spectrum trace size:" << integrated_trace.size();

                if(!integrated_trace.size())
                {
                    qDebug() << "There is not a single point in the integrated trace.";
                    return;
                }

                // Also, do not forget to copy the processing flow from the integrator. This
                // processing flow will be set into the plot widget !

                ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow();

                // Sanity check
                if(ms_run_data_set_csp != processing_flow.getMsRunDataSetCstSPtr())
                    qFatal("Cannot be that the ms run data set pointers be different.");

                // Finally, do not forget that we need to delete the integrator now that the
                // calculation is finished.
                delete mass_data_integrator_p;
                mass_data_integrator_p = nullptr;

                // At this point, we need to get a color for the plot. That color needs to be
                // that of the parent.
                QColor plot_color = parent_plottable_p->pen().color();

                // We need to establish what widget is the destination of the integration. If
                // one or more than a widget is/are pinned-down, then that/these should be the
                // destinations. If no widget is pinned-down, then a new plot widget needs to
                // be created.

                std::vector<BasePlotCompositeWidget *> pinned_down_widgets =
                    pinnedDownWidgets();

                if(pinned_down_widgets.size())
                {
                    for(auto &&pinned_down_widget : pinned_down_widgets)
                        static_cast<BaseTracePlotCompositeWidget *>(pinned_down_widget)
                            ->addTrace(integrated_trace,
                                    static_cast<QCPGraph *>(parent_plottable_p),
                                    ms_run_data_set_csp,
                                    ms_run_data_set_csp->getMsRunId()->getSampleName(),
                                    processing_flow,
                                    plot_color);
                }
                else
                    addTracePlot(integrated_trace,
                            ms_run_data_set_csp,
                            processing_flow,
                            plot_color,
                            static_cast<QCPGraph *>(parent_plottable_p));

                // At this point, if the window is really not visible, then show it, otherwise
                // I was told that the user does not think that they can ask for the window to
                // show up in the main program window.

                if(!isVisible())
                {
                    showWindow();
                }
            }

#endif


void
MassSpecTracePlotWnd::integrateToMz(
  QCPAbstractPlottable *parent_plottable_p,
  std::shared_ptr<std::vector<pappso::QualifiedMassSpectrumCstSPtr>>
    qualified_mass_spectra_sp,
  const ProcessingFlow &processing_flow)
{
  // qDebug().noquote() << "Integrating to mz with processing flow:"
  //<< processing_flow.toString();

  // Get the ms run data set that for the graph we are going to base the
  // integration on.
  MsRunDataSetCstSPtr ms_run_data_set_csp =
    processing_flow.getMsRunDataSetCstSPtr();
  if(ms_run_data_set_csp == nullptr)
    qFatal("Cannot be that the pointer is nullptr.");

  // What integration parameters are we going to use ? Since we do integrate to
  // a mass spectrum it is compulsory that the most recent step has valid mz
  // integration params.

  // Set aside an object for later use.
  const pappso::MzIntegrationParams *mz_integration_params_p =
    processing_flow.mostRecentStep()->getMzIntegrationParamsPtr();

  if(mz_integration_params_p == nullptr || !mz_integration_params_p->isValid())
    qFatal(
      "Programming error. Cannot be that integration to m/z has no valid mz "
      "integration parameters set.");

  // First prepare a vector of QualifiedMassSpectrumCstSPtr

  std::size_t qualified_mass_spectra_count = fillInQualifiedMassSpectraVector(
    ms_run_data_set_csp, qualified_mass_spectra_sp, processing_flow);

  if(!qualified_mass_spectra_count)
    return;

  // qDebug() << "The number of remaining mass spectra:"
  //<< qualified_mass_spectra_count;

  // Now start the actual integration work.

  // Allocate a mass data integrator to integrate the data.

  QualifiedMassSpectrumVectorMassDataIntegratorToMz *mass_data_integrator_p =
    new QualifiedMassSpectrumVectorMassDataIntegratorToMz(
      ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp);

  mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount());

  // Ensure the mass data integrator messages are used.

  connect(
    mass_data_integrator_p,
    &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal,
    mp_programWindow,
    &ProgramWindow::logTextToConsole);

  // qDebug() << "Receiving processing flow:" << processing_flow.toString();

  MassDataIntegratorTask *mass_data_integrator_task_p =
    new MassDataIntegratorTask();

  // This signal starts the computation in the MassDataIntegratorTask
  // object.
  connect(this,

          static_cast<void (MassSpecTracePlotWnd::*)(
            QualifiedMassSpectrumVectorMassDataIntegratorToMz *)>(
            &MassSpecTracePlotWnd::integrateToMzSignal),

          mass_data_integrator_task_p,

          static_cast<void (MassDataIntegratorTask::*)(
            QualifiedMassSpectrumVectorMassDataIntegratorToMz *)>(
            &MassDataIntegratorTask::integrateToMz),

          // Fundamental for signals that travel across QThread instances...
          Qt::QueuedConnection);

  // Allocate the thread in which the integrator task will run.
  QThread *thread_p = new QThread;

  // Move the task to the matching thread.
  mass_data_integrator_task_p->moveToThread(thread_p);
  thread_p->start();

  // Since we allocated the QThread dynamically we need to be able to
  // destroy it later, so make the connection.

  connect(mass_data_integrator_task_p,

          static_cast<void (MassDataIntegratorTask::*)(
            QualifiedMassSpectrumVectorMassDataIntegrator *)>(
            &MassDataIntegratorTask::finishedIntegratingDataSignal),

          this,

          [this,
           thread_p,
           mass_data_integrator_p,
           parent_plottable_p,
           mass_data_integrator_task_p]() {
            // Do not forget that we have to delete the
            // MassDataIntegratorTask allocated instance.
            mass_data_integrator_task_p->deleteLater();
            // Once the task has been labelled to be deleted later, we can
            // stop the thread and ask for it to also be deleted later.
            thread_p->deleteLater(), thread_p->quit();
            thread_p->wait();
            this->finishedIntegratingToMz(mass_data_integrator_p,
                                          parent_plottable_p);
          });


  // qDebug() << "the integrator pointer:" << mass_data_integrator_p;

  // Allocate a new TaskMonitorCompositeWidget that will receive all the
  // integrator's signals and provide feedback to the user about the ongoing
  // integration.

  TaskMonitorCompositeWidget *task_monitor_composite_widget_p =
    mp_programWindow->mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red);

  // Initialize the monitor composite widget's widgets and make all the
  // connections mass data integrator <--> widget.

  task_monitor_composite_widget_p->setMsRunIdText(
    ms_run_data_set_csp->getMsRunId()->getSampleName());
  task_monitor_composite_widget_p->setTaskDescriptionText(
    "Integrating to mass spectrum from the table view");
  task_monitor_composite_widget_p->setProgressBarMinValue(0);

  // Make the connections

  // When the MsRunReadTask instance has finished working, it will send a
  // signal that we trap to finally destroy (after a time lag of some
  // seconds, the monitor widget.

  connect(mass_data_integrator_task_p,

          static_cast<void (MassDataIntegratorTask::*)(
            QualifiedMassSpectrumVectorMassDataIntegrator *)>(
            &MassDataIntegratorTask::finishedIntegratingDataSignal),

          task_monitor_composite_widget_p,

          &TaskMonitorCompositeWidget::taskFinished,

          Qt::QueuedConnection);

  // If the user clicks the cancel button, relay the signal to the loader.
  connect(task_monitor_composite_widget_p,
          &TaskMonitorCompositeWidget::cancelTaskSignal,
          mass_data_integrator_p,
          &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation);

  // We need to register the meta type for std::size_t because otherwise it
  // cannot be shipped though signals.

  qRegisterMetaType<std::size_t>("std::size_t");

  task_monitor_composite_widget_p->makeMassDataIntegratorConnections(
    mass_data_integrator_p);

  emit integrateToMzSignal(mass_data_integrator_p);

  // We do not want to make signal/slot calls more than once. This is
  // because one user might well trigger more than one integration from this
  // window to a mass spectrum. Thus we do not want that *this window be
  // still connected to the specific mass_data_integrator_task_p when a new
  // integration is triggered. We want the signal/slot pairs to be contained
  // to specific objects. Each MassSpecTracePlotWnd::integrateToMz() call
  // must be contained to a this/mass_data_integrator_task_p specific
  // signal/slot pair.
  disconnect(this,

             static_cast<void (MassSpecTracePlotWnd::*)(
               QualifiedMassSpectrumVectorMassDataIntegratorToMz *)>(
               &MassSpecTracePlotWnd::integrateToMzSignal),

             mass_data_integrator_task_p,

             static_cast<void (MassDataIntegratorTask::*)(
               QualifiedMassSpectrumVectorMassDataIntegratorToMz *)>(
               &MassDataIntegratorTask::integrateToMz));
}


void
MassSpecTracePlotWnd::finishedIntegratingToMz(
  QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p,
  QCPAbstractPlottable *parent_plottable_p)
{
  // qDebug();

  // This function is actually a slot that is called when the integration to
  // mz is terminated in a QThread.

  // qDebug() << "the integrator pointer:" << mass_data_integrator_p;

  // We get back the integrator that was made to work in another thread. Now
  // get the obtained data and work with them.

  // Store the MsRunDataSetSPtr for later use before deleting the integrattor.

  MsRunDataSetCstSPtr ms_run_data_set_csp =
    mass_data_integrator_p->getMsRunDataSet();

  pappso::Trace integrated_trace =
    mass_data_integrator_p->getMapTrace().toTrace();
  // qDebug() << "mass spectrum trace size:" << integrated_trace.size();

  if(!integrated_trace.size())
    {
      qDebug() << "There is not a single point in the integrated trace.";
      return;
    }

  // Also, do not forget to copy the processing flow from the integrator. This
  // processing flow will be set into the plot widget !

  ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow();

  // Sanity check
  if(ms_run_data_set_csp != processing_flow.getMsRunDataSetCstSPtr())
    qFatal("Cannot be that the ms run data set pointers be different.");

  // Finally, do not forget that we need to delete the integrator now that the
  // calculation is finished.
  delete mass_data_integrator_p;
  mass_data_integrator_p = nullptr;

  // At this point, we need to get a color for the plot. That color needs to
  // be that of the parent.

  QColor plot_color;

  // There are two situations: either the integration started from a plot
  // widget and the color is certainly obtainable via the pen of the plot.
  if(parent_plottable_p != nullptr)
    plot_color = parent_plottable_p->pen().color();
  else
    // Or the integration started at the MsRunDataSetTableView and the color
    // can only be obtained via the MsRunDataSet in the OpenMsRunDataSetsDlg.
    plot_color = mp_programWindow->getColorForMsRunDataSet(ms_run_data_set_csp);

  // The new trace checks if there are push-pinned widgets. If so, the new
  // trace will be apportioned to the widgets according to the required
  // mechanics: new plot, sum, combine...

  newTrace(integrated_trace,
           ms_run_data_set_csp,
           processing_flow,
           plot_color,
           static_cast<QCPGraph *>(parent_plottable_p));

  // At this point, if the window is really not visible, then show it,
  // otherwise I was told that the user does not think that they can ask for
  // the window to show up in the main program window.

  if(!isVisible())
    {
      showWindow();
    }
}


void
MassSpecTracePlotWnd::integrateToRt(QCPAbstractPlottable *parent_plottable_p,
                                    const ProcessingFlow &processing_flow)
{
  // qDebug();

  if(parent_plottable_p == nullptr)
    qFatal("Cannot be that pointer is nullptr.");

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


void
MassSpecTracePlotWnd::integrateToDt(QCPAbstractPlottable *parent_plottable_p,
                                    const ProcessingFlow &processing_flow)
{
  // qDebug();

  if(parent_plottable_p == nullptr)
    qFatal("Cannot be that pointer is nullptr.");

  mp_programWindow->integrateToDt(parent_plottable_p, nullptr, processing_flow);
}


void
MassSpecTracePlotWnd::integrateToRtMz(QCPAbstractPlottable *plottable_p,
                                      const ProcessingFlow &processing_flow)
{
  if(plottable_p == nullptr)
    qFatal("Cannot be that pointer is nullptr.");

  mp_programWindow->integrateToRtMz(plottable_p, nullptr, processing_flow);
}


void
MassSpecTracePlotWnd::integrateToDtMz(QCPAbstractPlottable *plottable_p,
                                      const ProcessingFlow &processing_flow)
{
  if(plottable_p == nullptr)
    qFatal("Cannot be that pointer is nullptr.");

  mp_programWindow->integrateToDtMz(plottable_p, nullptr, processing_flow);
}


void
MassSpecTracePlotWnd::integrateToRtDt(QCPAbstractPlottable *plottable_p,
                                      const ProcessingFlow &processing_flow)
{
  if(plottable_p == nullptr)
    qFatal("Cannot be that pointer is nullptr.");

  mp_programWindow->integrateToRtDt(plottable_p, nullptr, processing_flow);
}


void
MassSpecTracePlotWnd::setMinimalChargeFractionalPartPinnedDownWidgets(
  double value)
{
  std::vector<BasePlotCompositeWidget *> widget_list = pinnedDownWidgets();

  for(auto &&widget_p : widget_list)
    {
      static_cast<MassSpecTracePlotCompositeWidget *>(widget_p)
        ->setMinimalChargeFractionalPartPinnedDownWidgets(value);
    }
}


void
MassSpecTracePlotWnd::setChargeStateEnvelopePeakSpanPinnedDownWidgets(
  std::size_t value)
{
  std::vector<BasePlotCompositeWidget *> widget_list = pinnedDownWidgets();

  for(auto &&widget_p : widget_list)
    {
      static_cast<MassSpecTracePlotCompositeWidget *>(widget_p)
        ->setChargeStateEnvelopePeakSpanPinnedDownWidgets(value);
    }
}


} // namespace minexpert


} // namespace msxps
