/**
 * \file pappsomspp/processing/cbor/psm/psmproteinmap.cpp
 * \date 05/07/2025
 * \author Olivier Langella
 * \brief PAPPSO CBOR protein map
 */

/*******************************************************************************
 * Copyright (c) 2025 Olivier Langella <Olivier.Langella@universite-paris-saclay.fr>.
 *
 * This file is part of PAPPSOms-tools.
 *
 *     PAPPSOms-tools 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.
 *
 *     PAPPSOms-tools 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 PAPPSOms-tools.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#include <QObject>
#include "psmproteinmap.h"
#include "pappsomspp/core/exception/exceptionnotfound.h"


pappso::cbor::psm::PsmProteinMap::PsmProteinMap()
{
}

pappso::cbor::psm::PsmProteinMap::~PsmProteinMap()
{
}


std::map<QString, pappso::cbor::psm::PsmProtein> &
pappso::cbor::psm::PsmProteinMap::getProteinMap()
{
  return m_proteinMap;
}


std::pair<std::map<QString, pappso::cbor::psm::PsmProtein>::iterator, bool>
pappso::cbor::psm::PsmProteinMap::insert(const pappso::cbor::psm::PsmProtein &psm_protein)
{
  return m_proteinMap.insert(
    std::pair<QString, PsmProtein>(psm_protein.protein_sp.get()->getAccession(), psm_protein));
}

void
pappso::cbor::psm::PsmProteinMap::writeMap(pappso::cbor::CborStreamWriter &writer) const
{
  // writer.append("protein_map");
  writer.startMap(m_proteinMap.size()); // protein map
  for(auto &protein_pair : m_proteinMap)
    {
      writer.append(protein_pair.first);

      qDebug() << protein_pair.first;
      writer.startMap(); // protein
      writer.append("description");
      writer.append(protein_pair.second.protein_sp.get()->getDescription());
      writer.append("sequence");
      writer.append(protein_pair.second.protein_sp.get()->getSequence());
      writer.append("target");
      writer.append(protein_pair.second.isTarget);
      writer.append("contaminant");
      writer.append(protein_pair.second.isContaminant);

      if(!protein_pair.second.cborEval.isEmpty())
        {
          writer.append("eval");
          writer.writeCborMap(protein_pair.second.cborEval);
        }
      writer.endMap(); // protein
    }

  writer.endMap(); // protein map
}

void
pappso::cbor::psm::PsmProteinMap::readMap(pappso::cbor::CborStreamReader &reader)
{
  PsmProtein psm_protein;
  reader.enterContainer();
  while(!reader.lastError() && reader.hasNext())
    {
      bool is_ok;

      QString accession;
      is_ok = reader.decodeString(accession);
      qDebug() << accession;
      if(is_ok)
        {
          reader.enterContainer();
          pappso::Protein protein;
          protein.setAccession(accession);
          psm_protein.protein_sp    = std::make_shared<pappso::Protein>(protein);
          psm_protein.isContaminant = false;
          psm_protein.isTarget      = true;
          auto it = m_proteinMap.insert(std::pair<QString, PsmProtein>(accession, psm_protein));

          QString tag;
          while(!reader.lastError() && reader.hasNext())
            {
              is_ok = reader.decodeString(tag);
              qDebug() << tag;
              if(is_ok)
                {
                  if(tag == "description")
                    {
                      QString description;
                      is_ok = reader.decodeString(description);
                      qDebug() << description;
                      it.first->second.protein_sp.get()->setDescription(description);
                    }
                  else if(tag == "sequence")
                    {
                      QString sequence;
                      reader.decodeString(sequence);
                      it.first->second.protein_sp.get()->setSequence(sequence);
                    }
                  else if(tag == "target")
                    {
                      it.first->second.isTarget = reader.toBool();
                      reader.next();
                    }
                  else if(tag == "contaminant")
                    {
                      it.first->second.isContaminant = reader.toBool();
                      reader.next();
                    }
                  else if(tag == "eval")
                    {
                      reader.readCborMap(it.first->second.cborEval);
                    }
                }
            }
          reader.leaveContainer();
        }
      else
        {
          // no accession
        }
      // reader.next();
      // }
    }
  reader.leaveContainer();
}

std::size_t
pappso::cbor::psm::PsmProteinMap::size() const
{
  return m_proteinMap.size();
}

const pappso::cbor::psm::PsmProtein &
pappso::cbor::psm::PsmProteinMap::getByAccession(const QString &accession) const
{
  auto it = m_proteinMap.find(accession);

  if(it == m_proteinMap.end())
    {
      throw pappso::ExceptionNotFound(QObject::tr("%1 accession not found").arg(accession));
    }
  return it->second;
}

void
pappso::cbor::psm::PsmProteinMap::merge(const PsmProteinMap &other_protein_map)
{
  for(auto &it_prot : other_protein_map.m_proteinMap)
    {
      m_proteinMap.insert(std::pair<QString, PsmProtein>(it_prot.first, it_prot.second));
    }
}

void
pappso::cbor::psm::PsmProteinMap::reduce(const QStringList &accession_list)
{
  std::map<QString, PsmProtein> new_protein_map;

  for(const QString &accession : accession_list)
    {
      new_protein_map.insert(std::pair<QString, PsmProtein>(accession, getByAccession(accession)));
    }
  m_proteinMap = new_protein_map;
}
