/**
 * \file src/input/mzidentml/mzidentmlreader.cpp
 * \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/>.
 *
 ******************************************************************************/

#include "mzidentmlreader.h"
#include "pappsomspp/core/utils.h"
#include "pappsomspp/core/psm/deepprot/deepprotenum.h"


#include "pappsomspp/core/exception/exceptionnotfound.h"
#include "pappsomspp/core/exception/exceptioninterrupted.h"
#include "pappsomspp/core/exception/exceptionnotrecognized.h"
#include <QDebug>
#include <memory>


namespace pappso
{
namespace cbor
{
namespace psm
{
QString
MzIdentMlReader::CvParam::toString() const
{
  return QString("%1 %2 %3 %4").arg(cvRef).arg(accession).arg(name).arg(value);
}


QString
MzIdentMlReader::UserParam::toString() const
{
  return QString("%1 %2").arg(name).arg(value);
}


MzIdentMlReader::MzIdentMlReader(pappso::UiMonitorInterface *p_monitor,
                                 pappso::cbor::CborStreamWriter *p_output,
                                 const QFileInfo &mzident_file)
{

  mp_monitor = p_monitor;
  qDebug() << mzident_file.absoluteFilePath() << "'";
  m_identificationEngine = IdentificationEngine::unknown;
  m_mzidentFile          = mzident_file;


  try
    {

      mp_cborWriter = p_output;

      mp_cborWriter->startMap();
      mp_cborWriter->writeInformations(
        "mzidentml_file_reader", Utils::getVersion(), "psm", "mzidentml reader");


      if(!readFile(mzident_file.absoluteFilePath()))
        {

          if(errorString() == "Not an MzIdentML file")
            {
              throw pappso::ExceptionNotRecognized(
                QObject::tr("Error reading %1 not mzIdentML file :\n %2")
                  .arg(mzident_file.absoluteFilePath())
                  .arg(errorString()));
            }
          else
            {
              throw pappso::PappsoException(QObject::tr("Error reading %1 mzIdentML file :\n %2")
                                              .arg(mzident_file.absoluteFilePath())
                                              .arg(errorString()));
            }
        }


      mp_cborWriter->endMap();
    }
  catch(pappso::ExceptionNotRecognized &err)
    {
      throw err;
    }
  catch(pappso::PappsoException &other_err)
    {
      throw pappso::PappsoException(QObject::tr("Error reading mzIdentML file %1:\n%2")
                                      .arg(mzident_file.absoluteFilePath())
                                      .arg(other_err.qwhat()));
    }
}

MzIdentMlReader::~MzIdentMlReader()
{
}


void
MzIdentMlReader::finalDebrief()
{
  qDebug();
  mp_cborWriter->append("parameter_map");
  mp_cborWriter->writeCborMap(m_cborParameterMap);

  QStringList fasta_files;
  for(auto &pair_searchdb : m_mzidSearchDatabaseIdMap)
    {
      fasta_files << pair_searchdb.second.file;
    }
  mp_cborWriter->append("target_fasta_files");
  mp_cborWriter->writeArray(fasta_files);


  for(std::pair<const QString, MzidDBSequence> &pair_sequence : m_MzidDBSequenceIdMap)
    {
      PsmProtein psm_protein;

      psm_protein.isContaminant = false;
      psm_protein.isTarget      = !pair_sequence.second.is_decoy;
      psm_protein.protein_sp    = pair_sequence.second.protein_sp;

      m_proteinMap.insert(psm_protein);
    }

  mp_cborWriter->append(QString("protein_map"));
  m_proteinMap.writeMap(*mp_cborWriter);

  mp_cborWriter->append("sample_list");
  mp_cborWriter->startArray();
  for(std::pair<const QString, std::vector<SpectrumIdentificationResult>> &pair_spectra :
      m_spectrumIdentificationResultBySpectraIdMap)
    {

      mp_cborWriter->startMap();
      mp_cborWriter->append("name");
      mp_cborWriter->append(m_mzidSpectraDataIdMap.at(pair_spectra.first).name);

      mp_cborWriter->append("identification_file_list");
      mp_cborWriter->startMap();
      mp_cborWriter->append("name");
      mp_cborWriter->append(m_mzidentFile.absoluteFilePath());
      mp_cborWriter->endMap();
      //  one_sample.cbor_core_sample.value("identification_file_list")
      //  .toCbor(m_sageReader.getCborStreamWriter());


      mp_cborWriter->append("peaklist_file");
      mp_cborWriter->startMap();
      mp_cborWriter->append("name");
      mp_cborWriter->append(m_mzidSpectraDataIdMap.at(pair_spectra.first).file);
      mp_cborWriter->endMap();
      //"scan_list": [

      mp_cborWriter->append("scan_list");
      mp_cborWriter->startArray(pair_spectra.second.size());
      for(SpectrumIdentificationResult &it_spectrum_ident : pair_spectra.second)
        {
          writeSpectrumIdentificationResult(it_spectrum_ident);
        }
      mp_cborWriter->endArray();


      mp_cborWriter->endMap();
    }

  mp_cborWriter->endArray();
  qDebug();
}

void
MzIdentMlReader::readStream()
{
  // mp_monitor->setStatus("reading X!Tandem result file");
  if(m_qxmlStreamReader.readNextStartElement())
    {

      qDebug() << m_qxmlStreamReader.name().toString();
      if(m_qxmlStreamReader.name().toString().toLower() == "mzidentml")
        {
          while(m_qxmlStreamReader.readNextStartElement())
            {
              // cvList
              if(m_qxmlStreamReader.name().toString() == "cvList")
                {
                  m_qxmlStreamReader.skipCurrentElement();
                }
              // AnalysisSoftwareList
              else if(m_qxmlStreamReader.name().toString() == "AnalysisSoftwareList")
                {
                  while(readAnalysisSoftware())
                    {
                    }
                } // Provider
              else if(m_qxmlStreamReader.name().toString() == "Provider")
                {
                  m_qxmlStreamReader.skipCurrentElement();
                }
              // AuditCollection
              else if(m_qxmlStreamReader.name().toString() == "AuditCollection")
                {
                  m_qxmlStreamReader.skipCurrentElement();
                }
              // SequenceCollection
              else if(m_qxmlStreamReader.name().toString() == "SequenceCollection")
                {
                  while(readSequenceCollectionItem())
                    {
                    }
                }
              // AnalysisCollection
              else if(m_qxmlStreamReader.name().toString() == "AnalysisCollection")
                {
                  while(readAnalysisCollectionItem())
                    {
                    }
                }
              // AnalysisProtocolCollection
              else if(m_qxmlStreamReader.name().toString() == "AnalysisProtocolCollection")
                {
                  readAnalysisProtocolCollection();
                }

              // DataCollection
              else if(m_qxmlStreamReader.name().toString() == "DataCollection")
                {
                  while(readDataCollectionItem())
                    {
                    }
                }
              else if(m_qxmlStreamReader.name().toString() == "BibliographicReference")
                {
                  m_qxmlStreamReader.skipCurrentElement();
                }

              else
                {
                  m_qxmlStreamReader.raiseError(
                    QObject::tr("element %1 not implemented").arg(m_qxmlStreamReader.name()));
                  m_qxmlStreamReader.skipCurrentElement();
                }
            }
        }
      else
        {
          m_qxmlStreamReader.raiseError(QObject::tr("Not an MzIdentML input file"));
          m_qxmlStreamReader.skipCurrentElement();
        }
    }
}


void
MzIdentMlReader::readAnalysisProtocolCollection()
{
  //<AnalysisProtocolCollection>

  qDebug();
  while(m_qxmlStreamReader.readNextStartElement())
    {
      qDebug() << m_qxmlStreamReader.name();
      if(m_qxmlStreamReader.name().toString() == "SpectrumIdentificationProtocol")
        {
          auto it_soft = m_IdentificationEngineMap.find(
            m_qxmlStreamReader.attributes().value("analysisSoftware_ref").toString());
          if(it_soft != m_IdentificationEngineMap.end())
            {
              IdentificationEngine identification_engine = it_soft->second;

              if(identification_engine == IdentificationEngine::XTandem)
                {
                  //<SpectrumIdentificationProtocol analysisSoftware_ref="ID_software"
                  // id="SearchProtocol_1">
                  QCborMap identification_engine_parameters;

                  while(m_qxmlStreamReader.readNextStartElement())
                    {
                      if(m_qxmlStreamReader.name().toString() == "SearchType")
                        {
                          m_qxmlStreamReader.skipCurrentElement();
                        }
                      else if(m_qxmlStreamReader.name().toString() == "ModificationParams")
                        {
                          m_qxmlStreamReader.skipCurrentElement();
                        }

                      else if(m_qxmlStreamReader.name().toString() == "Threshold")
                        {
                          m_qxmlStreamReader.skipCurrentElement();
                        }
                      else if(m_qxmlStreamReader.name().toString() == "ParentTolerance")
                        {
                          m_qxmlStreamReader.skipCurrentElement();
                        }
                      else if(m_qxmlStreamReader.name().toString() == "FragmentTolerance")
                        {
                          m_qxmlStreamReader.skipCurrentElement();
                        }
                      else if(m_qxmlStreamReader.name().toString() == "Enzymes")
                        {
                          m_qxmlStreamReader.skipCurrentElement();
                        }
                      else if(m_qxmlStreamReader.name().toString() == "AdditionalSearchParams")
                        {
                          while(m_qxmlStreamReader.readNextStartElement())
                            {
                              if(m_qxmlStreamReader.name().toString() == "userParam")
                                {
                                  //<userParam name="list path, default parameters"
                                  // value="/tmp/i2masschroq.ubFSuT/QExactive_analysis_FDR_nosemi.xml"/>
                                  identification_engine_parameters.insert(
                                    m_qxmlStreamReader.attributes().value("name").toString(),
                                    m_qxmlStreamReader.attributes().value("value").toString());
                                  m_qxmlStreamReader.skipCurrentElement();
                                }
                              else
                                {
                                  m_qxmlStreamReader.skipCurrentElement();
                                }
                            }
                        }
                      else
                        {

                          m_qxmlStreamReader.raiseError(QObject::tr("element %1 not implemented")
                                                          .arg(m_qxmlStreamReader.name()));
                          m_qxmlStreamReader.skipCurrentElement();
                        }
                    }

                  m_cborParameterMap.insert(QString("xtandem"),
                                            identification_engine_parameters.toCborValue());
                  //  qWarning() << "coucou";
                }
              else
                {
                  // other than tandem
                  m_qxmlStreamReader.skipCurrentElement();
                }
            }
          else
            {
              m_qxmlStreamReader.skipCurrentElement();
            }
        }
      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("element %1 not implemented").arg(m_qxmlStreamReader.name()));
          m_qxmlStreamReader.skipCurrentElement();
        }
    }
  qDebug();
}

bool
MzIdentMlReader::readAnalysisSoftware()
{


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


  /** @brief tells if the software name has been found and is handled by the
   * parser
   */
  IdentificationEngine analysisSotwareNameFound = IdentificationEngine::unknown;
  if(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "AnalysisSoftware")
        {

          // <AnalysisSoftware version="0.0.9" name="DeepProt" id="as1">


          analysisSoftwareId    = m_qxmlStreamReader.attributes().value("id").toString();
          QString software_name = m_qxmlStreamReader.attributes().value("name").toString();


          m_analysisSoftwareVersion = m_qxmlStreamReader.attributes().value("version").toString();

          if(software_name == "SpecOMS")
            {
              analysisSotwareNameFound = IdentificationEngine::SpecOMS;

              m_qxmlStreamReader.skipCurrentElement();
            }
          else if(software_name == "DeepProt")
            {
              analysisSotwareNameFound = IdentificationEngine::SpecOMS;

              m_qxmlStreamReader.skipCurrentElement();
            }
          else
            {
              while(m_qxmlStreamReader.readNextStartElement())
                {
                  if(m_qxmlStreamReader.name().toString() == "SoftwareName")
                    {
                      while(m_qxmlStreamReader.readNextStartElement())
                        {
                          if(m_qxmlStreamReader.name().toString() == "cvParam")
                            {
                              CvParam cv_param = readCvParam();
                              if(cv_param.accession == "MS:1001476")
                                {
                                  analysisSotwareNameFound = IdentificationEngine::XTandem;
                                }
                              else if(cv_param.accession == "MS:1002048")
                                {
                                  analysisSotwareNameFound = IdentificationEngine::MSGFplus;
                                }
                              else if(cv_param.accession == "MS:1001946")
                                {
                                  analysisSotwareNameFound = IdentificationEngine::PEAKS_Studio;
                                }
                            }
                        }
                    }
                  else
                    {
                      m_qxmlStreamReader.skipCurrentElement();
                    }
                }
            }


          switch(analysisSotwareNameFound)
            {
              case IdentificationEngine::SpecOMS:
                break;
              case IdentificationEngine::MSGFplus:
                break;
              case IdentificationEngine::XTandem:
                break;
              case IdentificationEngine::PEAKS_Studio:
                break;

              default:
                m_qxmlStreamReader.raiseError(
                  QObject::tr("identification results from %1 are not supported yet, "
                              "Please contact "
                              "the PAPPSO team.")
                    .arg(software_name));
                return false;
            }


          auto it = m_IdentificationEngineMap.insert(
            std::pair<QString, IdentificationEngine>(analysisSoftwareId, analysisSotwareNameFound));

          if(it.second == false)
            {
              it.first->second = analysisSotwareNameFound;
            }
        }
      else
        {
          m_qxmlStreamReader.raiseError(QObject::tr("Not an MzIdentML input file"));
          m_qxmlStreamReader.skipCurrentElement();
          return false;
        }
      return true;
    }
  return false;
}

bool
MzIdentMlReader::readSequenceCollectionItem()
{
  if(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "DBSequence")
        {
          readDBSequence();
        }
      else if(m_qxmlStreamReader.name().toString() == "Peptide")
        {
          readPeptide();
        }
      // PeptideEvidence
      else if(m_qxmlStreamReader.name().toString() == "PeptideEvidence")
        {
          readPeptideEvidence();
        }
      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in MzIdentML input file, %1 no DBSequence")
              .arg(m_qxmlStreamReader.name()));
          m_qxmlStreamReader.skipCurrentElement();
          return false;
        }
      return true;
    }
  return false;
}

void
MzIdentMlReader::readDBSequence()
{

  // attributes.value("base_name")
  // ProteinXtpSp sp_xtp_protein = _current_protein.makeProteinXtpSp();
  MzidDBSequence dbsequence;
  dbsequence.is_decoy  = false;
  dbsequence.accession = m_qxmlStreamReader.attributes().value("accession").toString();

  QString accession_description = dbsequence.accession;
  dbsequence.searchDatabase_ref =
    m_qxmlStreamReader.attributes().value("searchDatabase_ref").toString();

  QString id = m_qxmlStreamReader.attributes().value("id").toString();


  while(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "cvParam")
        {
          CvParam cv_param = readCvParam();


          if(cv_param.accession == "MS:1001088")
            {
              // protein description
              // protein.get()->setDescription(cv_param.value);
              dbsequence.description = cv_param.value;
              accession_description.append(" ").append(dbsequence.description);
            }
          else if(cv_param.accession == "MS:1001195")
            {
              // PSI-MS MS:1001195 decoy DB type reverse
              // protein.get()->setIsDecoy(true);
              dbsequence.is_decoy = true;
            }
          else
            {
              dbsequence.cvParamList.push_back(cv_param);
            }
        }
      else if(m_qxmlStreamReader.name().toString().toLower() == "seq")
        {


          dbsequence.sequence = m_qxmlStreamReader.readElementText();
        }
      else
        {

          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in MzIdentML/DBSequence unexpected %1 tag")
              .arg(m_qxmlStreamReader.name()));
          m_qxmlStreamReader.skipCurrentElement();
        }
    }


  // qWarning() << accession_description;
  dbsequence.protein_sp = std::make_shared<Protein>(accession_description, dbsequence.sequence);

  m_MzidDBSequenceIdMap.insert({id, dbsequence});
  // searchDatabase_ref="SearchDB_1"

  // protein.get()->setFastaFileP(fastaFile.get());
}

MzIdentMlReader::CvParam
MzIdentMlReader::readCvParam()
{
  CvParam cv_param;
  cv_param.cvRef         = m_qxmlStreamReader.attributes().value("cvRef").toString();
  cv_param.accession     = m_qxmlStreamReader.attributes().value("accession").toString();
  cv_param.name          = m_qxmlStreamReader.attributes().value("name").toString();
  cv_param.value         = m_qxmlStreamReader.attributes().value("value").toString();
  cv_param.unitAccession = m_qxmlStreamReader.attributes().value("unitAccession").toString();
  cv_param.unitName      = m_qxmlStreamReader.attributes().value("unitName").toString();
  cv_param.unitCvRef     = m_qxmlStreamReader.attributes().value("unitCvRef").toString();
  m_qxmlStreamReader.skipCurrentElement();
  return cv_param;
}

MzIdentMlReader::UserParam
MzIdentMlReader::readUserParam()
{
  UserParam user_param;

  user_param.name  = m_qxmlStreamReader.attributes().value("name").toString();
  user_param.value = m_qxmlStreamReader.attributes().value("value").toString();
  m_qxmlStreamReader.skipCurrentElement();

  return user_param;
}


void
MzIdentMlReader::readPeptide()
{
  std::shared_ptr<pappso::Peptide> peptide_sp;

  QString xml_id = m_qxmlStreamReader.attributes().value("id").toString();

  // PeptideSequence
  if(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "PeptideSequence")
        {
          peptide_sp = std::make_shared<Peptide>(m_qxmlStreamReader.readElementText().simplified());
        }
      else
        {

          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in MzIdentML/Peptide no PeptideSequence"));
        }
    }

  while(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "Modification")
        {
          //      <Modification monoisotopicMassDelta="-0.02682025649"
          //      location="1">
          //          <cvParam accession="-0.0268203" cvRef="PSI-MOD" name=""/>
          //      </Modification>

          Modification modification;
          modification.monoisotopicMassDelta =
            m_qxmlStreamReader.attributes().value("monoisotopicMassDelta").toDouble();
          modification.location = m_qxmlStreamReader.attributes().value("location").toUInt();
          bool is_cv_param      = false;
          while(m_qxmlStreamReader.readNextStartElement())
            {
              if(m_qxmlStreamReader.name().toString() == "cvParam")
                {
                  is_cv_param          = true;
                  modification.cvParam = readCvParam();


                  // qDebug() << "startElement_aa ";
                  pappso::AaModificationP modif = nullptr;


                  qDebug() << modification.monoisotopicMassDelta;
                  if(modification.cvParam.accession != "")
                    {
                      qDebug() << modification.cvParam.accession;
                      if(modification.cvParam.accession.startsWith("UNIMOD:"))
                        {
                          modif = pappso::Utils::translateAaModificationFromUnimod(
                            modification.cvParam.accession);
                        }
                      else
                        {
                          // hope it is psi mod:
                          if(modification.cvParam.accession.startsWith("MOD:"))
                            {
                              modif =
                                pappso::AaModification::getInstance(modification.cvParam.accession);
                            }
                          else if(modification.cvParam.accession == "MS:1001460")
                            {
                              //[Term]
                              // id: MS:1001460
                              // name: unknown modification
                              // def: "This term should be given if the
                              // modification was unknown." [PSI:PI] is_a:
                              // MS:1001471 ! peptide modification details
                              modif = pappso::AaModification::getInstanceCustomizedMod(
                                modification.monoisotopicMassDelta);
                            }
                          else
                            {
                              qInfo() << "MzIdentMlSaxHandler::endElement_"
                                         "Modification unknown "
                                         "modification "
                                      << modification.cvParam.accession << " "
                                      << modification.cvParam.name;
                            }
                        }
                    }

                  if(modif == nullptr)
                    {
                      m_qxmlStreamReader.raiseError(
                        QObject::tr("Error in MzIdentML/Peptide/Modification/cvParam "
                                    "modification accession %1 not found")
                          .arg(modification.cvParam.accession));
                      return;
                    }

                  if(modification.location == 0)
                    {
                      peptide_sp.get()->addAaModification(modif, 0);
                    }
                  else
                    {
                      peptide_sp.get()->addAaModification(modif, modification.location - 1);
                    }
                }
              else
                {

                  m_qxmlStreamReader.raiseError(
                    QObject::tr("Error in MzIdentML/Peptide/Modification "
                                "unexpected %1 tag")
                      .arg(m_qxmlStreamReader.name()));
                }
            }

          if(is_cv_param == false)
            {
              pappso::AaModificationP modif_without_cvparam = nullptr;
              // no cv param element

              if(modification.location == 0)
                {
                  modif_without_cvparam =
                    pappso::Utils::guessAaModificationPbyMonoisotopicMassDelta(
                      peptide_sp.get()->getAa(0).getAminoAcidChar(),
                      modification.monoisotopicMassDelta);
                  peptide_sp.get()->addAaModification(modif_without_cvparam, 0);
                }
              else
                {
                  modif_without_cvparam =
                    pappso::Utils::guessAaModificationPbyMonoisotopicMassDelta(
                      peptide_sp.get()->getAa(modification.location - 1).getAminoAcidChar(),
                      modification.monoisotopicMassDelta);
                  peptide_sp.get()->addAaModification(modif_without_cvparam,
                                                      modification.location - 1);
                }
            }
        }

      else
        {

          m_qxmlStreamReader.raiseError(QObject::tr("Error in MzIdentML/Peptide unexpected %1 tag")
                                          .arg(m_qxmlStreamReader.name()));
        }
    }


  m_PeptideIdMap.insert(std::pair<QString, PeptideSp>(xml_id, peptide_sp));
}

bool
MzIdentMlReader::readPeptideEvidence()
{
  qDebug();
  MzidPeptideEvidence pe;

  auto itprot =
    m_MzidDBSequenceIdMap.find(m_qxmlStreamReader.attributes().value("dBSequence_ref").toString());
  if(itprot == m_MzidDBSequenceIdMap.end())
    {
      m_qxmlStreamReader.raiseError(
        QObject::tr("dBSequence_ref %1 not defined")
          .arg(m_qxmlStreamReader.attributes().value("dBSequence_ref").toString()));
      return false;
    }
  qDebug();
  pe.protein = itprot->second.protein_sp;


  auto itpep = m_PeptideIdMap.find(m_qxmlStreamReader.attributes().value("peptide_ref").toString());
  if(itpep == m_PeptideIdMap.end())
    {
      m_qxmlStreamReader.raiseError(
        QObject::tr("peptide_ref %1 not defined")
          .arg(m_qxmlStreamReader.attributes().value("peptide_ref").toString()));
      return false;
    }
  qDebug();
  pe.peptide = itpep->second;

  pe.start   = m_qxmlStreamReader.attributes().value("start").toUInt() - 1;
  pe.end     = m_qxmlStreamReader.attributes().value("end").toUInt() - 1;
  pe.isDecoy = false;
  if(m_qxmlStreamReader.attributes().value("isDecoy").toString() == "true")
    {
      pe.isDecoy = true;
    }
  qDebug();
  m_MzidPeptideEvidenceIdMap.insert(std::pair<QString, MzidPeptideEvidence>(
    m_qxmlStreamReader.attributes().value("id").toString(), pe));
  m_qxmlStreamReader.skipCurrentElement();
  qDebug();
  return true;
}

bool
MzIdentMlReader::readAnalysisCollectionItem()
{

  qDebug();
  if(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "SpectrumIdentification")
        {
          readSpectrumIdentification();
          qDebug();
        }
      else if(m_qxmlStreamReader.name().toString() == "ProteinDetection")
        {
          m_qxmlStreamReader.skipCurrentElement();
        }
      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in MzIdentML/AnalysisCollection, unexpected %1 t")
              .arg(m_qxmlStreamReader.name()));
          m_qxmlStreamReader.skipCurrentElement();
          return false;
        }
      return true;
    }
  return false;
}

void
MzIdentMlReader::readSpectrumIdentification()
{

  m_qxmlStreamReader.skipCurrentElement();
}

bool
MzIdentMlReader::readDataCollectionItem()
{

  qDebug();
  if(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "Inputs")
        {
          readInputs();
        }

      // AnalysisData
      else if(m_qxmlStreamReader.name().toString() == "AnalysisData")
        {
          qDebug();
          readAnalysisData();
        }
      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in MzIdentML/DataCollection, unexpected %1 tag")
              .arg(m_qxmlStreamReader.name()));
          m_qxmlStreamReader.skipCurrentElement();
          return false;
        }
      return true;
    }
  return false;
}

void
MzIdentMlReader::readInputs()
{
  while(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "SearchDatabase")
        {
          readSearchDatabase();
        }
      else if(m_qxmlStreamReader.name().toString() == "SpectraData")
        {
          readSpectraData();
        }
      else if(m_qxmlStreamReader.name().toString() == "SourceFile")
        {
          m_qxmlStreamReader.skipCurrentElement();
        }

      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in MzIdentML/DataCollection/Inputs, unexpected %1 tag")
              .arg(m_qxmlStreamReader.name()));
          m_qxmlStreamReader.skipCurrentElement();
        }
    }
}


//<SearchDatabase numDatabaseSequences="136828"
// location="/home/thierry/test/MS-GF+/Genome_Z_mays_v5a_conta.fasta"
// id="SearchDB_1">
//      <FileFormat>
//        <cvParam cvRef="PSI-MS" accession="MS:1001348" name="FASTA format"/>
//      </FileFormat>
//      <DatabaseName>
//        <userParam name="Genome_Z_mays_v5a_conta.fasta"/>
//      </DatabaseName>
//    </SearchDatabase>
bool
MzIdentMlReader::readSearchDatabase()
{
  /* <SearchDatabase
     location="/gorgone/pappso/versions_logiciels_pappso/tandemng/database/Genome_Z_mays_5a.fasta"
     id="SearchDB_0"> <FileFormat> <cvParam accession="MS:1001348" cvRef="PSI-MS" name="FASTA
     format"/>
                  </FileFormat>
                  <DatabaseName>
                      <userParam name="DatabaseName" value="Genome_Z_mays_5a.fasta"/>
                  </DatabaseName>
                  <cvParam accession="MS:1001197" cvRef="PSI-MS" name="DB composition
     target+decoy"/> <cvParam accession="MS: 1001283" cvRef="PSI-MS" name="decoy DB accession
     regexp" value="^XXX"/> <cvParam accession="MS: 1001195" cvRef="PSI-MS" name="decoy DB type
     reverse"/>
              </SearchDatabase>
              */
  qDebug();
  QString id = m_qxmlStreamReader.attributes().value("id").toString();
  // auto itfasta = m_FastaFileIdMap.find(id);

  MzidSearchDatabase search_database;

  search_database.file = m_qxmlStreamReader.attributes().value("location").toString();


  if(search_database.file.isEmpty())
    {
      m_qxmlStreamReader.raiseError(QObject::tr("SearchDatabase id %1 location is empty").arg(id));
      return false;
    }


  m_mzidSearchDatabaseIdMap.insert({id, search_database});

  m_qxmlStreamReader.skipCurrentElement();
  qDebug();
  return true;
}

void
MzIdentMlReader::readSpectraData()
{

  qDebug();
  MzidSpectraData spectra_data;
  spectra_data.file = m_qxmlStreamReader.attributes().value("location").toString();


  // msrun.get()->setXmlId(attributes.value("id"));
  spectra_data.name = m_qxmlStreamReader.attributes().value("name").toString();


  m_mzidSpectraDataIdMap.insert(std::pair<QString, MzidSpectraData>(
    m_qxmlStreamReader.attributes().value("id").toString(), spectra_data));
  m_qxmlStreamReader.skipCurrentElement();
}

void
MzIdentMlReader::readAnalysisData()
{

  qDebug() << m_qxmlStreamReader.name();
  while(m_qxmlStreamReader.readNextStartElement())
    {
      qDebug() << m_qxmlStreamReader.name();
      if(m_qxmlStreamReader.name().toString() == "SpectrumIdentificationList")
        {
          while(m_qxmlStreamReader.readNextStartElement())
            {
              qDebug() << m_qxmlStreamReader.name();
              if(m_qxmlStreamReader.name().toString() == "SpectrumIdentificationResult")
                {
                  readSpectrumIdentificationResult();
                }
              else if(m_qxmlStreamReader.name().toString() == "FragmentationTable")
                {
                  m_qxmlStreamReader.skipCurrentElement();
                }
              else
                {
                  m_qxmlStreamReader.raiseError(
                    QObject::tr("Error in "
                                "MzIdentML/DataCollection/AnalysisData/"
                                "SpectrumIdentificationList, unexpected %1 tag")
                      .arg(m_qxmlStreamReader.name()));
                  m_qxmlStreamReader.skipCurrentElement();
                }
            }
        }
      else if(m_qxmlStreamReader.name().toString() == "ProteinDetectionList")
        {
          // ProteinDetectionList
          m_qxmlStreamReader.skipCurrentElement();
        }
      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in MzIdentML/DataCollection/AnalysisData, "
                        "unexpected %1 tag")
              .arg(m_qxmlStreamReader.name()));
          m_qxmlStreamReader.skipCurrentElement();
        }
    }
  qDebug();
  finalDebrief();
}

void
MzIdentMlReader::readSpectrumIdentificationResult()
{
  qDebug() << m_qxmlStreamReader.name();

  QString spectra_id   = m_qxmlStreamReader.attributes().value("spectraData_ref").toString();
  auto it_spectra_data = m_mzidSpectraDataIdMap.find(spectra_id);

  if(it_spectra_data == m_mzidSpectraDataIdMap.end())
    {
      m_qxmlStreamReader.raiseError(QObject::tr("spectraData_ref %1 not defined in "
                                                "m_mzidSpectraDataIdMap")
                                      .arg(spectra_id));
    }

  auto it_insert_ident = m_spectrumIdentificationResultBySpectraIdMap.insert({spectra_id, {}});

  it_insert_ident.first->second.push_back({});
  SpectrumIdentificationResult &spectrum_identification_result =
    it_insert_ident.first->second.back();
  spectrum_identification_result.cvParamList.clear();
  spectrum_identification_result.userParamList.clear();
  spectrum_identification_result.spectrumIdentificationItemList.clear();

  spectrum_identification_result.spectrumID =
    m_qxmlStreamReader.attributes().value("spectrumID").toString();
  spectrum_identification_result.id = m_qxmlStreamReader.attributes().value("id").toString();


  qDebug() << m_qxmlStreamReader.name();

  while(m_qxmlStreamReader.readNextStartElement())
    {
      qDebug() << m_qxmlStreamReader.name();
      if(m_qxmlStreamReader.name() == QString("SpectrumIdentificationItem"))
        {
          qDebug();
          readSpectrumIdentificationItem(spectrum_identification_result);
        }
      else if(m_qxmlStreamReader.name() == QString("cvParam"))
        {
          CvParam cv_param = readCvParam();
          qDebug() << cv_param.toString();
          spectrum_identification_result.cvParamList.push_back(cv_param);
        }

      else if(m_qxmlStreamReader.name() == QString("userParam"))
        {
          UserParam user_param = readUserParam();
          qDebug() << user_param.toString();
        }
      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("Error in "
                        "MzIdentML/DataCollection/AnalysisData/"
                        "SpectrumIdentificationList/"
                        "SpectrumIdentificationResult, unexpected %1 tag")
              .arg(m_qxmlStreamReader.name()));
          // m_qxmlStreamReader.skipCurrentElement();
        }
    }

  if(m_qxmlStreamReader.hasError())
    return;
  qDebug() << m_qxmlStreamReader.name();

  // find scan number
  spectrum_identification_result.spectrumIndex   = 0;
  spectrum_identification_result.isSpectrumIndex = false;
  spectrum_identification_result.scanNum         = 0;
  spectrum_identification_result.retentionTime   = 0;

  // spectrumID="index=194"
  if(spectrum_identification_result.spectrumID.startsWith("index="))
    {
      bool is_ok = false;
      spectrum_identification_result.spectrumIndex =
        spectrum_identification_result.spectrumID.mid(6).toULongLong(&is_ok);
      spectrum_identification_result.isSpectrumIndex = true;
      if(!is_ok)
        {
          m_qxmlStreamReader.raiseError(QObject::tr("reading spectrum index failed in %1"
                                                    "SpectrumIdentificationResult id %2")
                                          .arg(spectrum_identification_result.spectrumID)
                                          .arg(spectrum_identification_result.id));
          return;
        }
    }

  //  <cvParam cvRef="PSI-MS" accession="MS:1001115" name="scan number(s)"
  //        value="16079"/>
  for(auto cvParam : spectrum_identification_result.cvParamList)
    {

      qDebug() << cvParam.toString();
      if(cvParam.accession == "MS:1001115")
        {
          spectrum_identification_result.scanNum = cvParam.value.toUInt();
        }
      else if(cvParam.accession == "MS:1003062")
        {
          spectrum_identification_result.isSpectrumIndex = true;
          spectrum_identification_result.spectrumIndex   = cvParam.value.toUInt();
        }
      else if((cvParam.accession == "MS:1000016") || (cvParam.accession == "MS:1000894"))
        {
          //[Term]
          // id: MS:1000894
          // name: retention time
          // def: "A time interval from the start of chromatography when an
          // analyte exits a chromatographic column." [PSI:MS]

          //            [Term]
          // id: MS:1000016
          // name: scan start time
          // def: "The time that an analyzer started a scan, relative to the
          // start of the MS run." [PSI:MS]


          spectrum_identification_result.retentionTime = cvParam.value.toDouble();
        }
    }
  if((spectrum_identification_result.scanNum == 0) &&
     (spectrum_identification_result.isSpectrumIndex == false))
    {
      m_qxmlStreamReader.raiseError(QObject::tr("scan number or spectrum index not found in "
                                                "SpectrumIdentificationResult id %1")
                                      .arg(spectrum_identification_result.id));
    }


  if(spectrum_identification_result.retentionTime == 0)
    {
      m_qxmlStreamReader.raiseError(
        QObject::tr("retention time not found in SpectrumIdentificationResult id %1")
          .arg(spectrum_identification_result.id));
    }


  for(auto spectrumIdentificationItem :
      spectrum_identification_result.spectrumIdentificationItemList)
    {
      // processSpectrumIdentificationItem(spectrum_identification_result,
      // spectrumIdentificationItem);
    }
}

void
MzIdentMlReader::readSpectrumIdentificationItem(
  MzIdentMlReader::SpectrumIdentificationResult &spectrum_identification_result)
{

  qDebug();
  spectrum_identification_result.spectrumIdentificationItemList.push_back(
    SpectrumIdentificationItem());
  spectrum_identification_result.spectrumIdentificationItemList.back()
    .mzidPeptideEvidenceList.clear();
  spectrum_identification_result.spectrumIdentificationItemList.back().cvParamList.clear();
  spectrum_identification_result.spectrumIdentificationItemList.back().userParamList.clear();

  spectrum_identification_result.spectrumIdentificationItemList.back().chargeState =
    m_qxmlStreamReader.attributes().value("chargeState").toUInt();

  spectrum_identification_result.spectrumIdentificationItemList.back().experimentalMassToCharge =
    m_qxmlStreamReader.attributes().value("experimentalMassToCharge").toDouble();


  auto itpeptide =
    m_PeptideIdMap.find(m_qxmlStreamReader.attributes().value("peptide_ref").toString());

  if(itpeptide == m_PeptideIdMap.end())
    {
      m_qxmlStreamReader.raiseError(QObject::tr("peptide_ref %1 not defined")
                                      .arg(m_qxmlStreamReader.attributes().value("peptide_ref")));
    }
  spectrum_identification_result.spectrumIdentificationItemList.back().peptide = itpeptide->second;


  while(m_qxmlStreamReader.readNextStartElement())
    {
      qDebug() << m_qxmlStreamReader.name();
      if(m_qxmlStreamReader.name() == QString("PeptideEvidenceRef"))
        {

          auto itpeptideEvidence = m_MzidPeptideEvidenceIdMap.find(
            m_qxmlStreamReader.attributes().value("peptideEvidence_ref").toString());

          if(itpeptideEvidence == m_MzidPeptideEvidenceIdMap.end())
            {
              m_qxmlStreamReader.raiseError(
                QObject::tr("peptideEvidence_ref %1 not defined")
                  .arg(m_qxmlStreamReader.attributes().value("peptideEvidence_ref")));
            }

          spectrum_identification_result.spectrumIdentificationItemList.back()
            .mzidPeptideEvidenceList.push_back(itpeptideEvidence->second);
          m_qxmlStreamReader.skipCurrentElement();
        }
      else if(m_qxmlStreamReader.name() == QString("cvParam"))
        {
          spectrum_identification_result.spectrumIdentificationItemList.back()
            .cvParamList.push_back(readCvParam());
          qDebug() << spectrum_identification_result.spectrumIdentificationItemList.back()
                        .cvParamList.back()
                        .toString();
        }
      else if(m_qxmlStreamReader.name() == QString("userParam"))
        {
          UserParam user_param = readUserParam();
          spectrum_identification_result.spectrumIdentificationItemList.back()
            .userParamList.push_back(user_param);
          qDebug() << user_param.toString();
        }
      else
        {
          m_qxmlStreamReader.raiseError(QObject::tr("Error in "
                                                    "MzIdentML/DataCollection/AnalysisData/"
                                                    "SpectrumIdentificationList/"
                                                    "SpectrumIdentificationResult/"
                                                    "SpectrumIdentificationItem, unexpected %1 tag")
                                          .arg(m_qxmlStreamReader.name()));
        }
    }
  qDebug();
}
/*
void
MzIdentMlReader::processSpectrumIdentificationItem(
  SpectrumIdentificationResult &spectrum_identification_result,
  const SpectrumIdentificationItem &spectrumIdentificationItem)
{


  qDebug();

  if(spectrum_identification_result.isSpectrumIndex)
    {
      spectrum_identification_result.scanNum = spectrum_identification_result.spectrumIndex;
    }
  PeptideEvidence peptide_evidence(
    spectrum_identification_result.mzident_source_sp.get()->getMsRunSp().get(),
    spectrum_identification_result.scanNum,
    spectrum_identification_result.isSpectrumIndex);
  peptide_evidence.setRetentionTime(spectrum_identification_result.retentionTime);
  peptide_evidence.setCharge(spectrumIdentificationItem.chargeState);
  peptide_evidence.setPeptideXtpSp(spectrumIdentificationItem.peptide);
  qDebug() << peptide_evidence.getPeptideXtpSp().get()->toAbsoluteString();
  peptide_evidence.setChecked(true);
  peptide_evidence.setIdentificationDataSource(
    spectrum_identification_result.mzident_source_sp.get());
  peptide_evidence.setIdentificationEngine(getIdentificationEngine());

  peptide_evidence.setExperimentalMassToCharge(spectrumIdentificationItem.experimentalMassToCharge);

  qDebug();

  //          <cvParam cvRef="PSI-MS" accession="MS:1002049"
  //          name="MS-GF:RawScore" value="356"/> <cvParam cvRef="PSI-MS"
  //          accession="MS:1002050" name="MS-GF:DeNovoScore" value="369"/>
  //          <cvParam cvRef="PSI-MS" accession="MS:1002052"
  //          name="MS-GF:SpecEValue" value="9.149361665076834E-40"/> <cvParam
  //          cvRef="PSI-MS" accession="MS:1002053" name="MS-GF:EValue"
  //          value="2.057944235338586E-32"/>
  //         <userParam name="IsotopeError" value="0"/>
  //         <userParam name="AssumedDissociationMethod" value="HCD"/>
  for(auto cvParam : spectrumIdentificationItem.cvParamList)
    {

      //<cvParam accession="MS:1002258" cvRef="PSI-MS" value="7"
      // name="Comet:matched ions"/>
      if(cvParam.accession == "MS:1002049")
        {
          // PSI-MS MS:1002049 MS-GF:RawScore 356
          peptide_evidence.setParam(PeptideEvidenceParam::msgfplus_raw,
                                    QVariant(cvParam.value.toUInt()));
        }
      else if(cvParam.accession == "MS:1002050")
        {
          // msgfplus_denovo     = 9,  ///< MS:1002050  "MS-GF de novo score."
          peptide_evidence.setParam(PeptideEvidenceParam::msgfplus_denovo,
                                    QVariant(cvParam.value.toUInt()));
        }

      else if(cvParam.accession == "MS:1002052")
        {
          peptide_evidence.setParam(PeptideEvidenceParam::msgfplus_SpecEValue,
                                    QVariant(cvParam.value.toDouble()));
        }

      else if(cvParam.accession == "MS:1002053")
        {
          // PSI-MS MS:1002053 MS-GF:EValue
          peptide_evidence.setParam(PeptideEvidenceParam::msgfplus_EValue,
                                    QVariant(cvParam.value.toDouble()));
        }

      else if(cvParam.accession == "MS:1002054")
        {
          // <cvParam cvRef="PSI-MS" accession="MS:1002054" name="MS-GF:QValue"
          // value="0.0"/>
          peptide_evidence.setParam(PeptideEvidenceParam::msgfplus_QValue,
                                    QVariant(cvParam.value.toDouble()));
        }
      else if(cvParam.accession == "MS:1002055")
        {
          //  <cvParam cvRef="PSI-MS" accession="MS:1002055"
          //  name="MS-GF:PepQValue" value="0.0"/>
          peptide_evidence.setParam(PeptideEvidenceParam::msgfplus_PepQValue,
                                    QVariant(cvParam.value.toDouble()));
        }
      else if(cvParam.accession == "MS:1001331")
        {
          // PSI-MS MS:1001331 tandem hyperscore
          peptide_evidence.setParam(PeptideEvidenceParam::tandem_hyperscore,
                                    QVariant(cvParam.value.toDouble()));
        }
      else if(cvParam.accession == "MS:1001330")
        {
          // PSI-MS MS:1001330 X!Tandem:expect
          peptide_evidence.setParam(PeptideEvidenceParam::tandem_expectation_value,
                                    QVariant(cvParam.value.toDouble()));
          peptide_evidence.setEvalue(cvParam.value.toDouble());
        }
      else if(cvParam.accession == "MS:1001950")
        {
          //<cvParam accession="MS:1001950" cvRef="PSI-MS" value="54.90"
          // name="PEAKS:peptideScore"/>

          peptide_evidence.setParam(PeptideEvidenceParam::peaks_peptide_score,
                                    QVariant(cvParam.value.toDouble()));
        }

      //msgfplus_energy     = 10, ///< MS:1002051  "MS-GF energy score." [PSI:PI]
      //msgfplus_SpecEValue = 11, ///< MS:1002052  "MS-GF spectral E-value."
      //[PSI:PI] msgfplus_EValue     = 12, ///< MS:1002053  "MS-GF E-value."
      //[PSI:PI] msgfplus_isotope_error = 13, ///< MS-GF isotope error
      //comet_xcorr   = 14, ///< MS:1002252  "The Comet result 'XCorr'." [PSI:PI]
      //comet_deltacn = 15, ///< MS:1002253  "The Comet result 'DeltaCn'."
      //[PSI:PI] comet_deltacnstar = 16, ///< MS:1002254  "The Comet result
      //'DeltaCnStar'." [PSI:PI] comet_spscore = 17, ///< MS:1002255  "The Comet
      //result 'SpScore'." [PSI:PI] comet_sprank  = 18, ///< MS:1002256  "The
      //Comet result 'SpRank'." [PSI:PI] comet_expectation_value = 19, ///<
      //MS:1002257  "The Comet result 'Expectation value'." [PSI:PI]

      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("cvParam %1 is not taken into account").arg(cvParam.toString()));
        }
    }

  qDebug();
  for(auto userParam : spectrumIdentificationItem.userParamList)
    {
      if(userParam.name == "DeepProt:original_count")
        {
          // <userParam name="DeepProt:original_count" value="7"/>
          peptide_evidence.setParam(PeptideEvidenceParam::deepprot_original_count,
                                    QVariant(userParam.value.toUInt()));
        }
      else if(userParam.name == "DeepProt:fitted_count")
        {
          // <userParam name="DeepProt:fitted_count" value="7"/>
          peptide_evidence.setParam(PeptideEvidenceParam::deepprot_fitted_count,
                                    QVariant(userParam.value.toUInt()));
        }
      else if(userParam.name == "DeepProt:match_type")
        {
          peptide_evidence.setParam(
            PeptideEvidenceParam::deepprot_match_type,
            (std::uint8_t)pappso::DeepProtEnumStr::DeepProtMatchTypeFromString(userParam.value));
        }
      else if(userParam.name == "DeepProt:status")
        {
          peptide_evidence.setParam(
            PeptideEvidenceParam::deepprot_peptide_candidate_status,
            (std::uint8_t)pappso::DeepProtEnumStr::DeepProtPeptideCandidateStatusFromString(
              userParam.value));
        }
      else if(userParam.name == "DeepProt:mass_delta")
        {
          peptide_evidence.setParam(PeptideEvidenceParam::deepprot_mass_delta,
                                    QVariant(userParam.value.toDouble()));
        }
      else if(userParam.name == "DeepProt:delta_positions")
        {
          // DeepProt:delta_positions 4 5 6 7 8 9 10 11 12 13
          peptide_evidence.setParam(PeptideEvidenceParam::deepprot_delta_positions,
                                    userParam.value);
        }
      // <userParam name="IsotopeError" value="0"/>
      //<userParam name="AssumedDissociationMethod" value="HCD"/>
    }


  qDebug();
  for(auto mz_peptide_evidence : spectrumIdentificationItem.mzidPeptideEvidenceList)
    {
      PeptideMatch peptide_match;
      peptide_match.setStart(mz_peptide_evidence.start);
      peptide_match.setPeptideEvidenceSp(spectrum_identification_result.mzident_source_sp.get()
                                           ->getPeptideEvidenceStore()
                                           .getInstance(&peptide_evidence));


      ProteinMatch *p_protein_match =
        spectrum_identification_result.identification_group_p->getProteinMatchInstance(
          mz_peptide_evidence.protein.get()->getAccession());

      p_protein_match->setChecked(true);
      // qDebug() << "startElement_protein p_protein_match 3 " <<
      // _p_protein_match;
      p_protein_match->setProteinXtpSp(mz_peptide_evidence.protein);
      p_protein_match->addPeptideMatch(peptide_match);
    }
  qDebug();
}*/

void
MzIdentMlReader::writeSpectrumIdentificationResult(
  const SpectrumIdentificationResult &spectrum_identificatio_result)
{

  mp_cborWriter->startMap(); // one scan
  mp_cborWriter->append("id");
  mp_cborWriter->startMap(); // id
  mp_cborWriter->append("index");
  mp_cborWriter->append((qint64)spectrum_identificatio_result.spectrumIndex);
  mp_cborWriter->append("native_id");
  mp_cborWriter->append(spectrum_identificatio_result.spectrumID);
  mp_cborWriter->endMap(); // end id

  mp_cborWriter->append("ms2");
  mp_cborWriter->startMap(); // ms2
  mp_cborWriter->append("rt");
  mp_cborWriter->append(spectrum_identificatio_result.retentionTime);
  mp_cborWriter->endMap(); // end ms2


  uint charge = spectrum_identificatio_result.spectrumIdentificationItemList.front().chargeState;
  double exp_mz =
    spectrum_identificatio_result.spectrumIdentificationItemList.front().experimentalMassToCharge;

  mp_cborWriter->append("precursor");
  mp_cborWriter->startMap(); // precursor
  mp_cborWriter->append("z");
  mp_cborWriter->append(charge);
  mp_cborWriter->append("mz");
  mp_cborWriter->append(exp_mz);
  mp_cborWriter->endMap(); // end precursor


  mp_cborWriter->append("psm_list");
  mp_cborWriter->startArray(spectrum_identificatio_result.spectrumIdentificationItemList.size());
  for(auto &spectrum_ident_item : spectrum_identificatio_result.spectrumIdentificationItemList)
    {
      if(spectrum_ident_item.chargeState != charge)
        { // error
        }
      if(spectrum_ident_item.experimentalMassToCharge != exp_mz)
        { // error
        }
      writeSpectrumIdentificationItem(spectrum_ident_item);
    }
  mp_cborWriter->endArray();

  mp_cborWriter->endMap(); // end one scan
}

void
MzIdentMlReader::writeSpectrumIdentificationItem(
  const SpectrumIdentificationItem &spectrum_identification_item)
{
  mp_cborWriter->startMap(); // psm
  mp_cborWriter->append("proforma");
  mp_cborWriter->append(spectrum_identification_item.peptide.get()->toProForma());

  std::map<QString, std::vector<std::size_t>> map_protein_positions;
  for(auto &it_peptide_evidence : spectrum_identification_item.mzidPeptideEvidenceList)
    {
      auto it_insert =
        map_protein_positions.insert({it_peptide_evidence.protein.get()->getAccession(), {}});
      it_insert.first->second.push_back(it_peptide_evidence.start);
    }
  mp_cborWriter->append("protein_list");
  mp_cborWriter->startArray(map_protein_positions.size());
  for(auto &it_prot_pos : map_protein_positions)
    {
      mp_cborWriter->startMap();
      mp_cborWriter->append("accession");
      mp_cborWriter->append(it_prot_pos.first);
      mp_cborWriter->append("positions");
      mp_cborWriter->writeArray(it_prot_pos.second);
      mp_cborWriter->endMap();
    }
  mp_cborWriter->endArray();


  mp_cborWriter->append("eval");
  mp_cborWriter->startMap(); // start eval
  bool is_ok = false;
  is_ok      = writeTandemEval(spectrum_identification_item.cvParamList);
  mp_cborWriter->endMap(); // end eval

  if(!is_ok)
    {
      throw pappso::PappsoException("This identification engine is not taken into account");
    }
  mp_cborWriter->endMap(); // end psm
}


bool
MzIdentMlReader::writeTandemEval(const std::vector<CvParam> &cv_param_list)
{
  //        <cvParam accession="MS:1001330" cvRef="PSI-MS" name="X!Tandem:expect"
  //        value="0.0410883"/>
  //       <cvParam accession="MS:1001331" cvRef="PSI-MS" name="X!Tandem:hyperscore" value="25.9"/>
  auto it_find =
    std::find_if(cv_param_list.begin(), cv_param_list.end(), [](const CvParam &cv_param) {
      return cv_param.accession == "MS:1001330";
    });
  if(it_find != cv_param_list.end())
    {
      mp_cborWriter->append("xtandem");
      mp_cborWriter->startMap(); // start tandem
      mp_cborWriter->append("evalue");
      mp_cborWriter->append(it_find->value.toDouble());
      auto it_find =
        std::find_if(cv_param_list.begin(), cv_param_list.end(), [](const CvParam &cv_param) {
          return cv_param.accession == "MS:1001331";
        });
      mp_cborWriter->append("hyperscore");
      mp_cborWriter->append(it_find->value.toDouble());

      mp_cborWriter->endMap(); // end tandem

      return true;
    }
  return false;
}

} // namespace psm
} // namespace cbor
} // namespace pappso
