/**
 * \file utils/peptideevidence.cpp
 * \date 18/11/2017
 * \author Olivier Langella
 * \brief peptide evidence : a peptide sequence + spectrum + identification
 * engine evaluation (psm)
 */


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

#include "peptideevidence.h"
#include <pappsomspp/pappsoexception.h>

std::hash<std::string> PeptideEvidence::_hash_fn;

PeptideEvidence::PeptideEvidence(MsRun *msrunid_sp, std::size_t scan_index)
{
  _msrunid_sp   = msrunid_sp;
  m_scan_number = scan_index;

  _hash_sample_scan      = PeptideEvidence::_hash_fn(QString("%1 %2")
                                                  .arg(msrunid_sp->getXmlId())
                                                  .arg(m_scan_number)
                                                  .toStdString());
  _identification_engine = IdentificationEngine::unknown;
}

PeptideEvidence::PeptideEvidence(const PeptideEvidence &other)
  : PeptideEvidence(other._msrunid_sp, other.m_scan_number)
{
  _hash_sample_scan        = other._hash_sample_scan;
  _sp_grp_peptide          = other._sp_grp_peptide;
  _peptide_sp              = other._peptide_sp;
  _rt                      = other._rt;
  _evalue                  = other._evalue;
  _exp_mass                = other._exp_mass;
  _charge                  = other._charge;
  _p_identification_source = other._p_identification_source;
  _params                  = other._params;
  _checked                 = other._checked;
  _proxy_valid             = other._proxy_valid;
  _identification_engine   = other._identification_engine;
  m_scan_number            = other.m_scan_number;
}

PeptideEvidence::~PeptideEvidence()
{
}

pappso::pappso_double
PeptideEvidence::getTheoreticalMz() const
{
  return (getPeptideXtpSp().get()->getMz(getCharge()));
}

PeptideEvidenceSp
PeptideEvidence::makePeptideEvidenceSp() const
{
  return std::make_shared<PeptideEvidence>(*this);
}

void
PeptideEvidence::updateAutomaticFilters(
  const AutomaticFilterParameters &automatic_filter_parameters)
{
  _proxy_valid =
    this->_p_identification_source->isValid(this, automatic_filter_parameters);

  if(_proxy_valid)
    {
      unsigned int peprepro =
        automatic_filter_parameters.getFilterPeptideObservedInLessSamplesThan();
      if(peprepro > 1)
        {
          if(this->getPeptideXtpSp().get()->getObservedMsrunList().size() <
             peprepro)
            {
              _proxy_valid = false;
              return;
            }
        }
    }
}
void
PeptideEvidence::setRetentionTime(pappso::pappso_double rt)
{
  _rt = rt;
}
void
PeptideEvidence::setEvalue(pappso::pappso_double evalue)
{
  _evalue = evalue;
}


void
PeptideEvidence::setIdentificationEngine(
  IdentificationEngine identification_engine)
{
  _identification_engine = identification_engine;
}

IdentificationEngine
PeptideEvidence::getIdentificationEngine() const
{
  return _identification_engine;
}

/** \brief set specific parameter value
 */
void
PeptideEvidence::setParam(PeptideEvidenceParam param, const QVariant &value)
{
  auto ret =
    _params.insert(std::pair<PeptideEvidenceParam, QVariant>(param, value));

  if(ret.second == false)
    {
      ret.first->second = value;
    }
}
const QVariant
PeptideEvidence::getParam(PeptideEvidenceParam param) const
{
  try
    {
      return _params.at(param);
    }
  catch(std::out_of_range &std_error)
    {
      return QVariant();
    }
}
const std::map<PeptideEvidenceParam, QVariant> &
PeptideEvidence::getParamList() const
{
  return _params;
}

std::size_t
PeptideEvidence::getHashPeptideMassSample() const
{
  return PeptideEvidence::_hash_fn(QString("%1 %2")
                                     .arg(_peptide_sp.get()->toAbsoluteString())
                                     .arg(_msrunid_sp->getXmlId())
                                     .toStdString());
}

std::size_t
PeptideEvidence::getHashSampleScan() const
{
  return _hash_sample_scan;
}
pappso::pappso_double
PeptideEvidence::getEvalue() const
{
  return _evalue;
}
pappso::pappso_double
PeptideEvidence::getExperimentalMass() const
{
  return _exp_mass;
}
pappso::pappso_double
PeptideEvidence::getExperimentalMhplus() const
{
  return _exp_mass + pappso::MHPLUS;
}

pappso::pappso_double
PeptideEvidence::getExperimentalMz() const
{
  pappso::pappso_double mz = _exp_mass;
  for(unsigned int i = 0; i < _charge; i++)
    {
      mz += pappso::MHPLUS;
    }
  mz = mz / _charge;
  return mz;
}
void
PeptideEvidence::setExperimentalMass(pappso::pappso_double exp_mass)
{
  _exp_mass = exp_mass;
}
pappso::pappso_double
PeptideEvidence::getDeltaMass() const
{
  return ((_exp_mass + pappso::MHPLUS) - _peptide_sp.get()->getMz(1));
}
pappso::pappso_double
PeptideEvidence::getPpmDeltaMass() const
{
  // return (_peptide_sp.get()->getMz(1) - (_exp_mass+pappso::MHPLUS));
  pappso::pappso_double diff = getDeltaMass();
  while(diff > 0.5)
    {
      diff = diff - pappso::DIFFC12C13;
    }
  diff = (diff / getPeptideXtpSp().get()->getMz(1)) * pappso::ONEMILLION;
  return diff;
}
void
PeptideEvidence::setCharge(unsigned int charge)
{
  _charge = charge;
}

void
PeptideEvidence::setPeptideXtpSp(PeptideXtpSp peptide)
{
  _peptide_sp = peptide;
  _peptide_sp.get()->observedInMsRun(_msrunid_sp);
}

void
PeptideEvidence::setChecked(bool arg1)
{
  _checked = arg1;
}

ValidationState
PeptideEvidence::getValidationState() const
{
  if(isGrouped())
    {
      return ValidationState::grouped;
    }
  else if(isValidAndChecked())
    {
      return ValidationState::validAndChecked;
    }
  else if(isValid())
    {
      return ValidationState::valid;
    }
  return ValidationState::notValid;
}

bool
PeptideEvidence::isValid() const
{
  return _proxy_valid;
}
bool
PeptideEvidence::isChecked() const
{
  return _checked;
}

bool
PeptideEvidence::isValidAndChecked() const
{
  return _proxy_valid && _checked;
}

bool
PeptideEvidence::isGrouped() const
{
  if(_sp_grp_peptide.get() == nullptr)
    {
      return false;
    }
  if(_sp_grp_peptide.get()->getGroupNumber() == 0)
    {
      return false;
    }
  return true;
}
void
PeptideEvidence::setIdentificationDataSource(
  IdentificationDataSource *identification_source)
{
  _p_identification_source = identification_source;

  if(_identification_engine == IdentificationEngine::unknown)
    {
      _identification_engine = identification_source->getIdentificationEngine();
    }
}
IdentificationDataSource *
PeptideEvidence::getIdentificationDataSource() const
{
  return _p_identification_source;
}
unsigned int
PeptideEvidence::getScanNumber() const
{
  return m_scan_number;
}
pappso::pappso_double
PeptideEvidence::getRetentionTime() const
{
  return _rt;
}

pappso::pappso_double
PeptideEvidence::getHardenedRetentionTime() const
{
  if(_rt == 0)
    {
      // try to look at mz data file
      if(_p_identification_source != nullptr)
        {
          MsRunSp msrunsp = _p_identification_source->getMsRunSp();
          if(msrunsp != nullptr)
            {
              pappso::MsRunReaderSPtr reader =
                msrunsp.get()->getMsRunReaderSPtr();
              if(reader != nullptr)
                {
                  pappso::QualifiedMassSpectrum qmassspec =
                    reader.get()->qualifiedMassSpectrum(m_scan_number, false);

                  return qmassspec.getRtInSeconds();
                }
            }
        }
    }
  return _rt;
}

unsigned int
PeptideEvidence::getCharge() const
{
  return _charge;
}

const PeptideXtpSp &
PeptideEvidence::getPeptideXtpSp() const
{
  // if (_sp_grp_peptide.get() == nullptr) {
  //    throw pappso::PappsoException(QObject::tr("Peptide is null in %1
  //    %2").arg(_msrunid_sp->getXmlId()).arg(this->getScan()));
  //}
  return _peptide_sp;
}

const MsRun *
PeptideEvidence::getMsRunP() const
{
  return _msrunid_sp;
}


MsRun *
PeptideEvidence::getMsRunPtr()
{
  return _msrunid_sp;
}


void
PeptideEvidence::setGrpPeptideSp(const pappso::GrpPeptideSp &sp_grp_peptide)
{
  _sp_grp_peptide = sp_grp_peptide;
}

const pappso::GrpPeptideSp &
PeptideEvidence::getGrpPeptideSp() const
{
  return _sp_grp_peptide;
}
