/**
 * \file input/sage/sagereader.h
 * \date 21/08/2024
 * \author Olivier Langella
 * \brief read data files from Sage output
 */

/*******************************************************************************
 * Copyright (c) 2024 Olivier Langella
 *<Olivier.Langella@universite-paris-saclay.fr>.
 *
 * This file is part of i2MassChroQ.
 *
 *     i2MassChroQ 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.
 *
 *     i2MassChroQ 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 i2MassChroQ.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#pragma once

#include <odsstream/odsdochandlerinterface.h>
#include "pappsomspp/core/processing/uimonitor/uimonitorinterface.h"
#include "../../../../peptide/peptide.h"
#include "sagereader.h"
#include "../psmproteinmap.h"
#include <QCborArray>


namespace pappso
{
namespace cbor
{
namespace psm
{

/**
 * @todo write docs
 */
class SageTsvHandler : public OdsDocHandlerInterface
{
  public:
  enum class Columns : std::int8_t
  {
    psm_id,
    peptide,
    proteins,
    protein_groups,
    num_proteins,
    num_protein_groups,
    filename,
    scannr,
    rank,
    label,
    expmass,
    calcmass,
    charge,
    peptide_len,
    missed_cleavages,
    semi_enzymatic,
    isotope_error,
    precursor_ppm,
    fragment_ppm,
    hyperscore,
    delta_next,
    delta_best,
    rt,
    aligned_rt,
    predicted_rt,
    delta_rt_model,
    ion_mobility,
    predicted_mobility,
    delta_mobility,
    matched_peaks,
    longest_b,
    longest_y,
    longest_y_pct,
    matched_intensity_pct,
    scored_candidates,
    poisson,
    sage_discriminant_score,
    posterior_error,
    spectrum_q,
    peptide_q,
    protein_q,
    protein_group_q,
    ms2_intensity,
  };

  struct Line
  {
    int rank        = 0;
    int label       = 0;
    double expmass  = 0.0;
    double calcmass = 0.0;
    int charge      = 0;
    std::size_t peptide_len;
    int missed_cleavages;
    int semi_enzymatic;
    double isotope_error;
    double precursor_ppm;
    double fragment_ppm;
    double hyperscore;
    double delta_next;
    double delta_best;
    double rt;
    double aligned_rt;
    double predicted_rt;
    double delta_rt_model;
    double ion_mobility;
    double predicted_mobility;
    double delta_mobility;
    std::size_t matched_peaks;
    std::size_t longest_b;
    std::size_t longest_y;
    double longest_y_pct;
    double matched_intensity_pct;
    std::size_t scored_candidates;
    double poisson;
    double sage_discriminant_score;
    double posterior_error;
    double spectrum_q;
    double peptide_q;
    double protein_q;
    double ms2_intensity;
  };
  /**
   * Default constructor
   */
  SageTsvHandler(pappso::UiMonitorInterface *p_monitor,
                 const SageReader &sage_reader,
                 PsmProteinMap &psm_protein_map);

  /**
   * Destructor
   */
  virtual ~SageTsvHandler();
  /**
   * callback that indicates the begining of a data sheet. Override it in
   * order to retrieve information about the current data sheet.
   *
   */
  virtual void startSheet(const QString &sheet_name) override;

  /**
   * callback that indicates the end of the current data sheet. Override it if
   * needed
   */
  virtual void endSheet() override;

  /**
   * callback that indicates a new line start. Override it if needed.
   */

  virtual void startLine() override;

  /**
   * callback that indicates a line ending. Override it if needed.
   */

  virtual void endLine() override;

  /**
   * callback that report the content of the current cell in a dedicated Cell
   * object. Override it if you need to retrieve cell content.
   */
  virtual void setCell(const OdsCell &cell) override;
  virtual void endDocument() override;

  void writeSampleList();

  private:
  struct Psm
  {
    QString proforma;
    QStringList protein_list;
    QString peptide_sequence_li;
    QCborMap cbor_eval;
  };
  struct Scan
  {
    QCborMap cbor_id;
    QCborMap cbor_precursor;
    QCborMap cbor_ms2;
    std::vector<Psm> psm_list;
  };

  struct Sample
  {
    QString name;
    QCborMap cbor_core_sample;
    std::map<QString, Scan> scan_map;
  };

  private:
  void parsePeptide(const QString &peptide_str);
  void parseProteins(const QString &proteins_str);
  bool parseScanNrColumn(const QString &spectrum_string_id);
  void parseMsRunFilename(const QString &msrun_filename);
  void recordLine();

  void writeSample(const Sample &one_sample);
  void writeScan(const Scan &one_scan);
  void writePsm(const Psm &one_psm);

  private:
  const SageReader &m_sageReader;
  PsmProteinMap &m_psmProteinMap;
  pappso::UiMonitorInterface *mp_monitor = nullptr;
  std::size_t m_progressIndex            = 0;
  std::size_t m_lineNumber               = 0;
  std::size_t m_columnNumber             = 0;
  std::vector<Columns> m_columnTypeList;

  pappso::PeptideSp msp_peptide;
  std::vector<SageReader::SageModification> m_staticModificationList;
  std::vector<SageReader::SageModification> m_variableModificationList;
  std::size_t m_spectrumIndex;
  std::size_t m_scanNumber;
  bool m_scanNumberIsOk;

  Line m_line;
  QString m_decoyTag;
  QStringList m_proteinList;
  QString m_spectrumNativeId;
  std::map<QString, Sample> m_sampleMap;
  Sample *mp_currentSample;
};
} // namespace psm
} // namespace cbor
} // namespace pappso
