/**
 * \file src/input/mzidentml/mzidentmlreader.h
 * \date 24/11/2022
 * \author Olivier Langella
 * \brief new method to read mzIdentML XML files
 */


/*******************************************************************************
 * Copyright (c) 2022 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 <pappsomspp/core/processing/xml/xmlstreamreaderinterface.h>
#include "../../core/project.h"
#include "../../utils/workmonitor.h"
#include "../../core/identification_sources/identificationmzidentmlfile.h"
/**
 * @todo write docs
 */
class MzIdentMlReader : public pappso::XmlStreamReaderInterface
{
  public:
  /**
   * Default constructor
   */
  MzIdentMlReader(pappso::UiMonitorInterface *p_monitor,
                  Project *p_project,
                  const QFileInfo &mzident_file);
  /**
   * Destructor
   */
  virtual ~MzIdentMlReader();

  IdentificationEngine getIdentificationEngine() const;
  const QString &getIdentificationEngineVersion() const;


  protected:
  virtual void readStream() override;

  private:
  bool readAnalysisSoftware();
  bool readSequenceCollectionItem();
  bool readAnalysisCollectionItem();
  bool readDataCollectionItem();
  void readDBSequence();
  void readPeptide();
  bool readPeptideEvidence();
  void readSpectrumIdentification();
  void readInputs();
  void readAnalysisData();
  bool readSearchDatabase();
  void readSpectraData();
  void readSpectrumIdentificationResult();


  struct CvParam
  {
    QString cvRef;
    QString accession;
    QString name;
    QString value;
    QString unitAccession;
    QString unitName;
    QString unitCvRef;

    QString toString() const;
  };

  struct Modification
  {
    double monoisotopicMassDelta;
    std::size_t location;
    CvParam cvParam;
  };

  struct MzidPeptideEvidence
  {
    ProteinXtpSp protein;
    PeptideXtpSp peptide;
    std::size_t start;
    std::size_t end;
    bool isDecoy;
  };

  struct UserParam
  {
    QString name;
    QString value;
    QString toString() const;
  };

  struct SpectrumIdentificationItem
  {
    unsigned int chargeState;
    double experimentalMassToCharge;
    double calculatedMassToCharge;
    PeptideXtpSp peptide;
    std::vector<MzidPeptideEvidence> mzidPeptideEvidenceList;

    std::vector<CvParam> cvParamList;
    std::vector<UserParam> userParamList;
  };

  struct SpectrumIdentificationResult
  {
    QString id;
    QString spectrumID;
    IdentificationMzIdentMlFileSp mzident_source_sp;
    IdentificationGroup *identification_group_p;
    std::size_t scanNum;
    std::size_t spectrumIndex;
    bool isSpectrumIndex = false;
    double retentionTime;
    std::vector<SpectrumIdentificationItem> spectrumIdentificationItemList;

    std::vector<CvParam> cvParamList;
    std::vector<UserParam> userParamList;
  };

  CvParam readCvParam();

  UserParam readUserParam();


  void readSpectrumIdentificationItem(
    SpectrumIdentificationResult &spectrum_identification_result);

  void processSpectrumIdentificationItem(
    SpectrumIdentificationResult &spectrum_identification_result,
    const SpectrumIdentificationItem &spectrumIdentificationItem);

  private:
  pappso::UiMonitorInterface *mp_monitor;
  Project *mp_project;
  IdentificationEngine m_identificationEngine;
  QString m_analysisSoftwareVersion;


  std::map<QString, IdentificationGroup *>
    m_mapSpectraDataId2IdentificationGroupPtr;

  std::map<QString, IdentificationMzIdentMlFileSp>
    m_mapSpectraDataId2IdentificationMzIdentMlFileSp;


  /** @brief store association between xml ID and an identification engine
   */
  std::map<QString, IdentificationEngine> m_IdentificationEngineMap;


  /** @brief store association between xml ID and protein object
   */
  std::map<QString, ProteinXtpSp> m_ProteinXmlIdMap;

  /** @brief store association between xml ID and fasta files
   */
  std::map<QString, FastaFileSp> m_FastaFileIdMap;


  /** @brief store association between xml ID and peptide sequence
   */
  std::map<QString, PeptideXtpSp> m_PeptideIdMap;


  /** @brief store association between xml ID and peptide evidence
   */
  std::map<QString, MzidPeptideEvidence> m_MzidPeptideEvidenceIdMap;


  /** @brief store association between xml ID and msrun
   */
  std::map<QString, MsRunSp> m_MsRunIdMap;

  /** @brief associates database ref id to protein shared pointer
   * because the search database id is not described before the protein (silly
   * idea IMHO) we keep association of protein to database in this map until the
   * real search database definition appears We then have to reprocess each
   * protein to set the right fasta file pointer
   */
  std::map<QString, std::vector<ProteinXtpSp>> m_searchDatabase_ref2proteinList;
};
