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

#include <QVector>

#include <minexpert/nongui/MassSpecDataSet.hpp>
#include <minexpert/nongui/History.hpp>


namespace msXpSmineXpert
{


//! The MassDataIntegrator class provides the integration calculations.
/*!

  Any mass data mining session starts with the opening of a mass spectrometric
  data file. Immediately, the program computes a TIC chromatogram and a
  mz=f(dt) color map, if the data are for an ion mobility mass spectrometry
  experiment. From these two plots, the user starts making integrations to
  mine the data in the preferred direction. For example, one might want to
  look at the mass spectrum corresponding to the combination of all the
  spectra acquired between retention time1 and retention time2. The
  combination of the spectra actually correspond to an integration over the
  time lapse (time2 - time1). This class performs this kind of calculation.

*/
class MassDataIntegrator : public QObject
{
  Q_OBJECT;

  private:
  //! Mass spectral data set. We do not own that stuff.
  const mutable MassSpecDataSet *mp_massSpecDataSet = Q_NULLPTR;

  // History of the data set to take into account for the integration.
  History m_history;

  // Tells if the integration was cancelled by the user.
  bool m_isOperationCancelled = false;

  bool m_isRunning = false;

  // Vector of double values to hold the x-axis data.
  QVector<double> m_keyVector;

  // Vector of double values to hold the y-axis data.
  QVector<double> m_valVector;

  // Color map stuff
  int m_dtValueCount = 0;
  int m_mzCells      = 0;
  double m_firstKey  = 0;
  double m_lastKey   = 0;
  double m_firstVal  = 0;
  double m_lastVal   = 0;
  int m_errorCode    = -1;

  // TIC intensity single value stuff
  double m_ticIntensity;

  // Map relating x-axis data with y-axix data.
  QMap<double, double> m_map;

  // Map relating double data (dt, typically) with mass spectra.
  QHash<double, msXpSlibmass::MassSpectrum *> m_doubleMassSpecHash;

  QString m_feedbackMsgSkeleton;
  int m_progressFeedbackStartValue = -1;
  int m_progressFeedbackEndValue   = -1;
  int m_progressCounter            = 0;
  int m_counter                    = 0;

  public:
  MassDataIntegrator();

  MassDataIntegrator(const MassSpecDataSet *massSpecDataSet);

  MassDataIntegrator(const MassSpecDataSet *massSpecDataSet,
                     const History &history);
  virtual ~MassDataIntegrator();

  void setMassSpecDataSet(const MassSpecDataSet *massSpecDataSet);
  const MassSpecDataSet *massSpecDataSet() const;

  const QVector<double> &keyVector() const;
  const QVector<double> &valVector() const;

  const QMap<double, double> &map();
  const QHash<double, msXpSlibmass::MassSpectrum *> &doubleMassSpecHash();

  void setHistory(const History &history);
  History history() const;

  int
  dtValueCount()
  {
    return m_dtValueCount;
  };
  int
  mzCells()
  {
    return m_mzCells;
  };
  double
  firstKey()
  {
    return m_firstKey;
  };
  double
  lastKey()
  {
    return m_lastKey;
  };
  double
  firstVal()
  {
    return m_firstVal;
  };
  double
  lastVal()
  {
    return m_lastVal;
  };
  int
  errorCode()
  {
    return m_errorCode;
  };

  Q_INVOKABLE double ticIntensity() const;

  Q_INVOKABLE void initialTic();
  void streamInitialTic();

  Q_INVOKABLE void fillInDtMzHash();
  void streamFillInDtMzHash();

  Q_INVOKABLE bool integrate();

  Q_INVOKABLE bool integrateToRt();
  bool streamIntegrateToRt();

  Q_INVOKABLE bool integrateToMz();
  bool streamIntegrateToMz();

  Q_INVOKABLE bool integrateToDt();
  bool streamIntegrateToDt();

  Q_INVOKABLE bool integrateToTicIntensity();
  bool streamIntegrateToTicIntensity();

  public slots:

  //! React to the signal that tells the operation was cancelled by the
  // user.
  void cancelOperation();

  //! Relay a signal to another object.
  void updateFeedbackRelay(QString msg,
                           int currentValue,
                           bool setVisible,
                           int logType    = LogType::LOG_TO_CONSOLE,
                           int startValue = -1,
                           int endValue   = -1);

  void incrementCounter(int count);

  signals:
  void updateFeedbackSignal(QString msg,
                            int currentValue,
                            bool setVisible,
                            int logType    = LogType::LOG_TO_CONSOLE,
                            int startValue = -1,
                            int enValue    = -1);

  void cancelOperationSignal();

  void resultsReadySignal();
};


} // namespace msXpSmineXpert
