/**
 * \file utils/peptidestore.h
 * \date 7/10/2016
 * \author Olivier Langella
 * \brief store unique version of peptides
 */

/*******************************************************************************
 * Copyright (c) 2016 Olivier Langella <Olivier.Langella@moulon.inra.fr>.
 *
 * This file is part of peptider.
 *
 *     peptider 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.
 *
 *     peptider 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 peptider.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@moulon.inra.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "peptidestore.h"
#include <pappsomspp/core/amino_acid/aa.h>
#include <pappsomspp/core/pappsoexception.h>
#include <QSettings>

PeptideStore::PeptideStore()
{

  QSettings settings;
  m_checkSequenceCrc =
    settings.value("global/sequence_crc_check", "false").toBool();
  qInfo() << "m_checkSequenceCrc=" << m_checkSequenceCrc;
}

PeptideStore::~PeptideStore()
{
}

PeptideXtpSp &
PeptideStore::getInstance(PeptideXtpSp &peptide_in)
{

  std::size_t sequence_crc =
    _hash_fn(peptide_in.get()->toAbsoluteString().toStdString());

  // QByteArray source = peptide_in.get()->getLiAbsoluteString().toUtf8();
  // quint16 sequence_li_crc = qChecksum(source.data(), source.length());

  std::pair<std::unordered_map<std::size_t, PeptideXtpSp>::iterator, bool> ret =
    _map_crc_peptide_list.insert(
      std::pair<std::size_t, PeptideXtpSp>(sequence_crc, peptide_in));
  if(ret.second)
    {
      // if new peptide in store
      // Nter
      PeptideXtpSp current_peptide = ret.first->second;
      pappso::AaModificationP nter_cter_modp =
        current_peptide.get()->getNterModification();
      if(nter_cter_modp != nullptr)
        {
          _modification_collection.insert(nter_cter_modp);
        }
      // Cter
      nter_cter_modp = current_peptide.get()->getCterModification();
      if(nter_cter_modp != nullptr)
        {
          _modification_collection.insert(nter_cter_modp);
        }

      for(auto &&aa : *(current_peptide.get()))
        {
          std::vector<pappso::AaModificationP> mod_list =
            aa.getModificationList();
          _modification_collection.insert(mod_list.begin(), mod_list.end());
        }
    }
  else
    {
      if(m_checkSequenceCrc)
        {
          // check sequence crc :
          if(ret.first->second.get()->toAbsoluteString() !=
             peptide_in.get()->toAbsoluteString())
            {
              throw pappso::PappsoException(
                QObject::tr(
                  "hash function to find sequence crc failed between %1 "
                  "and %2 that gave same crc : %3")
                  .arg(ret.first->second.get()->toAbsoluteString())
                  .arg(peptide_in.get()->toAbsoluteString().arg(sequence_crc)));
            }
        }
    }
  return ret.first->second;
}

std::size_t
PeptideStore::size() const
{
  return _map_crc_peptide_list.size();
}

bool
PeptideStore::replaceModification(pappso::AaModificationP oldmod,
                                  pappso::AaModificationP newmod)
{
  for(std::pair<std::size_t, PeptideXtpSp> pair_peptide : _map_crc_peptide_list)
    {
      PeptideXtpSp peptide_xtp = pair_peptide.second;
      peptide_xtp.get()->replaceAaModification(oldmod, newmod);
    }
  _modification_collection.erase(oldmod);
  _modification_collection.insert(newmod);
  return true;
}


bool
PeptideStore::replaceModificationOnAminoAcid(pappso::Enums::AminoAcidChar aa,
                                             pappso::AaModificationP oldmod,
                                             pappso::AaModificationP newmod)
{
  bool still_exist = false;
  for(std::pair<std::size_t, PeptideXtpSp> pair_peptide : _map_crc_peptide_list)
    {
      PeptideXtpSp peptide_xtp = pair_peptide.second;
      peptide_xtp.get()->replaceAaModificationOnAminoAcid(aa, oldmod, newmod);

      if(peptide_xtp.get()->getNumberOfModification(oldmod) > 0)
        {
          still_exist = true;
        }
    }
  if(still_exist == false)
    _modification_collection.erase(oldmod);
  _modification_collection.insert(newmod);
  return true;
}
void
PeptideStore::clearLabelingMethod()
{
  for(std::pair<std::size_t, PeptideXtpSp> pair_peptide : _map_crc_peptide_list)
    {
      PeptideXtpSp peptide_xtp = pair_peptide.second;
      peptide_xtp.get()->clearLabel();
    }
}
const std::set<pappso::AaModificationP> &
PeptideStore::getModificationCollection() const
{
  return _modification_collection;
}
bool
PeptideStore::checkPsimodCompliance() const
{
  for(pappso::AaModificationP modification : _modification_collection)
    {
      if(modification->isInternal())
        {
        }
      else if(modification->getAccession().startsWith("MOD:"))
        {
        }
      else if(modification->getAccession().startsWith("UNIMOD:"))
        {
        }
      else if(modification->getAccession().startsWith("USER:"))
        {
        }
      else if(modification->getAccession().startsWith("C13N15:"))
        {
        }
      else if(modification->getAccession().startsWith("MUTATION:"))
        {
        }
      else
        {
          throw pappso::PappsoException(
            QObject::tr("Modification %1 is not a PSIMOD accession. Please "
                        "go into the edit=>modifications menu to replace "
                        "modifications masses by PSIMOD accessions")
              .arg(modification->getAccession()));
        }
    }
  return true;
}

void
PeptideStore::setLabelingMethodSp(LabelingMethodSp labeling_method_sp)
{
  if(_labeling_method_sp != nullptr)
    {
      clearLabelingMethod();
    }
  _labeling_method_sp = labeling_method_sp;
  for(std::pair<std::size_t, PeptideXtpSp> pair_peptide : _map_crc_peptide_list)
    {
      PeptideXtpSp peptide_xtp = pair_peptide.second;
      peptide_xtp.get()->applyLabelingMethod(labeling_method_sp);
    }
}

const std::unordered_map<std::size_t, PeptideXtpSp> &
PeptideStore::getPeptideMap() const
{
  return _map_crc_peptide_list;
}
