/**
 * \file utils/peptideevidencestore.cpp
 * \date 18/11/2017
 * \author Olivier Langella
 * \brief store unique instances of peptide evidences
 */


/*******************************************************************************
 * 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 "peptideevidencestore.h"
#include <QDebug>
#include <pappsomspp/core/pappsoexception.h>

#include "../core/peptideevidence.h"
#include "../core/msrun.h"
#include "../core/peptidextp.h"

std::shared_ptr<PeptideEvidence> &
PeptideEvidenceStore::recordInstance(const PeptideEvidence *p_peptide_evidence)
{
  _peptide_evidence_list.push_back(p_peptide_evidence->makePeptideEvidenceSp());

  // qDebug() << "PeptideEvidenceStore::getInstance end " <<
  // find_it->second.get()->getScan() << " size=" <<
  // _multimap_scan_evidence.size();
  return _peptide_evidence_list.back();
}

std::shared_ptr<PeptideEvidence> &
PeptideEvidenceStore::getInstance(const PeptideEvidence *p_peptide_evidence)
{
  // qDebug() << __FILE__ << " " << __FUNCTION__<< " " << __LINE__ << " scan="
  // << p_peptide_evidence->getScan(); qDebug() <<
  // "PeptideEvidenceStore::getInstance begin" ;
  std::multimap<unsigned int, PeptideEvidenceSp>::iterator it =
    _multimap_scan_evidence.find(p_peptide_evidence->getScanNumber());
  std::multimap<unsigned int, PeptideEvidenceSp>::iterator find_it =
    _multimap_scan_evidence.end();


  while((find_it == _multimap_scan_evidence.end()) &&
        (it->first == p_peptide_evidence->getScanNumber()) && (it != find_it))
    {
      if(it->second.get()->getPeptideXtpSp().get() ==
         p_peptide_evidence->getPeptideXtpSp().get())
        {
          // it is the same peptide
          find_it = it;
        }
      else
        {
          // throw
          // pappso::PappsoException(QObject::tr("PeptideEvidenceStore::getInstance
          // multiple peptide for scan %1").arg(p_peptide_evidence->getScan()));
        }
      it++;
    }

  if(find_it == _multimap_scan_evidence.end())
    {
      // insert it
      find_it = _multimap_scan_evidence.insert(
        std::pair<unsigned int, PeptideEvidenceSp>(
          p_peptide_evidence->getScanNumber(),
          p_peptide_evidence->makePeptideEvidenceSp()));
      _peptide_evidence_list.push_back(find_it->second);
    }
  // qDebug() << "PeptideEvidenceStore::getInstance end " <<
  // find_it->second.get()->getScan() << " size=" <<
  // _multimap_scan_evidence.size(); qDebug() << __FILE__ << " " <<
  // __FUNCTION__<< " " << __LINE__;
  return find_it->second;
}


std::size_t
PeptideEvidenceStore::size() const
{
  return _peptide_evidence_list.size();
}

void
PeptideEvidenceStore::clearMap()
{
  qDebug();
  _multimap_scan_evidence.clear();
  qDebug();
}

void
PeptideEvidenceStore::updateAutomaticFilters(
  const AutomaticFilterParameters &automatic_filter_parameters,
    std::map<const PeptideXtp *, std::set<const MsRun *>>
      &count_msrun_by_valid_peptide)
{
  qDebug();

  std::size_t peprepro_by_msrun =
    automatic_filter_parameters.getFilterPeptideObservedInLessSamplesThan();

  for(PeptideEvidenceSp &peptide_evidence_sp : _peptide_evidence_list)
    {
      peptide_evidence_sp.get()->updateAutomaticFilters(
        automatic_filter_parameters);

      if(peprepro_by_msrun > 1)
        {
          if(peptide_evidence_sp.get()->isValidAndChecked())
            {
              auto it_count = count_msrun_by_valid_peptide.insert(
                {peptide_evidence_sp.get()->getPeptideXtpSp().get(),
                 std::set<const MsRun *>()});
              it_count.first->second.insert(
                peptide_evidence_sp.get()->getMsRunPtr());
            }
        }
    }
}


void
PeptideEvidenceStore::pepreproFilter(
  const AutomaticFilterParameters &automatic_filter_parameters,
    std::map<const PeptideXtp *, std::set<const MsRun *>>
      &count_msrun_by_valid_peptide)
{
  
  std::size_t peprepro_by_msrun =
    automatic_filter_parameters.getFilterPeptideObservedInLessSamplesThan();
  if(peprepro_by_msrun > 1)
    {
      for(PeptideEvidenceSp &peptide_evidence_sp : _peptide_evidence_list)
        {
          if(peptide_evidence_sp.get()->isValid())
            {
              if(count_msrun_by_valid_peptide
                   .at(peptide_evidence_sp.get()->getPeptideXtpSp().get())
                   .size() < peprepro_by_msrun)
                {
                  peptide_evidence_sp.get()->setValid(false);
                }
            }
        }
    }
  qDebug();
}

const std::vector<std::shared_ptr<PeptideEvidence>> &
PeptideEvidenceStore::getPeptideEvidenceList() const
{
  return _peptide_evidence_list;
}


void
PeptideEvidenceStore::getSameXicPeptideEvidenceList(
  std::vector<const PeptideEvidence *> &peptide_evidence_list,
  const MsRun *p_msrun,
  const PeptideXtp *p_peptide,
  unsigned int charge) const
{
  for(const PeptideEvidenceSp &peptide_evidence_sp : _peptide_evidence_list)
    {
      if(p_msrun != peptide_evidence_sp.get()->getMsRunP())
        continue;
      else if(p_peptide != peptide_evidence_sp.get()->getPeptideXtpSp().get())
        continue;
      else if(charge != peptide_evidence_sp.get()->getCharge())
        continue;
      peptide_evidence_list.push_back(peptide_evidence_sp.get());
    }
}

void
PeptideEvidenceStore::ensureSpectrumIndexRef()
{
  qDebug();
  for(PeptideEvidenceSp &peptide_evidence_sp : _peptide_evidence_list)
    {
      peptide_evidence_sp.get()->setIsSpectrumIndex(true);
    }
  qDebug();
}

std::size_t
PeptideEvidenceStore::countUniqueValidSpectrumIndexList() const
{
  std::vector<std::size_t> spectra_set;
  for(const PeptideEvidenceSp &peptide_evidence_sp : _peptide_evidence_list)
    {
      if(peptide_evidence_sp.get()->isValid())
        spectra_set.push_back(peptide_evidence_sp.get()->getUniqueIndex());
    }

  std::sort(spectra_set.begin(), spectra_set.end());

  return std::distance(spectra_set.begin(),
                       std::unique(spectra_set.begin(), spectra_set.end()));
}

std::size_t
PeptideEvidenceStore::countSequenceLi(ValidationState valid_status) const
{
  std::vector<QString> sequence_set;
  for(const PeptideEvidenceSp &peptide_evidence_sp : _peptide_evidence_list)
    {
      if(peptide_evidence_sp.get()->getValidationState() >= valid_status)
        {
          sequence_set.push_back(peptide_evidence_sp.get()
                                   ->getPeptideXtpSp()
                                   .get()
                                   ->getSequenceLi());
        }
    }

  std::sort(sequence_set.begin(), sequence_set.end());

  return std::distance(sequence_set.begin(),
                       std::unique(sequence_set.begin(), sequence_set.end()));
}
