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


/////////////////////// Local includes
#include <minexpert/nongui/globals.hpp>
#include <minexpert/nongui/History.hpp>
#include <globals/globals.hpp>
#include <libmass/MassSpectrum.hpp>
#include <libmass/MsMultiHash.hpp>
#include <minexpert/nongui/MassSpecDataStats.hpp>

namespace msXpSmineXpert
{


class MassSpecDataStats;

//! The MassSpecDataSet class provides a structured memory storage for mass
//! data.
/*!

  The MassSpecDataSet class is the in-memory data storage workhorse of
  mineXpert. It allows storing mass spectra in a list and making references to
  the stored mass spectra using maps. In particular, it allows looking for
  spectra on the basis of their retention time or on the basis of their ion
  mobility drift time.

  The structure of MassSpecDataSet is crafted in such a manner that the mass
  spectrum extraction on the basis of various criteria is simple and speedy.

  The mineXpert software may be operated in two modes:

  - streamed, that means that data are systematically read from disk and never
  totally stored in RAM;

  - \e not streamed, that is full, where the data are totally read from disk
  into RAM and used from RAM.

  Member data are designed to allow crafting sub-datasets based on the
  streamed/full requirements above.

  When streamed mode is on (the \c m_isStreamed value is true), the user needs
  to allocate on the heap a new MassSpectrum and append it to the
  m_massSpectra mass spectrum list member because \e that spectrum is going to
  be the combination of the whole set of loaded mass spectra from file.


*/
class MassSpecDataSet : public QObject
{
  Q_OBJECT;


  //! This class has lots of friend classes that load mass data.
  /*!

    Because this class is the receiver of the mass spectrometry data loaded
    from files, this class has lots of friend classes that are indeed in
    charge of loading mass spectrometry data from files.

*/
  friend class MassSpecDataFileLoaderBrukerXy;
  friend class MassSpecDataFileLoaderDx;
  friend class MassSpecDataFileLoaderXy;
  friend class MassSpecDataFileLoaderMs1;
  friend class MassSpecDataFileLoaderPwiz;
  friend class MassSpecDataFileLoaderSqlite3;


  private:
  //! Name of this MassSpecDataSet
  QString m_name;

  //! Name of the file from which to load the data into this MassSpecDataSet.
  QString m_fileName;

  //! Mass spectrometry format of the file from which to load data.
  int m_fileFormat;

  //! Tells if the data are to be or were loaded in streamed mode or not.
  bool m_isStreamed = false;

  //! Number of cells to be used to fill-in the mz=f(dt) color map.
  int m_mzCellCount = -1;

  //! First (smallest) m/z value of the whole data set.
  double m_mzRangeStart = 1000000;

  //! Last (greatest) m/z value of the whole data set.
  double m_mzRangeEnd = 0;

  //! List of all the mass spectra in the data set.
  /*!

    MassSpecDataSet owns the MassSpectrum instances allocated and stored in this
    list. The spectra must be deleted upon destruction of \c this
    MassSpecDataSet instance.

*/
  QList<msXpSlibmass::MassSpectrum *> m_massSpectra;

  //! Hash relating retention time values with mass spectra.
  /*!

    This hash is central in the working of the program: it allows to make a
    quick relation between the retention times of a mass spectrometry
    acquisition and the corresponding mass spectra.

    Note that it is a multi-hash, that is, it might contain more than one key
    of the same value. This is because in ion mobility mass spectrometry, for
    any given retention time there might be a number of spectra corresponding
    to the various drift time slots. For example, with the Waters Synapt MS
    machine, each retention time contains a set of two hundred spectra, each
    spectrum corresponding to a time slice of the drift cycle (that's called a
    bin).

*/
  msXpSlibmass::MsMultiHash m_rtHash;

  //! Hash relating ion mobility drift time values with mass spectra.
  /*!

    This hash is central in the working of the program: it allows to make a
    quick relation between the drift time of a mass spectrometry
    acquisition and the corresponding mass spectra.

    Note that it is a multi-hash, that is, it might contain more than one key
    of the same value. This is because in ion mobility mass spectrometry, for
    any given retention time there might be a number of spectra corresponding
    to the various drift time slots. For example, with the Waters Synapt MS
    machine, each retention time contains a set of two hundred spectra, each
    spectrum corresponding to a time slice of the drift cycle (that's called a
    bin). Thus, if the acquisition lasts more than one single spectrum, for a
    given drift time there will be as many spectra as there were retention
    time values.

*/
  msXpSlibmass::MsMultiHash m_dtHash;

  //! Stores the TIC chromatogram data when loading in streamed mode.
  /*!

    When loading mass spectrometry data in streamed mode, the data are read
    from the file but are not stored durably in the MassSpecDataSet. Instead,
    the data are processed at read time so as to craft the very first usable
    data object: the TIC chromatogram that is produced so that the user can
    start mining the data in a useful way. In this map, the key corresponds to
    the retention time and the value to the corresponding TIC intensity value.

*/
  QMap<double, double> m_ticChromMap;

  //! Statistical data of the mass spectral data set.
  mutable MassSpecDataStats m_massSpecDataStats;

  public:
  // Construction / Destruction

  MassSpecDataSet(QObject *parent         = nullptr,
                  const QString &name     = QString(),
                  const QString &fileName = QString(),
                  bool isStreamed         = false);
  ~MassSpecDataSet();


  QString name() const;
  QString fileName() const;
  bool isStreamed() const;
  bool isMobilityExperiment() const;
  int fileFormat() const;
  int &rfileFormat();
  double mzCellCount() const;
  double mzRangeStart() const;
  double mzRangeEnd() const;

  const MassSpecDataStats &
  makeStatistics(const History &history = History()) const;

  const MassSpecDataStats &
  incrementStatistics(const msXpSlibmass::MassSpectrum &massSpectrum);
  const MassSpecDataStats &consolidateStatistics();

  const MassSpecDataStats &statistics() const;

  void resetStatistics();

  QString statisticsAsText() const;

  const QList<msXpSlibmass::MassSpectrum *> &massSpectra() const;
  QList<msXpSlibmass::MassSpectrum *> *
  extractMassSpectra(const History &history = History()) const;

  const msXpSlibmass::MsMultiHash &rtHash() const;
  const msXpSlibmass::MsMultiHash &dtHash() const;
  const QMap<double, double> &ticChromMap() const;

  const msXpSlibmass::MassSpectrum *massSpectrum(int index) const;

  int size() const;

  void setParent(QObject *parent);

  void appendMassSpectrum(msXpSlibmass::MassSpectrum *massSpectrum);

  void insertRtHash(double key, msXpSlibmass::MassSpectrum *value);

  void insertDtHash(double key, msXpSlibmass::MassSpectrum *value);
};


} // namespace msXpSmineXpert
