
/*******************************************************************************
 * 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 "spomsutils.h"
#include <QJsonValue>
#include <QFile>
#include <QJsonDocument>
#include <pappsomspp/core/exception/exceptionnotfound.h>
#include <pappsomspp/core/pappsoexception.h>
#include <QJsonObject>
#include <QObject>
#include <QCborArray>
#include <QCborMap>


inline void
initMyResource()
{
  Q_INIT_RESOURCE(resources);
}
namespace pappso
{
namespace spoms
{


SpomsUtils *SpomsUtils::mp_spomsUtils = nullptr;
SpomsUtils *
SpomsUtils::GetInstance()
{
  if(mp_spomsUtils == nullptr)
    {
      initMyResource();
      mp_spomsUtils = new SpomsUtils();

      QFile jsonfile(":/json/resources/json/spoms_default_parameters.json");
      if(!jsonfile.exists())
        {
          throw PappsoException(
            QObject::tr("JSON parameter resource file : %1 not found")
              .arg(jsonfile.fileName()));
        }

      QJsonDocument json_document;
      QJsonParseError parseError;

      if(!jsonfile.open(QIODevice::ReadOnly))
        {
          throw pappso::PappsoException(
            QObject::tr("error reading json from file %1")
              .arg(jsonfile.fileName()));
        }


      QByteArray jsonData = jsonfile.readAll();
      // ConsoleOut::mcq_cerr() << jsonData;
      json_document = QJsonDocument::fromJson(jsonData, &parseError);

      if(parseError.error != QJsonParseError::ParseError::NoError)
        {
          throw pappso::PappsoException(
            QObject::tr("error parsing json from stdin, at byte %2:\n%1")
              .arg(parseError.errorString())
              .arg(parseError.offset));
        }
      mp_spomsUtils->setJsonParameters(json_document.object());
    }
  return mp_spomsUtils;
}
bool
SpomsUtils::getParameterValueOrDefault(const QString &section,
                                       const QString &name,
                                       bool bool_default_value) const
{
  try
    {
      return getParameterValue(section, name).toBool();
    }
  catch(const pappso::ExceptionNotFound &not_found)
    {
      return bool_default_value;
    }
}

int
SpomsUtils::getParameterValueOrDefault(const QString &section,
                                       const QString &name,
                                       int int_default_value) const
{
  try
    {
      return getParameterValue(section, name).toInt();
    }
  catch(const pappso::ExceptionNotFound &not_found)
    {
      return int_default_value;
    }
}
QJsonValue
SpomsUtils::getParameterValue(const QString &section, const QString &name) const
{
  QJsonValue value;
  if(section.isEmpty())
    {
      return m_spomsParameters.value(name);
    }
  if(m_spomsParameters.contains(section))
    {

      if(m_spomsParameters.value(section).toObject().contains(name))
        {
          QJsonObject section_params =
            m_spomsParameters.value(section).toObject();

          return section_params.value(name);
        }
      else
        {
          throw pappso::ExceptionNotFound(
            QObject::tr(
              "parameter %1 not defined in %2 section from Spoms JSON "
              "parameters")
              .arg(name)
              .arg(section));
        }
    }
  else
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("section %1 not found in Spoms JSON parameters")
          .arg(section));
    }
  return value;
}

void
SpomsUtils::setParameterValue(const QString &section,
                              const QString &name,
                              bool true_or_false)
{
  if(m_spomsParameters.contains(section))
    {
      QJsonObject section_object = m_spomsParameters.value(section).toObject();

      section_object.insert(name, true_or_false);

      m_spomsParameters.insert(section, section_object);
    }
  else
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("section %1 not found in Spoms JSON parameters")
          .arg(section));
    }
}

void
SpomsUtils::setParameterValue(const QString &section,
                              const QString &name,
                              int number)
{
  if(m_spomsParameters.contains(section))
    {
      QJsonObject section_object = m_spomsParameters.value(section).toObject();

      section_object.insert(name, number);

      m_spomsParameters.insert(section, section_object);
    }
  else
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("section %1 not found in Spoms JSON parameters")
          .arg(section));
    }
}


void
SpomsUtils::setParameterValue(const QString &section,
                              const QString &name,
                              double number)
{

  if(m_spomsParameters.contains(section))
    {
      QJsonObject section_object = m_spomsParameters.value(section).toObject();

      section_object.insert(name, number);

      m_spomsParameters.insert(section, section_object);
    }
  else
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("section %1 not found in Spoms JSON parameters")
          .arg(section));
    }
}

void
SpomsUtils::setJsonParameters(const QJsonObject &json_params)
{

  m_fragmentTolerance = pappso::PrecisionFactory::getDaltonInstance(0.02);
  m_spomsParameters   = json_params;

  if(getParameterValue("spectrum", "fragment_tolerance_unit").toString() ==
     "dalton")
    {
      m_fragmentTolerance = pappso::PrecisionFactory::getDaltonInstance(
        getParameterValue("spectrum", "fragment_tolerance").toDouble());
    }
  else if(getParameterValue("spectrum", "fragment_tolerance_unit").toString() ==
          "ppm")
    {
      m_fragmentTolerance = pappso::PrecisionFactory::getPpmInstance(
        getParameterValue("spectrum", "fragment_tolerance").toDouble());
    }

  m_ms2accuracy = m_fragmentTolerance->getNominal();
}

const QJsonObject &
SpomsUtils::getJsonParameters() const
{
  return m_spomsParameters;
}

pappso::PrecisionPtr
SpomsUtils::getFragmentTolerance() const
{
  return m_fragmentTolerance;
}
const QString
SpomsUtils::massToString(double mass)
{
  return QString::number(mass, 'g', 6);
}

double
SpomsUtils::getMs2Accuracy() const
{
  // la precision concernant la masse des pics
  return m_ms2accuracy;
}

int
SpomsUtils::getRealTimeSave() const
{

  //// le nombre de spectre traites entre chaque sauvegarde
  // REAL_TIME_SAVE = 500;
  return 500;
}

int
SpomsUtils::getNbMinAaFound() const
{
  // NB_MIN_AA_FOUND = 10; // le nombre minimum d'AA devant etre present dans un
  // spectre pour que celui-ci soit considere
  return 10;
}
int
SpomsUtils::getInitialisationScorePost()
{
  if(m_initialisationScorePost < 0)
    {
      QJsonObject score         = getPostTreatmentScoreGrid();
      m_initialisationScorePost = score.value("found_with_shift_post").toInt() -
                                  score.value("certainly_found_post").toInt() -
                                  1;
      // FOUND_WITH_SHIFT_POST - CERTAINLY_FOUND_POST - 1;
    }
  return m_initialisationScorePost;
}

int
SpomsUtils::getInitialisationScoreMain()
{
  if(m_initialisationScoreMain < 0)
    {
      QJsonObject score         = getAlignmentScoreGrid();
      m_initialisationScoreMain = score.value("found_with_shift_main").toInt() -
                                  score.value("certainly_found_main").toInt() -
                                  1;
      // FOUND_WITH_SHIFT_POST - CERTAINLY_FOUND_POST - 1;
    }
  return m_initialisationScoreMain;
}

const QJsonObject
SpomsUtils::getDefaultParameterObject(const QString &section,
                                      const QString &name) const
{
  QFile jsonfile(":/json/resources/json/spoms_default_parameters.json");

  QJsonDocument json_document;
  QJsonParseError parseError;

  if(!jsonfile.open(QIODevice::ReadOnly))
    {
      throw pappso::PappsoException(
        QObject::tr("error reading json from file %1")
          .arg(jsonfile.fileName()));
    }


  QByteArray jsonData = jsonfile.readAll();
  // ConsoleOut::mcq_cerr() << jsonData;
  json_document = QJsonDocument::fromJson(jsonData, &parseError);

  return json_document.object()
    .value(section)
    .toObject()
    .value(name)
    .toObject();
}

const QJsonObject
SpomsUtils::getAlignmentScoreGrid() const
{
  try
    {
      return getParameterValue("alignment", "score").toObject();
    }
  catch(const pappso::ExceptionNotFound &not_found)
    {
      return getDefaultParameterObject("alignment", "score");
    }
}
const QJsonObject
SpomsUtils::getPostTreatmentScoreGrid() const
{
  try
    {
      return getParameterValue("post_treatment", "score").toObject();
    }
  catch(const pappso::ExceptionNotFound &not_found)
    {
      return getDefaultParameterObject("post_treatment", "score");
    }
}

QCborMap
SpomsUtils::getMassSpectrumCborMap(const pappso::Trace &mass_spectrum) const
{
  QCborMap trace_map;

  QCborArray mz_cbor;
  QCborArray intensity_cbor;
  for(const pappso::DataPoint &data_point : mass_spectrum)
    {
      mz_cbor.append(data_point.x);
      intensity_cbor.append(data_point.y);
    }
  trace_map.insert(QString("mz"), mz_cbor);
  trace_map.insert(QString("intensity"), intensity_cbor);
  return trace_map;
}
} // namespace spoms
} // namespace pappso
