/**
 * \file pappsomspp/processing/specglob/experimentalspectrum.h
 * \date 08/11/2023
 * \author Olivier Langella
 * \brief transform a spectrum to SpecGlob spectra
 *
 * C++ implementation of the SpecGlob algorithm described in :
 * 1. Prunier, G. et al. Fast alignment of mass spectra in large proteomics
 * datasets, capturing dissimilarities arising from multiple complex
 * modifications of peptides. BMC Bioinformatics 24, 421 (2023).
 *
 *     HAL Id : hal-04296170 , version 1
 *     Mot de passe : hxo20cl
 *     DOI : 10.1186/s12859-023-05555-y
 */


/*
 * SpecGlobTool, Spectra to peptide alignment tool
 * Copyright (C) 2023  Olivier Langella
 * <olivier.langella@universite-paris-saclay.fr>
 *
 * 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/>.
 *
 */

#pragma once

#include "../../massspectrum/qualifiedmassspectrum.h"
#include "pappsomspp/export-import-config.h"
#include "types.h"


namespace pappso
{
namespace specglob
{

struct ExperimentalSpectrumDataPoint
{
  ExperimentalSpectrumDataPointType type;
  double peak_mz = 0;
  std::size_t indice;
};

class ExperimentalSpectrum;

typedef std::shared_ptr<const ExperimentalSpectrum> ExperimentalSpectrumCsp;
/**
 * @todo write docs
 */
class PMSPP_LIB_DECL ExperimentalSpectrum : public std::vector<ExperimentalSpectrumDataPoint>
{
  public:
  /**
   * Default constructor
   */
  ExperimentalSpectrum(const pappso::QualifiedMassSpectrum &qmass_spectrum,
                       pappso::PrecisionPtr precision_ptr);

  /**
   * specpeptidoms post-processing constructor
   */
  ExperimentalSpectrum(const pappso::QualifiedMassSpectrum &qmass_spectrum,
                       pappso::PrecisionPtr precision_ptr,
                       double precursor_mass_error);

  /**
   * Copy constructor
   *
   * @param other TODO
   */
  ExperimentalSpectrum(const ExperimentalSpectrum &other);

  /**
   * Destructor
   */
  virtual ~ExperimentalSpectrum();

  std::vector<double> getMassList() const;

  /** @brief compute the symmetric mass
   * for debuggin purpose
   */
  double getSymetricMz(double mz) const;

  double getTargetMzSum() const;

  double getPrecursorMass() const;

  std::vector<double> getMassList(ExperimentalSpectrumDataPointType type) const;

  QString toString() const;

  const pappso::QualifiedMassSpectrum &getQualifiedMassSpectrum() const;

  /** @brief find the peak for wich mass difference from rbegin corresponds to
   * aaTheoMass Find if a peak back in the peak list has a mass difference that
   * corresponds to the targeted mass
   *
   * @param start_position reverse iterator on the reference peak to look for
   * mass difference from
   * @param targeted_mass_range the mass difference to look forconst
   * pappso::PeptideSp peptide_sp
   * @return a reverse iterator on the peak (found) or the end of the search
   * (not found)
   */
  std::vector<ExperimentalSpectrumDataPoint>::const_reverse_iterator
  reverseFindDiffMz(std::size_t start_position, const pappso::MzRange &targeted_mass_range) const;

  private:
  /** @brief add symmetric peaks to the spectrum
   * Create a SymetricPeakList that contain symmetric peaks and the information
   * if a peak is the initial peak, the symmetric peak, or both if already
   * exist.
   * assuming fragment ion charge is 1
   */
  void createSymetricPeakList();

  void createSymetricPeakList(double precursor_mass_error);

  /** @brief find the correspondin mz in the mass spectrum (given the precision)
   */
  std::vector<pappso::DataPoint>::const_iterator findMz(double mz);

  private:
  pappso::QualifiedMassSpectrum m_qualifiedMassSpectrum;
  double m_targetMzSum;
  double m_precursorMass;
  pappso::PrecisionPtr m_precisionPtr;
};
} // namespace specglob
} // namespace pappso
