/**
 * \file pappsomspp/protein/protein.cpp
 * \date 2/7/2015
 * \author Olivier Langella
 * \brief object to handle a protein
 */

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

#include "protein.h"
#include "../peptide/peptide.h"
#include <QStringList>
#include <algorithm>
#include "pappsomspp/core/pappsoexception.h"

namespace pappso
{

QRegularExpression Protein::m_removeTranslationStopRegExp("\\*$");

/*
 * http://www.ncbi.nlm.nih.gov/BLAST/blastcgihelp.shtml
 */
//    For those programs that use amino acid query sequences (BLASTP and
//    TBLASTN), the accepted amino acid codes are:
//
// 		A  alanine               P  proline
// 		B  aspartate/asparagine  Q  glutamine
// 		C  cystine               R  arginine
// 		D  aspartate             S  serine
// 		E  glutamate             T  threonine
// 		F  phenylalanine         U  selenocysteine
// 		G  glycine               V  valine
// 		H  histidine             W  tryptophan
// 		I  isoleucine            Y  tyrosine
// 		K  lysine                Z  glutamate/glutamine
// 		L  leucine               X  any
// 		M  methionine            *  translation stop
// 		N  asparagine            -  gap of indeterminate length

Protein::Protein()
{
}
Protein::Protein(const QString &description, const QString &sequence)
  : m_description(description.simplified()),
    m_accession(m_description.split(" ").at(0)),
    m_sequence(sequence)
{
  m_description = m_description.remove(0, m_accession.size()).simplified();
  // m_sequence.replace(m_removeTranslationStopRegExp, "");
  m_length = m_sequence.size();
}
Protein::Protein(const Protein &protein)
  : m_description(protein.m_description),
    m_accession(protein.m_accession),
    m_sequence(protein.m_sequence),
    m_length(protein.m_length)
{
}

Protein &
Protein::removeTranslationStop()
{
  m_sequence.replace(m_removeTranslationStopRegExp, "");
  return (*this);
}

Protein &
Protein::reverse()
{
  std::reverse(m_sequence.begin(), m_sequence.end());
  return (*this);
}

ProteinSp
Protein::makeProteinSp() const
{
  return std::make_shared<Protein>(*this);
}


bool
Protein::operator==(const Protein &other) const
{
  return (m_accession == other.m_accession);
}

void
Protein::setSequence(const QString &sequence)
{
  m_sequence = sequence.simplified();
  m_length   = m_sequence.size();
}
unsigned int
Protein::size() const
{
  return m_length;
}

const QString &
Protein::getSequence() const
{
  return m_sequence;
}
const QString &
Protein::getAccession() const
{
  return m_accession;
}
void
Protein::setAccession(const QString &accession)
{
  m_accession = accession.simplified();
}
const QString &
Protein::getDescription() const
{
  return m_description;
}
void
Protein::setDescription(const QString &description)
{
  m_description = description.simplified();
}
Protein::~Protein()
{
}
pappso_double
Protein::getMass() const
{
  try
    {
      // qDebug() << "ProteinXtp::getMass() begin " <<
      // getOnlyAminoAcidSequence().replace("[BZX]","E");
      // replace amino acid wildcard by E, just to give an random mass (assumed
      // it is not perfect)
      QString sequence(m_sequence);
      sequence.replace(QRegularExpression("[^WGASPVTLINDKQEMHFRCYUBZX]"), "");
      pappso::Peptide peptide(sequence.replace(QRegularExpression("[BZX]"), "E"));
      return peptide.getMass();
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(QObject::tr("Error computing mass for protein %1 :\n%2")
                                      .arg(getAccession())
                                      .arg(error.qwhat()));
    }
}
} // namespace pappso
