/*******************************************************************************
 * Copyright (c) 2015 Olivier Langella <olivier.langella@u-psud.fr>.
 *
 * This file is part of the PAPPSOms++ library.
 *
 *     PAPPSOms++ 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.
 *
 *     PAPPSOms++ 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 PAPPSOms++.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#pragma once

/////////////////////// StdLib includes
#include <memory>


/////////////////////// Qt includes


/////////////////////// Local includes
#include "pappsomspp/export-import-config.h"
#include "pappsomspp/core/types.h"
#include "massspectrum.h"
#include "massspectrumid.h"


namespace pappso
{

// Forward declaration.
class QualifiedMassSpectrum;

typedef std::shared_ptr<QualifiedMassSpectrum> QualifiedMassSpectrumSPtr;
typedef std::shared_ptr<const QualifiedMassSpectrum>
  QualifiedMassSpectrumCstSPtr;

enum class QualifiedMassSpectrumParameter
{

  IonMobOneOverK0,      ///< 1/kO value
  IonMobOneOverK0Begin, ///< 1/K0 range's begin value
  IonMobOneOverK0End,   ///< 1/K0 range's end value

  TimsIonMobScanIndex,
  TimsFrameIonMobScanIndexBegin,
  TimsFrameIonMobScanIndexEnd,

  IsolationMz,      ///< Isolation m/z value
  IsolationMzWidth, ///< m/z isolation window width (left + right)

  CollisionEnergy,      ///< Bruker's timsTOF collision energy
  BrukerPrecursorIndex, ///< Bruker's timsTOF precursor index
  TimsFrameScansCount,  ///< Bruker's timsTOF frame's total ion mobility slots

  TimsFrameMzIndexBegin, ///< Bruker's timsTOF mz index frame start range
  TimsFrameMzIndexEnd,   ///< Bruker's timsTOF mz index frame end range

  ScanNumber, ///< Scan number: Ordinal number of the scan indicating its order
              ///< of acquisition within a mass spectrometry acquisition run.
              ///< MS_scan_number = 1003057,
  last
};

struct PrecursorIonData
{
  double mz        = 0;
  int charge       = 0;
  double intensity = 0;

  // Constructor
  PrecursorIonData(double mz_value        = 0,
                   int charge_value       = 0,
                   double intensity_value = 0)
  {
    mz        = mz_value;
    charge    = charge_value;
    intensity = intensity_value;
  };
};


//! Class representing a fully specified mass spectrum.
/*!
 * The member data that qualify the MassSpectrum \c msp_massSpectrum member
 * allow to unambiguously characterize the mass spectrum.
 * \sa MassSpectrum
 */
class PMSPP_LIB_DECL QualifiedMassSpectrum
{
  public:
  QualifiedMassSpectrum();
  QualifiedMassSpectrum(const MassSpectrumId &id);
  QualifiedMassSpectrum(MassSpectrumSPtr mass_spectrum_SPtr);
  QualifiedMassSpectrum(const QualifiedMassSpectrum &other);
  ~QualifiedMassSpectrum();

  QualifiedMassSpectrum &operator=(const QualifiedMassSpectrum &other);

  /** @brief clone the mass spectrum contained in Qualified Mass Spectrum
   */
  const QualifiedMassSpectrum &cloneMassSpectrumSPtr();

  QualifiedMassSpectrumSPtr makeQualifiedMassSpectrumSPtr() const;
  QualifiedMassSpectrumCstSPtr makeQualifiedMassSpectrumCstSPtr() const;

  void setMassSpectrumSPtr(MassSpectrumSPtr massSpectrum);
  MassSpectrumSPtr getMassSpectrumSPtr() const;
  MassSpectrumCstSPtr getMassSpectrumCstSPtr() const;

  void setMassSpectrumId(const MassSpectrumId &iD);
  const MassSpectrumId &getMassSpectrumId() const;
  MassSpectrumId &getMassSpectrumId();

  void setEmptyMassSpectrum(bool is_empty_mass_spectrum);
  bool isEmptyMassSpectrum() const;

  void setMsLevel(uint ms_level);
  uint getMsLevel() const;

  void setRtInSeconds(pappso_double rt);
  pappso_double getRtInSeconds() const;
  pappso_double getRtInMinutes() const;

  void setDtInMilliSeconds(pappso_double rt);
  pappso_double getDtInMilliSeconds() const;

  /** @brief get precursor mz
   * @param ok pointer on boolean, false if precursor mz is not defined
   * @return precursor mz
   */
  pappso_double getPrecursorMz(bool *ok = nullptr) const;

  /** @brief get precursor mass given the charge stats and precursor mz
   * @param ok pointer on boolean, false if precursor mz is not defined
   * @return precursor mass (neutral mass without H+)
   */
  double getPrecursorMass(bool *ok_p = nullptr) const;

  QString getPrecursorDataMzValuesAsString(
    const std::vector<PrecursorIonData> &precursor_ion_data_vector,
    const QString &separator = "\n") const;
  QString
  getPrecursorDataMzValuesAsString(const QString &separator = "\n") const;
  QString getMzSortedPrecursorDataMzValuesAsString(
    const QString &separator = "\n") const;

  /** @brief get precursor charge
   * @param ok pointer on boolean, false if precursor charge is not defined
   * @return precursor charge
   */
  uint getPrecursorCharge(bool *ok = nullptr) const;
  QString getPrecursorDataChargeValuesAsString(
    const std::vector<PrecursorIonData> &precursor_ion_data_vector,
    const QString &separator = "\n") const;
  QString
  getPrecursorDataChargeValuesAsString(const QString &separator = "\n") const;
  QString getMzSortedPrecursorDataChargeValuesAsString(
    const QString &separator = "\n") const;


  /** @brief get precursor intensity
   * @param ok pointer on boolean, false if precursor intensity is not defined
   * @return precursor intensity
   */
  pappso_double getPrecursorIntensity(bool *ok = nullptr) const;

  void setPrecursorSpectrumIndex(std::size_t precursor_scan_num);
  std::size_t getPrecursorSpectrumIndex() const;

  void setPrecursorNativeId(const QString &native_id);
  const QString &getPrecursorNativeId() const;

  void appendPrecursorIonData(const PrecursorIonData &precursor_ion_data);
  const std::vector<PrecursorIonData> &getPrecursorIonData() const;
  std::vector<PrecursorIonData> getPrecursorIonDataSortedWithMz() const;

  void setParameterValue(QualifiedMassSpectrumParameter parameter,
                         const QVariant &value);
  const QVariant
  getParameterValue(QualifiedMassSpectrumParameter parameter) const;

  std::size_t size() const;

  QString toString(bool with_data = false) const;

  protected:
  //! Shared pointer to the mass spectrum.
  MassSpectrumSPtr msp_massSpectrum = nullptr;

  //! Id of the mass spectrum.
  MassSpectrumId m_massSpectrumId;

  bool m_isEmptyMassSpectrum = false;

  //! Mass spectrometry level of this mass spectrum.
  unsigned int m_msLevel = 0;

  //! Retention time (in seconds) at which this mass spectrum was acquired.
  pappso_double m_rt = -1;

  //! Drift time (in milliseconds) at which this mass spectrum was acquired.
  pappso_double m_dt = -1;

  //! Index of the spectrum of the precusor ion that was fragmented to yield
  // this mass spectrum.
  std::size_t m_precursorSpectrumIndex =
    std::numeric_limits<std::size_t>::max();

  //! Native XML id of the spectrum relative to the mz data native file
  QString m_precursorNativeId;

  //! vector of precursor ion data of the precursors that were fragmented to
  //! yield this mass spectrum.
  std::vector<PrecursorIonData> m_precursorIonData;

  //! map containing any parameter value for this spectrum
  std::map<QualifiedMassSpectrumParameter, QVariant> m_paramsMap;
};


} // namespace pappso
