/**
 * \file utils/proteinstore.cpp
 * \date 23/3/2017
 * \author Olivier Langella
 * \brief store unique version of proteins
 */

/*******************************************************************************
 * 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 "proteinstore.h"
#include "../files/fastafile.h"
#include <QDebug>
#include <QSettings>


ProteinStore::ProteinStore()
{
  QSettings settings;

  _regexp_contaminant.setPattern(
    settings.value("automatic_filter/contaminant_regexp", "^conta\\|")
      .toString());
  _regexp_decoy.setPattern(
    settings.value("automatic_filter/decoy_regexp", ".*\\|reversed$")
      .toString());
}

ProteinStore::~ProteinStore()
{
}
std::size_t
ProteinStore::size() const
{
  return _map_accession_protein_list.size();
}

const std::vector<const FastaFile *> &
ProteinStore::getContaminantFastaFileList() const
{
  return _fasta_contaminant_list;
}
const std::vector<const FastaFile *> &
ProteinStore::getDecoyFastaFileList() const
{
  return _fasta_decoy_list;
}
QRegularExpression
ProteinStore::getRegexpContaminant() const
{
  return (_regexp_contaminant);
}
void
ProteinStore::setRegexpContaminantPattern(const QString &pattern)
{
  setContaminantSelectionType(ContaminantSelectionType::regexp);
  _regexp_contaminant.setPattern(pattern);

  for(std::pair<const QString, ProteinXtpSp> &acc_protein :
      _map_accession_protein_list)
    {
      setProteinInformations(acc_protein.second);
    }
  QSettings settings;
  settings.setValue("automatic_filter/contaminant_regexp", pattern);
}
QRegularExpression
ProteinStore::getRegexpDecoy() const
{
  return (_regexp_decoy);
}

const std::map<QString, ProteinXtpSp> &
ProteinStore::getProteinMap() const
{
  return _map_accession_protein_list;
}

void
ProteinStore::setRegexpDecoyPattern(const QString &pattern)
{
  _regexp_decoy.setPattern(pattern);
  setDecoySelectionType(DecoySelectionType::regexp);

  for(std::pair<const QString, ProteinXtpSp> &acc_protein :
      _map_accession_protein_list)
    {
      setProteinInformations(acc_protein.second);
    }
  QSettings settings;
  settings.setValue("automatic_filter/decoy_regexp", pattern);
}

void
ProteinStore::clearDecoys()
{
  _fasta_decoy_list.clear();
  for(std::pair<const QString, ProteinXtpSp> &acc_protein :
      _map_accession_protein_list)
    {
      acc_protein.second.get()->setIsDecoy(false);
    }
}
void
ProteinStore::clearContaminants()
{
  _fasta_contaminant_list.clear();
  for(std::pair<const QString, ProteinXtpSp> &acc_protein :
      _map_accession_protein_list)
    {
      acc_protein.second.get()->setIsContaminant(false);
    }
}

void
ProteinStore::addContaminantFastaFile(const FastaFile *p_fasta_file)
{
  qDebug() << p_fasta_file->getAbsoluteFilePath();
  _fasta_contaminant_list.push_back(p_fasta_file);
}
void
ProteinStore::addDecoyFastaFile(const FastaFile *p_fasta_file)
{
  _fasta_decoy_list.push_back(p_fasta_file);
}


void
ProteinStore::setDecoyAccession(QString accession)
{
  std::map<QString, ProteinXtpSp>::iterator it =
    _map_accession_protein_list.find(accession);
  if(it != _map_accession_protein_list.end())
    {
      it->second.get()->setIsDecoy(true);
    }
}
void
ProteinStore::setContaminantAccession(QString accession)
{
  std::map<QString, ProteinXtpSp>::iterator it =
    _map_accession_protein_list.find(accession);
  if(it != _map_accession_protein_list.end())
    {
      it->second.get()->setIsContaminant(true);
    }
}
ProteinXtpSp &
ProteinStore::getInstance(ProteinXtpSp &protein_in)
{

  std::pair<std::map<QString, ProteinXtpSp>::iterator, bool> ret =
    _map_accession_protein_list.insert(std::pair<QString, ProteinXtpSp>(
      protein_in.get()->getAccession(), protein_in));

  if(ret.second)
    {
      // the protein is new in the store, update content
      setProteinInformations(ret.first->second);

      if(ret.first->second.get()->getDbxrefList().size() == 0)
        {
          ret.first->second.get()->parseAccession2dbxref();
        }
    }
  return (ret.first->second);
}

void
ProteinStore::setProteinInformations(ProteinXtpSp &protein_in)
{
  // qDebug() << "ProteinStore::setProteinInformations begin" <<
  // peptide_in.get()->getSequence();
  QString accession = protein_in.get()->getAccession();

  if(getContaminantSelectionType() == ContaminantSelectionType::regexp)
    {
      protein_in.get()->setIsContaminant(false);
      if((!_regexp_contaminant.pattern().isEmpty()) &&
         (_regexp_contaminant.match(accession).hasMatch()))
        {
          // qDebug() << "ProteinStore::setProteinInformations is contaminant "
          // << accession;
          protein_in.get()->setIsContaminant(true);
        }
    }

  if(getDecoySelectionType() == DecoySelectionType::regexp)
    {
      protein_in.get()->setIsDecoy(false);
      if((!_regexp_decoy.pattern().isEmpty()) &&
         (_regexp_decoy.match(accession).hasMatch()))
        {
          protein_in.get()->setIsDecoy(true);
        }
    }
  // qDebug() << "ProteinStore::setProteinInformations end";
}

void
ProteinStore::setContaminantSelectionType(
  ContaminantSelectionType cont_select_type)
{
  m_contaminantSelectionType = cont_select_type;
}

ContaminantSelectionType
ProteinStore::getContaminantSelectionType() const
{
  return m_contaminantSelectionType;
}

void
ProteinStore::setDecoySelectionType(DecoySelectionType decoy_select_type)
{
  m_decoySelectionType = decoy_select_type;
}

DecoySelectionType
ProteinStore::getDecoySelectionType() const
{
  return m_decoySelectionType;
}
