/**
 * \file src/input/tandem/tandeminfoparser.cpp
 * \date 23/12/2021
 * \author Olivier Langella
 * \brief reads tandem xml result files to parse various informations
 */

/*******************************************************************************
 * Copyright (c) 2021 Olivier Langella <Olivier.Langella@u-psud.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 "tandeminfoparser.h"
#include <QDebug>
#include <QFileInfo>
#include <QDir>
#include <pappsomspp/core/mzrange.h>

TandemInfoParser::TandemInfoParser()
{
}

TandemInfoParser::TandemInfoParser(const TandemInfoParser &other)
{
  m_spectrum_path = other.m_spectrum_path;
  m_modelCount    = other.m_modelCount;
  m_msDataFormat  = other.m_msDataFormat;
}

TandemInfoParser::~TandemInfoParser()
{
}

void
TandemInfoParser::readStream()
{
  qDebug();
  m_modelCount = 0;
  if(m_qxmlStreamReader.readNextStartElement())
    {
      if(m_qxmlStreamReader.name().toString() == "bioml")
        {
          qDebug();
          while(m_qxmlStreamReader.readNextStartElement())
            {
              qDebug() << m_qxmlStreamReader.name();

              if(m_qxmlStreamReader.name().toString() == "group")
                {
                  // read_note();
                  QString type =
                    m_qxmlStreamReader.attributes().value("type").toString();
                  QString label =
                    m_qxmlStreamReader.attributes().value("label").toString();


                  qDebug() << m_qxmlStreamReader.name() << " type=" << type
                           << " label=" << label;

                  if(type == "model")
                    {
                      m_modelCount++;
                      m_qxmlStreamReader.skipCurrentElement();
                    }
                  else if(type == "parameters")
                    {
                      //<group label="residue mass parameters"
                      // type="parameters">
                      if(label == "residue mass parameters")
                        {
                          readResidueMassParameters();
                        }
                      else
                        {
                          // project parameter named
                          // cvparam_SpectraDataFileFormat in category 5 not
                          // found
                          while(m_qxmlStreamReader.readNextStartElement())
                            {
                              if(m_qxmlStreamReader.name().toString() == "note")
                                {

                                  QString type = m_qxmlStreamReader.attributes()
                                                   .value("type")
                                                   .toString();
                                  QString label =
                                    m_qxmlStreamReader.attributes()
                                      .value("label")
                                      .toString();

                                  qDebug()
                                    << m_qxmlStreamReader.name()
                                    << " type=" << type << " label=" << label;

                                  QString value =
                                    m_qxmlStreamReader.readElementText();
                                  if(type == "input")
                                    {
                                      pappso::ProjectParam project_param(
                                        {pappso::ProjectParamCategory::
                                           identification,
                                         "",
                                         QVariant()});
                                      project_param.name  = label;
                                      project_param.value = value;

                                      m_projectParameters.setProjectParam(
                                        project_param);
                                    }

                                  if((type == "input") &&
                                     (label == "spectrum, path"))
                                    {
                                      //<note type="input" label="spectrum,
                                      // path">

                                      m_spectrum_path = value;


                                      QFileInfo fileinfo(m_spectrum_path);
                                      if(fileinfo.fileName() == "analysis.tdf")
                                        {
                                          m_spectrum_path =
                                            fileinfo.absoluteDir()
                                              .absolutePath();
                                        }
                                      // m_qxmlStreamReader.skipCurrentElement();
                                    }

                                  else if((type == "input") &&
                                          (label == "spectrum, mzFormat"))
                                    {

                                      m_msDataFormat =
                                        (pappso::Enums::MsDataFormat)value.toInt();
                                    }
                                  else if((type == "input") &&
                                          (label == "output, path"))
                                    {
                                      //<note type="input" label="output, path">
                                      // m_qxmlStreamReader.skipCurrentElement();

                                      // m_qxmlStreamReader.skipCurrentElement();
                                    }
                                  // list path, default parameters
                                  else if((type == "input") &&
                                          (label ==
                                           "list path, default parameters"))
                                    {
                                      //<note type="input" label="list path,
                                      // default
                                      // parameters">/gorgone/pappso/tmp/i2masschroq.AjyZGg/Lumos_trypsin_rev_camC_oxM_10ppm_HCDOT_12102017CH.xml</note>

                                      // m_qxmlStreamReader.skipCurrentElement();
                                    }
                                  else
                                    {
                                      // m_qxmlStreamReader.skipCurrentElement();
                                    }
                                }
                              else
                                { // note
                                  m_qxmlStreamReader.raiseError(QObject::tr(
                                    "Not an X!Tandem input file (no note)"));
                                  m_qxmlStreamReader.skipCurrentElement();
                                }
                            }
                        }
                    }
                }
              else
                { // group
                  m_qxmlStreamReader.raiseError(
                    QObject::tr("Not an X!Tandem input file (no group)"));
                  m_qxmlStreamReader.skipCurrentElement();
                }
            }
        }
      else
        {
          m_qxmlStreamReader.raiseError(
            QObject::tr("Not an X!Tandem input file (no bioml)"));
          m_qxmlStreamReader.skipCurrentElement();
        }
    }

  qDebug();
}

const QString &
TandemInfoParser::getSpectraDataLocation() const
{
  return m_spectrum_path;
}

std::size_t
TandemInfoParser::getModelCount() const
{
  return m_modelCount;
}

pappso::Enums::MsDataFormat
TandemInfoParser::getMsDataFormat() const
{
  return m_msDataFormat;
}

void
TandemInfoParser::readResidueMassParameters()
{
  /*
   * <group label="residue mass parameters" type="parameters">
  <aa type="A" mass="75.044213" />
  <aa type="B" mass="116.036998" />
  <aa type="C" mass="107.016284" />
  <aa type="D" mass="120.037397" />
  <aa type="E" mass="135.056402" />
  <aa type="F" mass="157.095642" />
  <aa type="G" mass="60.025208" />
  <aa type="H" mass="146.070146" />
  <aa type="I" mass="120.101228" />
  <aa type="J" mass="0.000000" />
  <aa type="K" mass="136.109162" />
  <aa type="L" mass="120.101228" />
  <aa type="M" mass="137.054294" />
  <aa type="N" mass="120.050417" />
  <aa type="O" mass="0.000000" />
  <aa type="P" mass="103.066573" />
  <aa type="Q" mass="135.069421" />
  <aa type="R" mass="166.109380" />
  <aa type="S" mass="91.039128" />
  <aa type="T" mass="106.058133" />
  <aa type="U" mass="150.953634" />
  <aa type="V" mass="105.082223" />
  <aa type="W" mass="199.110286" />
  <aa type="X" mass="112.057034" />
  <aa type="Y" mass="173.090557" />
  <aa type="Z" mass="130.052648" />
  <molecule type="NH3" mass="18.023583" />
  <molecule type="H2O" mass="18.010565" />
</group>
*/

  /// /gorgone/pappso/moulon/users/thierry/20230407_rusconi_RD/xml/recherche_drastique_heavy/20230407_rusconi_RD_H3_1_230412182306.xml
  while(m_qxmlStreamReader.readNextStartElement())
    {
      qDebug() << m_qxmlStreamReader.name().toString();
      if(m_qxmlStreamReader.name().toString() == "aa")
        {

          QString type =
            m_qxmlStreamReader.attributes().value("type").toString();
          bool ok = false;
          double mass =
            m_qxmlStreamReader.attributes().value("mass").toDouble(&ok);
          if(!ok)
            {
              m_qxmlStreamReader.raiseError(
                QObject::tr("amino mass for %1 not relevant (%2)")
                  .arg(type)
                  .arg(m_qxmlStreamReader.attributes().value("mass")));
            }

          qDebug() << m_qxmlStreamReader.name() << " type=" << type
                   << " mass=" << mass;

          //<aa type="A" mass="75.044213" />
          if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::alanine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::alanine, mass);
            }
          //	<aa type="R" mass="107.016284" />
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::arginine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::arginine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::asparagine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::asparagine, mass);
            }
          else if(type[0].toLatin1() ==
                  (char)pappso::Enums::AminoAcidChar::aspartic_acid)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::aspartic_acid, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::cysteine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::cysteine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::glutamine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::glutamine, mass);
            }
          else if(type[0].toLatin1() ==
                  (char)pappso::Enums::AminoAcidChar::glutamic_acid)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::glutamic_acid, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::glycine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::glycine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::histidine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::histidine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::isoleucine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::isoleucine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::leucine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::leucine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::lysine)
            {
              setMapAminoAcidChar2AaModificationP(pappso::Enums::AminoAcidChar::lysine,
                                                  mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::methionine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::methionine, mass);
            }
          else if(type[0].toLatin1() ==
                  (char)pappso::Enums::AminoAcidChar::phenylalanine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::phenylalanine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::proline)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::proline, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::serine)
            {
              setMapAminoAcidChar2AaModificationP(pappso::Enums::AminoAcidChar::serine,
                                                  mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::threonine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::threonine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::tryptophan)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::tryptophan, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::tyrosine)
            {
              setMapAminoAcidChar2AaModificationP(
                pappso::Enums::AminoAcidChar::tyrosine, mass);
            }
          else if(type[0].toLatin1() == (char)pappso::Enums::AminoAcidChar::valine)
            {
              setMapAminoAcidChar2AaModificationP(pappso::Enums::AminoAcidChar::valine,
                                                  mass);
            }
          else
            {
              //  m_qxmlStreamReader.raiseError(
              //   QObject::tr("error : amino acid %1 not implemented
              //   ").arg(type));
            }

          m_qxmlStreamReader.skipCurrentElement();
        }

      else if(m_qxmlStreamReader.name().toString() == "molecule")
        {
          m_qxmlStreamReader.skipCurrentElement();
        }
      else
        { // note
          m_qxmlStreamReader.raiseError(
            QObject::tr("Not an X!Tandem input file (not a residue mass "
                        "parameters group)"));
          m_qxmlStreamReader.skipCurrentElement();
        }
    }
}

void
TandemInfoParser::setMapAminoAcidChar2AaModificationP(
  pappso::Enums::AminoAcidChar amino_acid, double mass)
{

  pappso::PrecisionPtr mass_precision =
    pappso::PrecisionFactory::getDaltonInstance(0.001);
  pappso::Aa alanine((char)amino_acid);
  double diff_mono                  = mass - alanine.getMass();
  pappso::AaModificationP aa_c13n15 = pappso::AaModification::getInstance(
    QString("C13N15:%1").arg((char)amino_acid));
  if(pappso::MzRange(aa_c13n15->getMass(), mass_precision).contains(diff_mono))
    {
      qDebug() << aa_c13n15->getAccession() << " *=" << aa_c13n15;
      aa_c13n15 =
        pappso::AaModification::getInstance(aa_c13n15->getAccession());
      qDebug() << aa_c13n15->getAccession() << " *=" << aa_c13n15;
      m_mapAminoAcidChar2AaModificationP[amino_acid] = aa_c13n15;
    }
  else
    {
      m_mapAminoAcidChar2AaModificationP[amino_acid] =
        pappso::AaModification::getInstanceCustomizedMod(diff_mono);
    }
}

const std::map<pappso::Enums::AminoAcidChar, pappso::AaModificationP> &
TandemInfoParser::getResidueMassModifications() const
{
  return m_mapAminoAcidChar2AaModificationP;
}

const pappso::ProjectParameters &
TandemInfoParser::getProjectParameters() const
{
  return m_projectParameters;
}
