/**
 * \file /core/tandem_run/tandemparameters.cpp
 * \date 19/9/2017
 * \author Olivier Langella
 * \brief handles X!Tandem parameters
 */

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

#include "tandemparameters.h"
#include <QDebug>
#include <QObject>
#include <pappsomspp/core/exception/exceptionnotfound.h>
#include <pappsomspp/core/exception/exceptionnotpossible.h>

/*
 *
specific parameters for the modified TPP tandem version :
http://tools.proteomecenter.org/wiki/index.php?title=TPP:X%21Tandem_and_the_TPP

<note label="scoring, algorithm" type="input">k-score</note>
<note label="spectrum, use conditioning" type="input">no</note>
<note label="scoring, minimum ion count" type="input">1</note>
new labels :
"protein, taxon" https://www.thegpm.org/TANDEM/api/pt.html
"protein, homolog management"
"refine, sequence path" https://www.thegpm.org/TANDEM/api/rsp.html
 "refine, tic percent" https://www.thegpm.org/TANDEM/api/rtp.html
 "output, log path" https://www.thegpm.org/TANDEM/api/olp.html
 "output, message" https://www.thegpm.org/TANDEM/api/om.html
  "output, sequence path" https://www.thegpm.org/TANDEM/api/osp.html
   "output, path" https://www.thegpm.org/TANDEM/api/opath.html
  "protein, use annotations" https://www.thegpm.org/TANDEM/api/pua.html


   obsolete, not documented :
  "refine, maximum missed cleavage sites" 3
   "protein, use minimal annotations" yes no
   "scoring, pluggable scoring" yes no
*/

TandemParameters::TandemParameters()
{
}
TandemParameters::~TandemParameters()
{
}

TandemParameters::TandemParameters(const pappso::ProjectParameters &other)
{
  qDebug() << "copy begin";
  //_map_label_value = other._map_label_value;
  auto param_list = other.getProjectParamListByCategory(
    pappso::ProjectParamCategory::identification);

  for(auto &param : param_list)
    {
      qDebug() << "copy " << param.name << " " << param.value;
      _map_label_value.insert(param.name, param.value.toString());
    }
  qDebug() << "copy end";
}


TandemParameters::TandemParameters(const TandemParameters &other)
{
  this->operator=(other);
}

TandemParameters &
TandemParameters::operator=(const TandemParameters &other)
{

  qDebug() << "copy begin";
  //_map_label_value = other._map_label_value;
  _method_name = other._method_name;

  QMap<QString, QString>::const_iterator i =
    other._map_label_value.constBegin();
  while(i != other._map_label_value.constEnd())
    {
      qDebug() << "copy " << i.key() << " " << i.value();
      _map_label_value.insert(i.key(), i.value());
      i++; // added
    }
  qDebug() << "copy end";
  return *this;
}

void
TandemParameters::clear()
{
  _method_name = "";
  _map_label_value.clear();
}


bool
TandemParameters::equals(const TandemParameters &other) const
{
  if(_method_name != other._method_name)
    {
      return false;
    }
  if(_map_label_value.size() != other._map_label_value.size())
    {
      return false;
    }
  QMap<QString, QString>::const_iterator i = _map_label_value.constBegin();
  while(i != _map_label_value.constEnd())
    {
      if(i.value() != other.getValue(i.key()))
        {
          return false;
        }
      i++; // added
    }
  return true;
}

const QString
TandemParameters::getLabelCategory(const QString &value) const
{

  qDebug() << value;
  return value.split(", ").at(0);
}
const QString
TandemParameters::getValue(const QString &label) const
{
  qDebug() << label;
  QMap<QString, QString>::const_iterator it = _map_label_value.constFind(label);
  if(it == _map_label_value.end())
    {
      if(label == "spectrum, timstof MS2 filters")
        {
          return "";
        }
      else
        {
          throw pappso::ExceptionNotFound(
            QObject::tr(
              "X!Tandem preset label \"%1\" not found in method \"%2\"")
              .arg(label)
              .arg(_method_name));
        }
    }
  qDebug();
  return it.value();
}
void
TandemParameters::setParamLabelValue(const QString &label, const QString &value)
{
  qDebug() << label;
  // list path
  //<note type="input" label="list path, default
  // parameters">/gorgone/pappso/tmp/temp_condor_job24872841484824316495370334631825647/QExactive_analysis_FDR_nosemi.xml</note>
  //<note type="input" label="list path, taxonomy
  // information">/gorgone/pappso/tmp/temp_condor_job24872841484824316495370334631825647/database.xml</note>
  if(getLabelCategory(label) == "list path")
    {
      return;
    }

  if((label == "timing, tandemwrapper conversion time (sec)") ||
     (label == "spectrum, timstof MS2 filters") ||
     (label == "spectrum, timstof MS2 centroid parameters") ||
     (label == "output, spectrum index") || (label == "spectrum, mzFormat") ||
     (label == "output, spectrum index") || (label == "spectrum, mzFormat") ||
     (label == "output, spectrum index") || (label == "spectrum, mzFormat"))
    {
      //<note type="input" label="timing, tandemwrapper conversion time
      //(sec)">112</note> ignore it
      return;
    }

  qDebug() << label;
  if((label == "spectrum, parent monoisotopic mass error units") ||
     (label == "spectrum, fragment monoisotopic mass error units"))
    {
      if((value != "Da") && (value != "Daltons") && (value != "ppm"))
        {
          throw pappso::ExceptionNotPossible(
            QObject::tr("\"%1\" value must be Daltons or ppm (not \"%2\")")
              .arg(label)
              .arg(value));
        }
    }
  else if((label == "spectrum, parent monoisotopic mass isotope error") ||
          (label == "spectrum, use neutral loss window") ||
          (label == "spectrum, use contrast angle") ||
          (label == "protein, cleavage semi") ||
          (label == "protein, quick acetyl") ||
          (label == "protein, quick pyrolidone") ||
          (label == "protein, stP bias") ||
          (label == "scoring, cyclic permutation") ||
          (label == "scoring, include reverse") ||
          (label == "scoring, y ions") || (label == "scoring, b ions") ||
          (label == "scoring, c ions") || (label == "scoring, z ions") ||
          (label == "scoring, a ions") || (label == "scoring, x ions") ||
          (label == "refine") ||
          (label ==
           "refine, use potential modifications for full refinement") ||
          (label == "refine, cleavage semi") ||
          (label == "refine, unanticipated cleavage") ||
          (label == "refine, spectrum synthesis") ||
          (label == "refine, point mutations") ||
          (label == "output, spectra") || (label == "output, proteins") ||
          (label == "output, sequences") ||
          (label == "output, one sequence copy") ||
          (label == "output, parameters") || (label == "output, performance") ||
          (label == "output, histograms") ||
          (label == "output, path hashing") ||
          (label == "spectrum, use conditioning") ||
          (label == "protein, homolog management") ||
          (label == "protein, use minimal annotations") ||
          (label == "protein, use annotations") ||
          (label == "scoring, pluggable scoring") ||
          (label == "output, mzid") ||
          (label == "spectrum, use noise suppression"))
    {
      if((value != "yes") && (value != "no"))
        {
          throw pappso::ExceptionNotPossible(
            QObject::tr("%1 value must be yes or no (not %2)")
              .arg(label)
              .arg(value));
        }
    }

  else if((label == "spectrum, parent monoisotopic mass error minus") ||
          (label == "spectrum, parent monoisotopic mass error plus") ||
          (label == "spectrum, dynamic range") ||
          (label == "spectrum, minimum parent m+h") ||
          (label == "protein, cleavage C-terminal mass change") ||
          (label == "protein, cleavage N-terminal mass change") ||
          (label == "protein, C-terminal residue modification mass") ||
          (label == "protein, N-terminal residue modification mass") ||
          (label == "refine, maximum valid expectation value") ||
          (label == "spectrum, fragment monoisotopic mass error") ||
          (label == "spectrum, neutral loss mass") ||
          (label == "spectrum, neutral loss window") ||
          (label == "spectrum, minimum fragment mz") ||
          (label == "output, maximum valid expectation value") ||
          (label == "output, maximum valid protein expectation value") ||
          (label == "refine, tic percent")


  )

    {

      bool ok;
      QString value_bis = value.simplified();
      if(value_bis.isEmpty())
        {
          value_bis = "0.0";
        }
      value_bis.toDouble(&ok);
      if(!ok)
        { // not an integer
          throw pappso::ExceptionNotPossible(
            QObject::tr("\"%1\" value must be a number (not \"%2\")")
              .arg(label)
              .arg(value));
        }
    }
  else if((label == "protein, cleavage site") ||
          (label == "protein, modified residue mass file") ||
          (label == "residue, modification mass") ||
          (label == "residue, modification mass 1") ||
          (label == "residue, modification mass 2") ||
          (label == "residue, potential modification mass") ||
          (label == "residue, potential modification motif") ||
          (label == "refine, potential N-terminus modifications") ||
          (label == "refine, potential C-terminus modifications") ||
          (label == "refine, modification mass") ||
          (label == "refine, modification mass 1") ||
          (label == "refine, modification mass 2") ||
          (label == "refine, potential modification mass") ||
          (label == "refine, potential modification mass 1") ||
          (label == "refine, potential modification mass 2") ||
          (label == "refine, potential modification motif") ||
          (label == "refine, potential modification motif 1") ||
          (label == "refine, potential modification motif 2") ||
          (label == "output, sort results by") ||
          (label == "output, xsl path") || (label == "spectrum, path") ||
          (label == "scoring, algorithm") || (label == "protein, taxon") ||
          (label == "refine, sequence path") || (label == "output, log path") ||
          (label == "output, message") || (label == "output, sequence path") ||
          (label == "output, path") ||
          (label == "residue, potential modification mass 1") ||
          (label == "residue, potential modification mass 2") ||
          (label == "residue, potential modification mass 3") ||
          (label == "residue, potential modification motif 1") ||
          (label == "residue, potential modification motif 2") ||
          (label == "residue, potential modification motif 3"))
    {
      // string
    }
  else if((label == "spectrum, maximum parent charge") ||
          (label == "spectrum, total peaks") ||
          (label == "spectrum, minimum peaks") ||
          (label == "spectrum, sequence batch size") ||
          (label == "spectrum, threads") ||
          (label == "scoring, minimum ion count") ||
          (label == "scoring, maximum missed cleavage sites") ||
          (label == "output, histogram column width") ||
          (label == "refine, maximum missed cleavage sites"))
    {

      bool ok;
      value.toInt(&ok);
      if(!ok)
        { // not an integer
          throw pappso::ExceptionNotPossible(
            QObject::tr("\"%1\" value must be an integer (not \"%2\")")
              .arg(label)
              .arg(value));
        }
    }
  else if(label == "spectrum, fragment mass type")
    {
      if((value != "monoisotopic") && (value != "average"))
        {
          throw pappso::ExceptionNotPossible(
            QObject::tr(
              "\"%1\" value must be monoisotopic or average (not \"%2\")")
              .arg(label)
              .arg(value));
        }
    }
  // tandem input parameter label "output, results" for value "valid" not known.

  else if(label == "output, results")
    {
      /*
      if((value != "all") && (value != "valid"))
      {
        throw pappso::ExceptionNotPossible(
          QObject::tr("\"%1\" value must be valid or all (not \"%2\")")
            .arg(label)
            .arg(value));
      }
      */
    }
  else
    {

      throw pappso::ExceptionNotPossible(
        QObject::tr(
          "tandem input parameter label \"%1\" for value \"%2\" not known.")
          .arg(label)
          .arg(value));
    }


  // text "protein, cleavage site" "protein, modified residue mass file"
  // "residue, modification mass"  || (label == "refine, potential N-terminus
  // modifications") || (label == "refine, potential C-terminus modifications")
  // spectrum, neutral loss mass
  // spectrum, neutral loss window
  qDebug() << label;
  _map_label_value.insert(label, value);
  qDebug() << label;
}
void
TandemParameters::setMethodName(const QString &method)
{
  _method_name = method;
}
const QString &
TandemParameters::getMethodName() const
{
  return _method_name;
}
const QMap<QString, QString> &
TandemParameters::getMapLabelValue() const
{
  return _map_label_value;
}
