/**
 * \file pappsomspp/vendors/tims/timsddaprecursors.h
 * \date 30/06/2024
 * \brief handle specific data for DDA MS runs
 */

/*******************************************************************************
 * Copyright (c) 2024 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
#include "timsdata.h"

namespace pappso
{
/**
 * @todo TimsData helper that stores all related DDA informations
 */
class PMSPP_LIB_DECL TimsDdaPrecursors
{
  friend TimsData;

  public:
  /**
   * Default constructor
   */
  TimsDdaPrecursors(QSqlQuery &query, TimsData *tims_data_origin);

  /**
   * Destructor
   */
  ~TimsDdaPrecursors();


  /** @brief get the number of precursors analyzed by PASEF
   */
  std::size_t getTotalPrecursorCount() const;


  XicCoordTims getXicCoordTimsFromPrecursorId(std::size_t precursor_id,
                                              PrecisionPtr precision_ptr);


  struct SpectrumDescr
  {
    std::size_t parent_frame        = 0;
    std::size_t precursor_id        = 0;
    std::size_t scan_mobility_start = 0;
    std::size_t scan_mobility_end   = 0;
    std::size_t ms1_index           = 0;
    std::size_t ms2_index           = 0;
    double isolationMz              = 0;
    double isolationWidth           = 0;
    float collisionEnergy           = 0;
    std::vector<std::size_t> tims_frame_list;
    PrecursorIonData precursor_ion_data;
  };


  /** @brief get an intermediate structure describing a spectrum
   */
  TimsDdaPrecursors::SpectrumDescr
  getSpectrumDescrWithPrecursorId(std::size_t precursor_id) const;

  /** @brief get a list of TimsDdaPrecursors::SpectrumDescr for a frame
   * @param frame_id the frame_id
   */
  std::vector<TimsDdaPrecursors::SpectrumDescr>
  getSpectrumDescrListByFrameId(std::size_t frame_id) const;

  // FIXME NAMING: identical to above
  // Not used in i2mcq
  void getQualifiedMs2MassSpectrumBySpectrumDescr(
    const MsRunIdCstSPtr &msrun_id,
    QualifiedMassSpectrum &mass_spectrum,
    const SpectrumDescr &spectrum_descr,
    bool want_binary_data);

  // FIXME NAMING: identical to above
  // Not used in i2mcq
  void getQualifiedMs1MassSpectrumBySpectrumDescr(
    const MsRunIdCstSPtr &msrun_id,
    QualifiedMassSpectrum &mass_spectrum,
    const SpectrumDescr &spectrum_descr,
    bool want_binary_data);


  /** @brief filter interface to apply just after raw MS2 specturm extraction
   * the filter can be a list of filters inside a FilterSuite object
   */
  void setMs2FilterCstSPtr(pappso::FilterInterfaceCstSPtr &filter);

  /** @brief filter interface to apply just after raw MS1 specturm extraction
   * the filter can be a list of filters inside a FilterSuite object
   */
  void setMs1FilterCstSPtr(pappso::FilterInterfaceCstSPtr &filter);


  /** @brief enable or disable simple centroid filter on raw tims data for MS2
   */
  void setMs2BuiltinCentroid(bool centroid);


  /** @brief tells if simple centroid filter on raw tims data for MS2 is enabled
   * or not
   */
  bool getMs2BuiltinCentroid() const;


  /** @brief function to visit an MsRunReader and get each Spectrum in a
   * spectrum collection handler by Ms Levels
   *
   * this function will retrieve processed qualified spectrum depending on each
   * Bruker precursors
   */
  void ms2ReaderSpectrumCollectionByMsLevel(
    const MsRunIdCstSPtr &msrun_id,
    SpectrumCollectionHandlerInterface &handler,
    unsigned int ms_level);

  /** @brief set only one is_mono_thread to true
   *
   * this avoid to use qtconcurrent
   */
  void setMonoThread(bool is_mono_thread);


  /** @brief function to visit an MsRunReader and get each raw Spectrum in a
   * spectrum collection handler by Ms Levels
   *
   * this function will retrieve every scans as a qualified mass spectrum
   */
  void rawReaderSpectrumCollectionByMsLevel(
    const MsRunIdCstSPtr &msrun_id,
    SpectrumCollectionHandlerInterface &handler,
    unsigned int ms_level);


  /** @brief guess possible precursor ids given a charge, m/z, retention time
   * and k0
   * @return a list of possible precursor ids
   */
  std::vector<std::size_t> getPrecursorsByMzRtCharge(int charge,
                                                     double mz_val,
                                                     double rt_sec,
                                                     double k0);

  // FIXME: TO THROW AWAY
  [[deprecated("This function will be removed")]] std::vector<std::size_t>
  getMatchPrecursorIdByKo(std::vector<std::vector<double>> ids,
                          double ko_value);

  /** @todo documentation
   */
  // FIXME: TO THROW AWAY
  [[deprecated("This function will be removed")]] std::vector<std::size_t>
  getClosestPrecursorIdByMz(std::vector<std::vector<double>> ids,
                            double mz_value);


  /** @brief get cumulated raw signal for a given
   * precursorCMakeLists.txt.userCMakeLists.txt.userCMakeLists.txt.user only to
   * use to see the raw signal
   *
   * @param precursor_index precursor index to extract signal from
   * @result a map of integers, x=time of flights, y= intensities
   */
  // Not used in i2mcq
  TimsDataFastMap &getCombinedMs2ScansByPrecursorId(std::size_t precursor_id);

  protected:
  // FIXME NAMING: identical to above
  // Not used in i2mcq
  SpectrumDescr getSpectrumDescrWithScanCoordinates(
    const std::pair<std::size_t, std::size_t> &scan_coordinates);

  private:
  void ms2ReaderGenerateMS1MS2Spectrum(
    const MsRunIdCstSPtr &msrun_id,
    std::vector<QualifiedMassSpectrum> &qualified_mass_spectrum_list,
    SpectrumCollectionHandlerInterface &handler,
    const SpectrumDescr &spectrum_descr,
    unsigned int ms_level);

  void fillSpectrumDescriptionWithSqlRecord(SpectrumDescr &spectrum_descr,
                                            QSqlQuery &qprecursor_list);

  private:
  TimsData *mp_timsDataOrigin;

  std::size_t m_totalPrecursorCount;


  std::map<std::size_t, QSqlRecord> m_mapXicCoordRecord;


  pappso::FilterInterfaceCstSPtr mcsp_ms2Filter = nullptr;
  pappso::FilterInterfaceCstSPtr mcsp_ms1Filter = nullptr;

  /** @brief enable builtin centroid on raw tims integers by default
   */
  bool m_builtinMs2Centroid = true;

  bool m_isMonoThread = false;

  QMutex m_mutex;
};
} // namespace pappso
