/**
 * \file input/xtandemsaxhandler.cpp
 * \date 5/4/2017
 * \author Olivier Langella
 * \brief parse XML X!Tandem result file
 */


/*******************************************************************************
 * Copyright (c) 2017 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/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "xtandemsaxhandler.h"

#include <pappsomspp/exception/exceptionnotfound.h>
#include <cmath>
#include "../utils/peptidestore.h"
#include "../utils/proteinstore.h"
#include "../files/fastafile.h"
#include "../utils/utils.h"
#include "datafilenotsupportedexception.h"


XtandemSaxHandler::XtandemSaxHandler(
  Project *p_project,
  IdentificationGroup *p_identification_group,
  IdentificationXtandemFile *p_identification_data_source)
  : _p_project(p_project)
{
  _p_identification_group = p_identification_group;

  _p_identification_data_source = p_identification_data_source;
  _sp_msrun                     = p_identification_data_source->getMsRunSp();
}

XtandemSaxHandler::~XtandemSaxHandler()
{
}


bool
XtandemSaxHandler::startElement(const QString &namespaceURI [[maybe_unused]],
                                const QString &localName [[maybe_unused]],
                                const QString &qName,
                                const QXmlAttributes &attributes)
{
  // qDebug() << namespaceURI << " " << localName << " " << qName ;
  _tag_stack.push_back(qName);
  bool is_ok = true;

  try
    {
      if(_tag_stack.size() == 1)
        {
          if(qName != "bioml")
            {
              throw DataFileNotSupportedException(
                QObject::tr("ERROR this file is not an X!Tandem result file %1")
                  .arg(qName));
            }
        }
      // startElement_group
      else if(qName == "group")
        {
          is_ok = startElement_group(attributes);
        }
      else if(qName == "protein")
        {
          is_ok = startElement_protein(attributes);
        }
      else if(qName == "note")
        {
          is_ok = startElement_note(attributes);
        }
      else if(qName == "file")
        {
          is_ok = startElement_file(attributes);
        }
      else if(qName == "aa")
        {
          is_ok = startElement_aa(attributes);
        }
      else if(qName == "domain")
        {
          is_ok = startElement_domain(attributes);
        }

      _current_text.clear();
    }
  catch(pappso::PappsoException &exception_pappso)
    {
      _errorStr = QObject::tr(
                    "ERROR in XtandemSaxHandler::startElement tag "
                    "%1, PAPPSO exception:\n%2")
                    .arg(qName)
                    .arg(exception_pappso.qwhat());
      return false;
    }
  catch(std::exception &exception_std)
    {
      _errorStr =
        QObject::tr(
          "ERROR in XtandemSaxHandler::startElement tag %1, std exception:\n%2")
          .arg(qName)
          .arg(exception_std.what());
      return false;
    }
  return is_ok;
}

bool
XtandemSaxHandler::endElement(const QString &namespaceURI [[maybe_unused]],
                              const QString &localName [[maybe_unused]],
                              const QString &qName)
{

  bool is_ok = true;
  // endElement_peptide_list
  try
    {
      if(qName == "note")
        {
          is_ok = endElement_note();
        }
      else if(qName == "domain")
        {
          is_ok = endElement_domain();
        }

      // end of detection_moulon
      // else if ((_tag_stack.size() > 1) &&
      //         (_tag_stack[_tag_stack.size() - 2] == "detection_moulon"))
    }
  catch(pappso::PappsoException &exception_pappso)
    {
      _errorStr = QObject::tr(
                    "ERROR in XtandemSaxHandler::endElement tag %1, "
                    "PAPPSO exception:\n%2")
                    .arg(qName)
                    .arg(exception_pappso.qwhat());
      return false;
    }
  catch(std::exception &exception_std)
    {
      _errorStr =
        QObject::tr(
          "ERROR in XtandemSaxHandler::endElement tag %1, std exception:\n%2")
          .arg(qName)
          .arg(exception_std.what());
      return false;
    }

  _current_text.clear();
  _tag_stack.pop_back();

  return is_ok;
}


bool
XtandemSaxHandler::startElement_group(QXmlAttributes attrs)
{
  //<group id="1976" mh="1120.529471" z="2" rt="PT667.022S" expect="9.7e-04"
  // label="GRMZM2G083841_P01 P04711 Phosphoenolpyruvate carboxylase 1 (PEPCase
  // 1)(PEPC 1)(EC..." type="model" sumI="5.34" maxI="35986.9" fI="359.869"
  // act="0" >
  bool is_ok = true;
  // logger.debug("startElementgroup begin");
  // <group label="performance parameters" type="parameters">
  _current_group_label = attrs.value("label");
  _current_group_type  = attrs.value("type");
  if(_current_group_type == "model")
    {
      _scan         = attrs.value("id").toUInt();
      _mhplus_obser = attrs.value("mh").toDouble();
      _charge       = attrs.value("z").toUInt();
      _retention_time =
        attrs.value("rt").replace("PT", "").replace("S", "").toDouble();
    }
  // label="input parameters" type="parameters"
  return is_ok;
}


bool
XtandemSaxHandler::startElement_note(QXmlAttributes attributes)
{
  //<note label="description">GRMZM2G083841_P01 P04711 Phosphoenolpyruvate
  // carboxylase 1 (PEPCase 1)(PEPC 1)(EC //4.1.1.31) seq=translation;
  // coord=9:61296279..61301686:1; parent_transcript=GRMZM2G083841_T01;
  ////parent_gene=GRMZM2G083841</note>
  bool is_ok              = true;
  _current_note_label     = attributes.value("label");
  _current_note_type      = attributes.value("type");
  _is_protein_description = false;
  if(attributes.value("label") == "description")
    {
      if(_tag_stack[_tag_stack.size() - 2] == "protein")
        {
          _is_protein_description = true;
        }
    }
  return is_ok;
}

bool
XtandemSaxHandler::startElement_file(QXmlAttributes attributes)
{
  bool is_ok = true;
  //<file type="peptide"
  // URL="/gorgone/pappso/formation/TD/Database/Genome_Z_mays_5a.fasta"/>
  if(attributes.value("type") == "peptide")
    {
      // prot_.setDatabase(identification_.getDatabaseSet().getInstance(
      //                     attrs.getValue("URL")));
      if(_p_protein_match == nullptr)
        {
          throw pappso::PappsoException(
            "ERROR in "
            "XtandemSaxHandler::startElement_file "
            ": _p_protein_match == nullptr");
        }
      _p_protein_match->getProteinXtpSp().get()->setFastaFileP(
        _p_project->getFastaFileStore()
          .getInstance(FastaFile(attributes.value("URL")))
          .get());
    }


  return is_ok;
}

bool
XtandemSaxHandler::startElement_domain(QXmlAttributes attributes)
{
  // mh="1120.529471"
  //<domain id="1976.1.1" start="620" end="629" expect="9.7e-04" mh="1120.5307"
  // delta="-0.0012" hyperscore="29.9"  nextscore="10.2" y_score="10.4"
  // y_ions="7"
  // b_score="11.2" b_ions="3" pre="QLYR" post="RYGV"  seq="AQEEMAQVAK"
  // missed_cleavages="0">  qDebug() << "startElement_domain ";
  bool is_ok    = true;
  _current_text = _current_text.simplified().replace(" ", "");
  if(!_current_text.isEmpty())
    {
      //._sequence.replace(QRegExp("\\*"), "")).removeTranslationStop()
      //_p_protein_match->getProteinXtpSp().get()->setSequence(_current_text.replace(QRegExp("\\*"),
      //""));
      if(_p_protein_match == nullptr)
        {
          throw pappso::PappsoException(
            "ERROR in "
            "XtandemSaxHandler::startElement_"
            "domain : _p_protein_match == nullptr");
        }

      _p_protein_match->getProteinXtpSp().get()->setSequence(_current_text);
    }

  // <domain id="4017.1.1" start="21" end="31" expect="2.0e-06"
  // mh="1263.575"
  // delta="0.998" hyperscore="32.9" nextscore="12.2" y_score="10.7"
  // y_ions="9" b_score="0.0" b_ions="0"
  // pre="VLGR" post="VEFM" seq="TGSQGQCTQVR" missed_cleavages="10">
  /*
   * id
  – the identifier for t
  his particular identified dom
  ain (s
  pectrum
  #).(i
  d
  #).(dom
  ain#)
  start
  – the first residue
  of t
  he dom
  ain
  end
  – the last residue
  of t
  he dom
  ain
  expect
  – the expe
  ctation va
  lue for t
  he peptide identification
  mh
  – the calculated pe
  ptide mass + a prot
  on
  delta
  – the spectrum
  mh m
  inus
  the calculated m
  h
  hyperscore
  – T
  ande
  m’s score for t
  he identification
  peak_count
  – the num
  ber of pe
  aks that matched be
  tween the theoretical
  and t
  he test mass spectrum
  pre
  – the four re
  sidue
  s pre
  ceding t
  he dom
  ain
  post
  – the four re
  sidue
  s fol
  lowing t
  he dom
  ain
  seq
  – the seque
  nce of t
  he dom
  ain
  missed_cleavages
  – the num
  ber of pot
  ential cleavage sites in this
  peptide seque
  nce*/

  // valeur généric du scan
  _current_peptide_sp =
    PeptideXtp(attributes.value("seq").simplified()).makePeptideXtpSp();
  _p_peptide_evidence = new PeptideEvidence(
    _sp_msrun.get(),
    attributes.value("id").simplified().section(".", 0, 0).toUInt());

  _p_peptide_evidence->setRetentionTime(_retention_time);
  _p_peptide_evidence->setEvalue(
    attributes.value("expect").simplified().toDouble());
  // qDebug() << "XtandemSaxHandler::startElement_domain evalue "  <<
  // _p_peptide_match->getEvalue() << " scan " << _p_peptide_match->getScan();
  /*
    pappso::pappso_double xtandem_mhtheoretical =
      attributes.value("mh").simplified().toDouble();
    pappso::pappso_double xtandem_delta =
      attributes.value("delta").simplified().toDouble();
  */
  // delta – the spectrum mh minus the calculated mh

  // exp mass computed from X!Tandem mh :
  pappso::pappso_double exp_mass = _mhplus_obser - pappso::MHPLUS;


  _p_peptide_evidence->setExperimentalMass(exp_mass);
  _current_peptide_match.setStart(
    attributes.value("start").simplified().toUInt() - 1);
  _p_peptide_evidence->setCharge(_charge);

  _p_peptide_evidence->setParam(
    PeptideEvidenceParam::tandem_hyperscore,
    QVariant(attributes.value("hyperscore").toDouble()));

  _p_peptide_evidence->setIdentificationDataSource(
    _p_identification_data_source);
  _p_peptide_evidence->setChecked(true);


  // missing information
  // peptide.set_hypercorr(Float.valueOf(attrs.getValue("hyperscore")));
  // peptide.set_pre(attrs.getValue("pre"));
  // peptide.set_post(attrs.getValue("post"));
  // qDebug() << "startElement_domain end" ;
  return is_ok;
}

bool
XtandemSaxHandler::startElement_aa(QXmlAttributes attributes)
{
  //<aa type="M" at="624" modified="15.99491" />

  bool is_ok = true;
  // qDebug() << "startElement_aa ";
  pappso::AaModificationP modif = nullptr;
  if(attributes.value("pm").isEmpty())
    {

      modif = Utils::guessAaModificationPbyMonoisotopicMassDelta(
        attributes.value("modified").simplified().toDouble());
    }
  else
    {
      //<aa type="P" at="59" modified="31.98983" pm="E" />
      //<aa type="C" at="64" modified="-15.97716" pm="S" />
      // point mutation
      QChar mut_from(attributes.value("type")[0]);
      QChar mut_to(attributes.value("pm")[0]);
      modif = pappso::AaModification::getInstanceMutation(mut_from, mut_to);
    }
  unsigned int position_in_prot =
    attributes.value("at").simplified().toUInt() - 1;
  _current_peptide_sp.get()->addAaModification(
    modif, position_in_prot - _current_peptide_match.getStart());
  // qDebug() << "startElement_aa end" ;
  return is_ok;
}

bool
XtandemSaxHandler::endElement_domain()
{
  bool is_ok = true;
  _current_peptide_sp =
    _p_project->getPeptideStore().getInstance(_current_peptide_sp);

  _p_peptide_evidence->setPeptideXtpSp(_current_peptide_sp);

  _current_peptide_match.setPeptideEvidenceSp(
    _p_peptide_evidence->getIdentificationDataSource()
      ->getPeptideEvidenceStore()
      .getInstance(_p_peptide_evidence));
  if(_p_protein_match == nullptr)
    {
      throw pappso::PappsoException(
        "ERROR in "
        "XtandemSaxHandler::endElement_domain : "
        "_p_protein_match == nullptr");
    }

  _p_protein_match->addPeptideMatch(_current_peptide_match);

  delete _p_peptide_evidence;
  return is_ok;
}


bool
XtandemSaxHandler::startElement_protein(QXmlAttributes attributes
                                        [[maybe_unused]])
{
  //<protein expect="-704.6" id="1976.1" uid="195701" label="GRMZM2G083841_P01
  // P04711 Phosphoenolpyruvate carboxylase 1 (PEPCase 1)(PEPC 1)(EC..."
  // sumI="9.36" >
  bool is_ok = true;

  // the protein label could be truncated => we must wait for the <note
  // label="description">sp|P11413|G6PD_HUMAN Glucose-6-phosphate
  // 1-dehydrogenase OS=Homo sapiens GN=G6PD PE=1 SV=4</note>  to get the real
  // protein
  _p_protein_match = nullptr;
  // qDebug() << "startElement_protein end" ;
  return is_ok;
}


bool
XtandemSaxHandler::endElement_note()
{
  //<note label="description">GRMZM2G083841_P01 P04711 Phosphoenolpyruvate
  // carboxylase 1 (PEPCase 1)(PEPC 1)(EC //4.1.1.31) seq=translation;
  // coord=9:61296279..61301686:1; parent_transcript=GRMZM2G083841_T01;
  ////parent_gene=GRMZM2G083841</note>
  bool is_ok = true;
  if(_is_protein_description)
    {
      //_p_protein_match->getProteinXtpSp().get()->setDescription(_current_text.section("
      //",1));
      _current_protein.setCompleteDescription(_current_text);
      if(!_current_protein.getAccession().endsWith(":reversed") &&
         _current_protein.getDescription().endsWith(":reversed"))
        {
          // to fit most cases, just check that the :reversed chars added by
          // X!Tandem are not in the description. if so, then add it too in the
          // accession
          _current_protein.setAccession(QString("%1%2")
                                          .arg(_current_protein.getAccession())
                                          .arg(":reversed"));
        }
      // for older versions < 2013.09.01.1
      if(!_current_protein.getAccession().endsWith("|reversed") &&
         _current_protein.getDescription().endsWith("|reversed"))
        {
          // to fit most cases, just check that the :reversed chars added by
          // X!Tandem are not in the description. if so, then add it too in the
          // accession
          _current_protein.setAccession(QString("%1%2")
                                          .arg(_current_protein.getAccession())
                                          .arg("|reversed"));
        }

      // qDebug() << "startElement_protein accession" << accession;
      _p_protein_match = _p_identification_group->getProteinMatchInstance(
        _current_protein.getAccession());

      _p_protein_match->setChecked(false);
      // qDebug() << "startElement_protein p_protein_match 3 " <<
      // _p_protein_match;
      ProteinXtpSp sp_xtp_protein = _current_protein.makeProteinXtpSp();
      _p_protein_match->setProteinXtpSp(
        _p_project->getProteinStore().getInstance(sp_xtp_protein));
      _p_protein_match->setChecked(true);
    }
  else
    {

      qDebug() << _current_note_label;
      //<group label="input parameters" type="parameters">
      //<note type="input" label="list path, default
      // parameters">/gorgone/pappso/tmp/temp_condor_job8533994640337729751189420695540169/QExactive_analysis_FDR_nosemi.xml</note>
      if(_current_note_label == "list path, default parameters")
        {
          _p_identification_data_source->setIdentificationEngineParam(
            IdentificationEngineParam::tandem_param, _current_text);
        }
      /*
      <note type="input" label="list path, taxonomy
      information">/gorgone/pappso/tmp/temp_condor_job8533994640337729751189420695540169/database.xml</note>
      <note type="input" label="output, histogram column width">30</note>
      <note type="input" label="output, histograms">yes</note>
      <note type="input" label="output, maximum valid expectation
      value">0.05</note> <note type="input" label="output, maximum valid protein
      expectation value">0.05</note> <note type="input" label="output, one
      sequence copy">yes</note> <note type="input" label="output,
      parameters">yes</note> <note type="input" label="output,
      path">/gorgone/pappso/formation/TD/xml_tandem/20120906_balliau_extract_1_A02_urzb-1.xml</note>
      <note type="input" label="output, path hashing">no</note>
      <note type="input" label="output, performance">yes</note>
      <note type="input" label="output, proteins">yes</note>
      <note type="input" label="output, results">valid</note>
      <note type="input" label="output, sequences">yes</note>
      <note type="input" label="output, sort results by">spectrum</note>
      <note type="input" label="output, spectra">yes</note>
      <note type="input" label="output, xsl path">tandem-style.xsl</note>
      <note type="input" label="protein, C-terminal residue modification
      mass">0.0</note> <note type="input" label="protein, N-terminal residue
      modification mass">0.0</note> <note type="input" label="protein, cleavage
      C-terminal mass change">+17.00305</note> <note type="input"
      label="protein, cleavage N-terminal mass change">+1.00794</note> <note
      type="input" label="protein, cleavage semi">no</note> <note type="input"
      label="protein, cleavage site">[RK]|{P}</note> <note type="input"
      label="protein, modified residue mass file"></note> <note type="input"
      label="protein, quick acetyl">yes</note> <note type="input"
      label="protein, quick pyrolidone">yes</note> <note type="input"
      label="protein, stP bias">yes</note> <note type="input" label="protein,
      taxon">usedefined</note> <note type="input" label="refine">yes</note>
      <note type="input" label="refine, cleavage semi">no</note>
      <note type="input" label="refine, maximum valid expectation
      value">0.01</note> <note type="input" label="refine, modification
      mass">57.02146@C</note> <note type="input" label="refine, modification
      mass 1"></note> <note type="input" label="refine, point
      mutations">no</note> <note type="input" label="refine, potential
      C-terminus modifications"></note> <note type="input" label="refine,
      potential N-terminus modifications">+42.01056@[</note> <note type="input"
      label="refine, potential modification mass">15.99491@M</note> <note
      type="input" label="refine, potential modification mass 1"></note> <note
      type="input" label="refine, potential modification motif"></note> <note
      type="input" label="refine, potential modification motif 1"></note> <note
      type="input" label="refine, spectrum synthesis">yes</note> <note
      type="input" label="refine, unanticipated cleavage">no</note> <note
      type="input" label="refine, use potential modifications for full
      refinement">yes</note> <note type="input" label="residue, modification
      mass">57.02146@C</note> <note type="input" label="residue, modification
      mass 1"></note> <note type="input" label="residue, potential modification
      mass">15.99491@M</note> <note type="input" label="residue, potential
      modification motif"></note> <note type="input" label="scoring, a
      ions">no</note> <note type="input" label="scoring, b ions">yes</note>
      <note type="input" label="scoring, c ions">no</note>
      <note type="input" label="scoring, cyclic permutation">yes</note>
      <note type="input" label="scoring, include reverse">yes</note>
      <note type="input" label="scoring, maximum missed cleavage sites">1</note>
      <note type="input" label="scoring, minimum ion count">4</note>
      <note type="input" label="scoring, x ions">no</note>
      <note type="input" label="scoring, y ions">yes</note>
      <note type="input" label="scoring, z ions">no</note>
      <note type="input" label="spectrum, dynamic range">100.0</note>
      <note type="input" label="spectrum, fragment mass
      type">monoisotopic</note> <note type="input" label="spectrum, fragment
      monoisotopic mass error">0.02</note> <note type="input" label="spectrum,
      fragment monoisotopic mass error units">Daltons</note> <note type="input"
      label="spectrum, maximum parent charge">4</note> <note type="input"
      label="spectrum, minimum fragment mz">150.0</note> <note type="input"
      label="spectrum, minimum parent m+h">500.0</note> <note type="input"
      label="spectrum, minimum peaks">15</note> <note type="input"
      label="spectrum, neutral loss mass">18.01057</note> <note type="input"
      label="spectrum, neutral loss window">0.02</note> <note type="input"
      label="spectrum, parent monoisotopic mass error minus">10</note> <note
      type="input" label="spectrum, parent monoisotopic mass error
      plus">10</note> <note type="input" label="spectrum, parent monoisotopic
      mass error units">ppm</note> <note type="input" label="spectrum, parent
      monoisotopic mass isotope error">yes</note>
      */
      //<note type="input" label="spectrum,
      // path">/gorgone/pappso/formation/TD/mzXML/20120906_balliau_extract_1_A02_urzb-1.mzXML</note>

      if(_current_note_label == "spectrum, path")
        {
          _sp_msrun.get()->setFileName(_current_text);
        }

      /*
      <note type="input" label="spectrum, sequence batch size">1000</note>
      <note type="input" label="spectrum, threads">1</note>
      <note type="input" label="spectrum, total peaks">100</note>
      <note type="input" label="spectrum, use contrast angle">no</note>
      <note type="input" label="spectrum, use neutral loss window">yes</note>
      <note type="input" label="spectrum, use noise suppression">yes</note>
      </group>

      */

      //<group label="unused input parameters"  type="parameters">

      /*
        <note type="input" label="protein, use minimal annotations">yes</note>
        <note type="input" label="refine, modification mass 2"></note>
        <note type="input" label="refine, potential modification mass 2"></note>
        <note type="input" label="refine, potential modification motif
      2"></note> <note type="input" label="residue, modification mass 2"></note>
        <note type="input" label="residue, potential modification mass
      1"></note> <note type="input" label="residue, potential modification mass
      2"></note> <note type="input" label="residue, potential modification motif
      1"></note> <note type="input" label="residue, potential modification motif
      2"></note> <note type="input" label="scoring, pluggable scoring">no</note>
      </group>
      */

      //<group label="performance parameters" type="parameters">

      //<note label="list path, sequence source
      //#1">/gorgone/pappso/formation/TD/Database/Genome_Z_mays_5a.fasta</note>
      //<note label="list path, sequence source
      //#2">/gorgone/pappso/formation/TD/Database/contaminants_standarts.fasta</note>
      if(_current_note_label.startsWith("list path, sequence source #"))
        {
          _p_identification_data_source->addFastaFile(
            _p_project->getFastaFileStore().getInstance(
              FastaFile(_current_text)));
        }

      /*
      <note label="list path, sequence source description #1">no
      description</note> <note label="list path, sequence source description
      #2">no description</note> <note label="modelling, duplicate peptide
      ids">6019</note> <note label="modelling, duplicate proteins">19735</note>
      <note label="modelling, estimated false positives">18</note>
      <note label="modelling, reversed sequence false positives">20</note>
      <note label="modelling, spectrum noise suppression ratio">0.00</note>
      */
      //<note label="modelling, total peptides used">96618641</note>
      if(_current_note_label == "modelling, total peptides used")
        {
          _p_identification_data_source->setIdentificationEngineStatistics(
            IdentificationEngineStatistics::total_peptide_used,
            _current_text.toUInt());
        }

      //<note label="modelling, total proteins used">273656</note>
      if(_current_note_label == "modelling, total proteins used")
        {
          _p_identification_data_source->setIdentificationEngineStatistics(
            IdentificationEngineStatistics::total_proteins_used,
            _current_text.toUInt());
        }
      //<note label="modelling, total spectra assigned">7464</note>
      if(_current_note_label == "modelling, total spectra assigned")
        {
          _p_identification_data_source->setIdentificationEngineStatistics(
            IdentificationEngineStatistics::total_spectra_assigned,
            _current_text.toUInt());
        }
      //<note label="modelling, total spectra used">12199</note>
      if(_current_note_label == "modelling, total spectra used")
        {

          qDebug() << _current_note_label;
          _p_identification_data_source->setIdentificationEngineStatistics(
            IdentificationEngineStatistics::total_spectra_used,
            _current_text.toUInt());
        }
      //<note label="modelling, total unique assigned">6260</note>
      if(_current_note_label == "modelling, total unique assigned")
        {

          qDebug() << _current_note_label;
          _p_identification_data_source->setIdentificationEngineStatistics(
            IdentificationEngineStatistics::total_unique_assigned,
            _current_text.toUInt());
        }
      qDebug() << _current_note_label;
      if(_current_note_label == "spectrum, timstof MS2 centroid parameters")
        {
          qDebug() << _current_note_label;
          _p_identification_data_source->setTimstofMs2CentroidParameters(
            _current_text);
        }
      //<note label="process, start time">2013:12:20:16:47:19</note>

      //<note label="process, version">X! Tandem Sledgehammer
      //(2013.09.01.1)</note>
      if(_current_note_label == "process, version")
        {
          QRegExp rx("\\((.*)\\)");
          if(rx.indexIn(_current_text, 0) != -1)
            {
              _p_identification_data_source->setIdentificationEngineVersion(
                rx.cap(1));
            }
          qDebug()
            << _p_identification_data_source->getIdentificationEngineVersion();
        }
      /*
      <note label="quality values">243 476 437 382 384 417 399 416 346 387 390
      382 321 355 311 283 253 272 251 228</note> <note label="refining, # input
      models">4893</note> <note label="refining, # input spectra">5520</note>
      <note label="refining, # partial cleavage">326</note>
      <note label="refining, # point mutations">0</note>
      <note label="refining, # potential C-terminii">0</note>
      <note label="refining, # potential N-terminii">392</note>
      <note label="refining, # unanticipated cleavage">0</note>
      <note label="timing, initial modelling total (sec)">170.96</note>
      <note label="timing, initial modelling/spectrum (sec)">0.0140</note>
      <note label="timing, load sequence models (sec)">0.33</note>
      <note label="timing, refinement/spectrum (sec)">0.0141</note>
      </group>
      */
    }
  _current_text = "";
  return is_ok;
}


bool
XtandemSaxHandler::error(const QXmlParseException &exception)
{
  _errorStr = QObject::tr(
                "Parse error at line %1, column %2 :\n"
                "%3")
                .arg(exception.lineNumber())
                .arg(exception.columnNumber())
                .arg(exception.message());

  return false;
}


bool
XtandemSaxHandler::fatalError(const QXmlParseException &exception)
{
  _errorStr = QObject::tr(
                "Parse error at line %1, column %2 :\n"
                "%3")
                .arg(exception.lineNumber())
                .arg(exception.columnNumber())
                .arg(exception.message());
  return false;
}

QString
XtandemSaxHandler::errorString() const
{
  return _errorStr;
}


bool
XtandemSaxHandler::endDocument()
{
  return true;
}

bool
XtandemSaxHandler::startDocument()
{
  return true;
}

bool
XtandemSaxHandler::characters(const QString &str)
{
  _current_text += str;
  return true;
}
