/**
 * \file src/input/mzidentml/mzidentmlsaxhandler.h
 * \date 14/11/2020
 * \author Olivier Langella
 * \brief parse mzIdentML result file
 */


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


#pragma once

#include <QXmlDefaultHandler>
#include <pappsomspp/pappsoexception.h>
#include "../../core/proteinxtp.h"
#include "../../core/peptidextp.h"
#include <pappsomspp/amino_acid/aamodification.h>
#include "../../core/project.h"
#include "../../core/proteinmatch.h"

class MzIdentMlSaxHandler : public QXmlDefaultHandler
{
  public:
  MzIdentMlSaxHandler(Project *p_project,
                      IdentificationGroup *p_identification_group,
                      IdentificationDataSource *p_identification_data_source);
  ~MzIdentMlSaxHandler();

  bool startElement(const QString &namespaceURI,
                    const QString &localName,
                    const QString &qName,
                    const QXmlAttributes &attributes);

  bool endElement(const QString &namespaceURI,
                  const QString &localName,
                  const QString &qName);

  bool startDocument();

  bool endDocument();

  bool characters(const QString &str);

  bool fatalError(const QXmlParseException &exception);
  bool error(const QXmlParseException &exception);

  QString errorString() const;

  IdentificationEngine getIdentificationEngine() const;

  private:
  bool startElement_AnalysisSoftware(QXmlAttributes attrs);
  bool startElement_DBSequence(QXmlAttributes attrs);
  bool startElement_cvParam(QXmlAttributes attributes);
  bool startElement_userParam(QXmlAttributes attributes);
  bool startElement_Peptide(QXmlAttributes attributes);
  bool startElement_Modification(QXmlAttributes attributes);
  bool startElement_PeptideEvidence(QXmlAttributes attributes);
  bool startElement_SearchDatabase(QXmlAttributes attributes);
  bool startElement_SpectraData(QXmlAttributes attributes);
  bool startElement_SpectrumIdentificationResult(QXmlAttributes attributes);
  bool startElement_SpectrumIdentificationItem(QXmlAttributes attributes);
  bool startElement_PeptideEvidenceRef(QXmlAttributes attributes);


  bool endElement_cvParam();
  bool endElement_userParam();
  bool endElement_PeptideSequence();
  bool endElement_Peptide();
  bool endElement_Modification();
  bool endElement_SpectrumIdentificationResult();
  bool endElement_AnalysisSoftware();
  bool endElement_Seq();


  private:
  std::vector<QString> m_tagStack;
  QString m_errorStr;
  QString m_currentText;

  Project *mp_project;
  IdentificationGroup *mp_identificationGroup;
  IdentificationDataSource *mp_identificationDataSource;
  MsRunSp msp_msrun;

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

  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 SpectrumIdentificationItem
  {
    unsigned int chargeState;
    double experimentalMassToCharge;
    double calculatedMassToCharge;
    PeptideXtpSp peptide;
    std::vector<MzidPeptideEvidence> mzidPeptideEvidenceList;

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


  bool processSpectrumIdentificationItem(
    const SpectrumIdentificationItem &spectrumIdentificationItem);

  struct SpectrumIdentificationResult
  {
    QString id;
    QString spectrumID;
    MsRunSp msrun;
    std::size_t scanNum;
    std::size_t spectrumIndex;
    double retentionTime;
    std::vector<SpectrumIdentificationItem> spectrumIdentificationItemList;

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


  SpectrumIdentificationResult m_currentSpectrumIdentificationResult;

  CvParam m_currentCvParam;
  UserParam m_currentUserParam;

  ProteinXtpSp m_currentProtein;
  PeptideXtpSp m_currentPeptide;
  QString m_currentPeptideXmlId;

  Modification m_currentModification;

  /** @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 store association between xml ID and an identification engine
   */
  std::map<QString, IdentificationEngine> m_IdentificationEngineMap;


  /** @brief stores the current analysis software id
   */
  QString m_currentAnalysisSoftwareId;

  /** @brief tells if the software name has been found and is handled by the
   * parser
   */
  IdentificationEngine m_analysisSotwareNameFound =
    IdentificationEngine::unknown;
};

