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


#pragma once


/////////////////////// Qt includes
#include <QObject>
#include <QString>
#include <QWidget>
#include <QColor>


///////////////////////////// Local includes
#include <minexpert/gui/AbstractPlotWidget.hpp>
#include <minexpert/gui/AbstractMultiPlotWnd.hpp>
#include <minexpert/nongui/MassSpecDataSet.hpp>
#include <minexpert/nongui/History.hpp>


namespace msXpSmineXpert
{


//! The MassSpecPlotWidget class provides a mass spectrum-specific plot widget.
class MassSpecPlotWidget : public AbstractPlotWidget
{
  Q_OBJECT

  private:
  virtual QMenu *createContextMenu() override;

  // These data are required to display the charge and mass values as
  // calculated when the user drags the mouse over peaks belonging to either
  // an isotopic cluster or two peaks of the same charge envelope.


  //! Last charge level that was computed.
  int m_lastCharge = -1;

  //! Proton mass value. Used for the deconvolutions.
  double m_protonMass = 1.007825035;

  //! Last m/z value that was computed.
  double m_lastMz = qSNaN();

  //! Last Mr value that was computed.
  double m_lastMass = qSNaN();

  //! Last resolving power value that was computed.
  double m_lastResolvingPower = std::numeric_limits<double>::min();

  //! Tolerance on the charge fractional part during deconvolutions.
  /*:

    When doing deconvolutions, the charge of the ion under the peak cannot
    be determined as an integer. Instead, it is a decimal value that should
    be the nearest as possible to an integer value. But it is not possible
    to discard charge values that are decimal. This value accounts for just
    that.

    Ideally that would be set to 1, but the graphical display of the mass
    spectrum is pixel-based, and depending on the screen real estate, from a
    pixel to the other, the m/z gap might be too much and then we would not
    be able to ever show the deconvolution results. Setting this value too
    low produces hysteresis, in the sense that by pointing exactly the same
    points, but from left to right or right to left, the Mr values differ
    significantly.

*/
  double m_chargeFracPartTolerance = 0.99;

  public:
  MassSpecPlotWidget(QWidget *parent,
                     const QString &name,
                     const QString &desc,
                     const MassSpecDataSet *massSpecDataSet = Q_NULLPTR,
                     const QString &fileName                = QString(),
                     bool isMultiGraph                      = false);

  ~MassSpecPlotWidget();

  int arbitraryIntegrationType() override;

  QString craftAnalysisStanza(QCPGraph *theGraph      = Q_NULLPTR,
                              const QString &fileName = QString());

  bool deconvolute();
  bool deconvoluteIsotopicCluster();
  bool deconvoluteChargedState(int span = 1);

  bool computeResolvingPower();

  void mouseMoveHandler(QMouseEvent *event) override;
  void mouseReleaseHandledEvent(QMouseEvent *event) override;

  void keyReleaseEvent(QKeyEvent *event) override;

  void integrateToDt(double lower = qSNaN(), double upper = qSNaN());
  Q_INVOKABLE void jsIntegrateToDt(double lower = qSNaN(),
                                   double upper = qSNaN());

  void integrateToRt(double lower = qSNaN(), double upper = qSNaN());
  Q_INVOKABLE void jsIntegrateToRt(double lower = qSNaN(),
                                   double upper = qSNaN());

  void integrateToTicIntensity(double lower = qSNaN(), double upper = qSNaN());
  Q_INVOKABLE double jsIntegrateToTicIntensity(double lower = qSNaN(),
                                               double upper = qSNaN());

  Q_INVOKABLE msXpSlibmass::MassSpectrum massSpectrum(double lower = qSNaN(),
                                                      double upper = qSNaN());

  Q_INVOKABLE void newPlot();

  void showHelpSummary();

  signals:
  void recordAnalysisStanza(QString stanza, const QColor &color = QColor());

  void newDriftSpectrum(const MassSpecDataSet *massSpecDataSet,
                        const QString &msg,
                        const History &history,
                        QColor color);

  void newTicChromatogram(const MassSpecDataSet *massSpecDataSet,
                          const QString &msg,
                          const History &history,
                          QColor color);

  void ticIntensitySignal(const MassSpecDataSet *massSpecDataSet,
                          const QString &msg,
                          const History &history);
};


} // namespace msXpSmineXpert
