/**
 * \file utils/identificationdatasourcestore.cpp
 * \date 5/4/2017
 * \author Olivier Langella
 * \brief store unique version of identification data sources (output files from
 * identification engines)
 */


/*******************************************************************************
 * 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 "identificationdatasourcestore.h"
#include "../core/identification_sources/identificationxtandemfile.h"
#include "../core/identification_sources/identificationmascotdatfile.h"
#include "../core/identification_sources/identificationpwizfile.h"
#include "../core/identification_sources/identificationpepxmlfile.h"
//#include "../core/identification_sources/identificationpsmcborfile.h"
//#include "../core/identification_sources/identificationmzidentmlfile.h"
#include "../core/identification_sources/identificationsagejsonfile.h"
#include <pappsomspp/core/pappsoexception.h>
#include <pappsomspp/core/utils.h>
#include "../utils/utils.h"

IdentificationDataSourceStore::IdentificationDataSourceStore()
{
}

IdentificationDataSourceStore::~IdentificationDataSourceStore()
{
}

IdentificationDataSourceSp
IdentificationDataSourceStore::getInstance(const QString &location,
                                           IdentificationEngine engine,
                                           const MsRunSp &ms_run_sp)
{
  // TODO file format read needs a fix
  qDebug() << "IdentificationDataSourceStore::getInstance begin " << location
           << " engine = " << Utils::getIdentificationEngineName(engine);
  std::map<QString, IdentificationDataSourceSp>::iterator it =
    _map_identification_data_sources.find(location);
  if(it != _map_identification_data_sources.end())
    {
      qDebug() << "IdentificationDataSourceStore::getInstance found "
               << location;
      return it->second;
    }
  else
    {
      QFileInfo location_file(location);
      QString ext = location_file.suffix();
      qDebug() << "IdentificationDataSourceStore::getInstance coucou 1 ";
      // QString sample_name = location_file.baseName();
      IdentificationDataSourceSp p_identfile = nullptr;
      switch(engine)
        {
          case IdentificationEngine::mascot:
            p_identfile =
              std::make_shared<IdentificationMascotDatFile>(location_file);
            break;

          case IdentificationEngine::XTandem:
            if(ext == "xml")
              {
                p_identfile =
                  std::make_shared<IdentificationXtandemFile>(location_file);
              }
            else
              {
                p_identfile = std::make_shared<IdentificationMzIdentMlFile>(
                  QFileInfo(location_file), ms_run_sp);
              }
            break;
          case IdentificationEngine::sage:
            p_identfile = std::make_shared<IdentificationSageJsonFile>(
              QFileInfo(location_file), ms_run_sp);
            break;

          case IdentificationEngine::Comet:
            p_identfile =
              std::make_shared<IdentificationPepXmlFile>(location_file);
            break;

          case IdentificationEngine::SEQUEST:
            p_identfile =
              std::make_shared<IdentificationPepXmlFile>(location_file);
            break;

          case IdentificationEngine::PEAKS_Studio:

            p_identfile = std::make_shared<IdentificationMzIdentMlFile>(
              QFileInfo(location_file), ms_run_sp);
            break;
          default:
            break;
        }

      if(p_identfile == nullptr)
        {
          throw pappso::PappsoException(
            QObject::tr("Identification resource %1 not recognized "
                        "(p_identfile == nullptr)")
              .arg(location));
        }
      qDebug() << "IdentificationDataSourceStore::getInstance coucou 2 ";
      p_identfile.get()->setXmlId(
        QString("ident%1").arg(pappso::Utils::getLexicalOrderedString(
          _map_identification_data_sources.size())));
      p_identfile.get()->setIdentificationEngine(engine);
      _map_identification_data_sources.insert(
        std::pair<QString, IdentificationDataSourceSp>(location, p_identfile));
      _map_identification_data_sources.insert(
        std::pair<QString, IdentificationDataSourceSp>(
          location_file.absoluteFilePath(), p_identfile));
      qDebug() << "IdentificationDataSourceStore::getInstance inserted "
               << location;
      return p_identfile;
    }
  throw pappso::PappsoException(
    QObject::tr("Identification resource %1 not recognized").arg(location));
}

IdentificationDataSourceSp
IdentificationDataSourceStore::getInstance(const QString &location)
{
  qDebug() << " begin " << location;
  qDebug() << " " << _map_identification_data_sources.size();
  std::map<QString, IdentificationDataSourceSp>::iterator it =
    _map_identification_data_sources.find(location);
  if(it != _map_identification_data_sources.end())
    {
      qDebug();
      return it->second;
    }
  else
    {
      QFileInfo location_file(location);
      QString ext = location_file.completeSuffix();
      // QString sample_name = location_file.baseName();
      IdentificationDataSourceSp p_identfile = nullptr;
      if((ext.toLower() == "xml") || (ext.toLower() == ".d.xml"))
        {
          // X!Tandem result file
          p_identfile =
            std::make_shared<IdentificationXtandemFile>(location_file);
        }
      else if(ext.toLower() == "pep")
        {
          // pep xml file
          p_identfile =
            std::make_shared<IdentificationPepXmlFile>(location_file);
        }
      else if(ext.toLower() == "pep.xml")
        {
          // pep xml file
          p_identfile =
            std::make_shared<IdentificationPepXmlFile>(location_file);
        }
      else if(ext.toLower() == "pepxml")
        {
          // pep xml file
          p_identfile =
            std::make_shared<IdentificationPepXmlFile>(location_file);
        }
      else if(ext.toLower() == "dat")
        {
          // MASCOT dat file
          p_identfile =
            std::make_shared<IdentificationMascotDatFile>(location_file);
        }
      else if(ext.toLower() == "cbor")
        {
          // CBOR PSM file
          // p_identfile =
          //  std::make_shared<IdentificationPsmCborFile>(location_file);
        }
      else
        {
          // p_identfile =
          // std::make_shared<IdentificationPwizFile>(location_file);
        }
      if(p_identfile == nullptr)
        {
          throw pappso::PappsoException(
            QObject::tr("Identification resource %1 not recognized (not mzid "
                        "p_identfile == nullptr)")
              .arg(location));
        }
      p_identfile.get()->setXmlId(
        QString("ident%1").arg(pappso::Utils::getLexicalOrderedString(
          _map_identification_data_sources.size())));

      _map_identification_data_sources.insert(
        std::pair<QString, IdentificationDataSourceSp>(location, p_identfile));
      _map_identification_data_sources.insert(
        std::pair<QString, IdentificationDataSourceSp>(
          location_file.absoluteFilePath(), p_identfile));
      return p_identfile;
    }
  throw pappso::PappsoException(
    QObject::tr("Identification resource %1 not recognized").arg(location));
}


std::vector<IdentificationDataSourceSp>
IdentificationDataSourceStore::getIdentificationDataSourceList() const
{
  std::vector<IdentificationDataSourceSp> idsource_list;
  for(auto &msrun_pair : _map_identification_data_sources)
    {
      idsource_list.push_back(msrun_pair.second);
    }
  return idsource_list;
}

void
IdentificationDataSourceStore::fillProjectParameters(
  pappso::ProjectParameters &parameters) const
{
  try
    {
      pappso::ProjectParam project_param;
      project_param.category = pappso::ProjectParamCategory::identification;
      std::vector<IdentificationDataSourceSp> idsource_list;
      for(auto &msrun_pair : _map_identification_data_sources)
        {
          msrun_pair.second.get()->fillProjectParameters(parameters);

          pappso::ProjectParam project_param(
            {pappso::ProjectParamCategory::identification, "", QVariant()});

          project_param.name = "AnalysisSoftware_name";
          project_param.value.setValue(
            msrun_pair.second.get()->getIdentificationEngineName());
          parameters.setProjectParam(project_param);
          project_param.name = "AnalysisSoftware_version";
          project_param.value.setValue(
            msrun_pair.second.get()->getIdentificationEngineVersion());
          parameters.setProjectParam(project_param);
        }
    }
  catch(const pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error in %1 %2 %3 :\n%4")
                                      .arg(__FUNCTION__)
                                      .arg(__FILE__)
                                      .arg(__LINE__)
                                      .arg(error.qwhat()));
    }
}

IdentificationSageJsonFileSp
IdentificationDataSourceStore::buildIdentificationSageJsonFileSp(
  const QFileInfo &location,
  int identification_source_size,
  const MsRunSp &msrun)
{
  QFile mfile(location.absoluteFilePath());
  if(!mfile.open(QFile::ReadOnly))
    {
      throw pappso::PappsoException(
        QObject::tr("Unable to read Sage JSON file %1")
          .arg(location.absoluteFilePath()));
    }
  QByteArray iContents = mfile.readAll();

  QJsonParseError parseError;
  QJsonDocument jsondoc = QJsonDocument::fromJson(iContents, &parseError);
  if(parseError.error != QJsonParseError::NoError)
    {
      throw pappso::PappsoException(
        QObject::tr("Error reading Sage JSON file %1 at %2:%3")
          .arg(location.absoluteFilePath())
          .arg(parseError.offset)
          .arg(parseError.errorString()));
    }


  return buildIdentificationSageJsonFileSp(
    location, identification_source_size, jsondoc, msrun);
}


IdentificationSageJsonFileSp
IdentificationDataSourceStore::buildIdentificationSageJsonFileSp(
  const QFileInfo &location,
  int identification_source_size,
  const QJsonDocument &jsondoc,
  const MsRunSp &msrun)
{
  QString xml_id = QString("ident%1").arg(
    pappso::Utils::getLexicalOrderedString(identification_source_size));
  IdentificationSageJsonFileSp identification_sage_sp;
  try
    {
      identification_sage_sp =
        std::make_shared<IdentificationSageJsonFile>(location, jsondoc, msrun);
    }
  catch(pappso::PappsoException &err)
    {
      throw pappso::PappsoException(
        QObject::tr("Identification resource %1 not recognized: %2")
          .arg(location.absoluteFilePath())
          .arg(err.qwhat()));
    }
  if(identification_sage_sp == nullptr)
    {
      throw pappso::PappsoException(
        QObject::tr("Identification resource %1 not recognized "
                    "(identification_sage_sp == nullptr)")
          .arg(location.absoluteFilePath()));
    }
  identification_sage_sp.get()->setXmlId(xml_id);

  _map_identification_data_sources.insert(
    std::pair<QString, IdentificationDataSourceSp>(xml_id,
                                                   identification_sage_sp));
  _map_identification_data_sources.insert(
    std::pair<QString, IdentificationDataSourceSp>(xml_id,
                                                   identification_sage_sp));
  return identification_sage_sp;
}

IdentificationMzIdentMlFileSp
IdentificationDataSourceStore::buildIdentificationMzIdentMlFileSp(
  const QFileInfo &location,
  int identification_source_size,
  const MsRunSp &msrun)
{

  QString xml_id = QString("ident%1").arg(
    pappso::Utils::getLexicalOrderedString(identification_source_size));
  IdentificationMzIdentMlFileSp identification_mzident_sp;
  try
    {
      identification_mzident_sp =
        std::make_shared<IdentificationMzIdentMlFile>(location, msrun);
    }
  catch(pappso::PappsoException &err)
    {
      throw pappso::PappsoException(
        QObject::tr("Identification resource %1 not recognized: %2")
          .arg(location.absoluteFilePath())
          .arg(err.qwhat()));
    }
  if(identification_mzident_sp == nullptr)
    {
      throw pappso::PappsoException(
        QObject::tr("Identification resource %1 not recognized "
                    "(identification_mzident_sp == nullptr)")
          .arg(location.absoluteFilePath()));
    }
  identification_mzident_sp.get()->setXmlId(xml_id);

  _map_identification_data_sources.insert(
    std::pair<QString, IdentificationDataSourceSp>(xml_id,
                                                   identification_mzident_sp));
  _map_identification_data_sources.insert(
    std::pair<QString, IdentificationDataSourceSp>(xml_id,
                                                   identification_mzident_sp));
  return identification_mzident_sp;
}
