/**
 * \file utils/peptideevidence.h
 * \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 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
 ******************************************************************************/
#pragma once

#include <pappsomspp/core/types.h>
#include "peptidextp.h"
#include "identification_sources/identificationdatasource.h"
#include "automaticfilterparameters.h"
#include "msrun.h"

#include "../grouping/groupingexperiment.h"

class PeptideEvidence;

/** \brief shared pointer on a Peptide object
 */
typedef std::shared_ptr<PeptideEvidence> PeptideEvidenceSp;

class PeptideEvidence
{
  public:
  /** @brief build a peptide evidence either with a scan number (deprecated)
   * @param msrunid_sp the MSrun on which the peptide evidence was made
   * @param scan_index integer to store the scan number
   */
  [[deprecated]] PeptideEvidence(MsRun *msrunid_sp, std::size_t scan_index);

  /** @brief build a peptide evidence either with a scan number or a spectrum
   * index
   * @param msrunid_sp the MSrun on which the peptide evidence was made
   * @param scan_index integer to store either a scan number (deprecated) or a
   * spectrum index
   * @param isSpectrumIndex to tell if scan index is a spectrum index
   */
  PeptideEvidence(MsRun *msrunid_sp,
                  std::size_t scan_index,
                  bool isSpectrumIndex);
  PeptideEvidence(const PeptideEvidence &other);
  virtual ~PeptideEvidence();
  std::size_t getHashSampleScan() const;
  std::size_t getHashPeptideMassSample() const;

  PeptideEvidenceSp makePeptideEvidenceSp() const;

  void setRetentionTime(pappso::pappso_double rt);
  void setEvalue(pappso::pappso_double evalue);

  /** @brief get experimental mass of this peptide
   * @return the computed mass given the precursor measured mass and the deduced
   * peptide charge
   */
  pappso::pappso_double getExperimentalMass() const;

  /** @brief get experimental MH+ of this peptide
   * @return getExperimentalMass + MHPLUS
   */
  pappso::pappso_double getExperimentalMhplus() const;

  /** @brief get experimental mz of this peptide
   * @return the real mass measured (precuror mass) by the spectrometer
   */
  pappso::pappso_double getExperimentalMz() const;


  /** @brief set experimental mass of this peptide
   * @arg exp_mass the computed mass given the precursor measured mass and the
   * deduced peptide charge without MH+
   */
  void setExperimentalMass(pappso::pappso_double exp_mass);

  /** @brief set experimental m/z as observed by the mass spectrometer
   * @arg experimental m/z
   *
   * The charge has to be previously set
   */
  void setExperimentalMassToCharge(pappso::pappso_double exp_mz);

  /** \brief set specific parameter value
   */
  virtual void setParam(PeptideEvidenceParam param, const QVariant &value);
  /** \brief get specific parameter value
   */
  virtual const QVariant getParam(PeptideEvidenceParam param) const;

  const std::map<PeptideEvidenceParam, QVariant> &getParamList() const;


  void setCharge(unsigned int charge);
  void setPeptideXtpSp(PeptideXtpSp peptide);
  void
  setIdentificationDataSource(IdentificationDataSource *identification_source);


  /** @brief sets the identification engine
   * by default, this is the identification engine of the datasource
   */
  void setIdentificationEngine(IdentificationEngine identification_engine);

  /** @brief get the identification engine
   * by default, this is the identification engine of the datasource
   */
  IdentificationEngine getIdentificationEngine() const;

  void setValid(bool is_valid);
  void setChecked(bool arg1);
  bool isChecked() const;
  bool isValid() const;
  bool isValidAndChecked() const;
  bool isGrouped() const;

  const MsRun *getMsRunP() const;
  MsRun *getMsRunPtr();
  IdentificationDataSource *getIdentificationDataSource() const;
  unsigned int getScanNumber() const;

  /** @brief get retention time of this PSM in seconds
   * the retention time must have been present when reading MS identification
   * results. If no retention time was set, this returns O
   * @return retention time in seconds or zero if data is missing
   */
  pappso::pappso_double getRetentionTime() const;

  /** @brief get retention time of this PSM in seconds by all means
   *
   * if retention time is missing, this tries to guess it by all means. It will
   * try to look at mz data file.
   * This could be time consuming.
   * @return retention time in seconds or zero if data is missing
   */
  pappso::pappso_double getHardenedRetentionTime() const;
  unsigned int getCharge() const;
  const PeptideXtpSp &getPeptideXtpSp() const;
  pappso::pappso_double getEvalue() const;

  void setGrpPeptideSp(const pappso::GrpPeptideSp &sp_grp_peptide);
  const pappso::GrpPeptideSp &getGrpPeptideSp() const;

  /** @brief validate or invalidate peptides and proteins based automatic
   * filters and manual checks
   * */
  void updateAutomaticFilters(
    const AutomaticFilterParameters &automatic_filter_parameters);

  /** @brief get delta between theoretical mhplus mass and mhplus experimental
   * mass mhplus experimental mass - theoretical mhplus mass
   */
  pappso::pappso_double getDeltaMass() const;

  /** @brief get delta in ppm between theoretical mhplus mass and mhplus
   * experimental mass
   * @return mhplus experimental mass - theoretical mhplus mass
   */
  pappso::pappso_double getPpmDeltaMass() const;

  /** @brief get theoretical (not observed) m/z based on peptide composition and
   * charge
   * @return theoretical mz mass
   */
  pappso::pappso_double getTheoreticalMz() const;

  ValidationState getValidationState() const;

  /** @brief get the mass spectrum associated to this peptide evidence
   * @return pappso::MassSpectrumCstSPtr or an exception
   */
  pappso::MassSpectrumCstSPtr getMassSpectrumCstSPtr() const;


  /** @brief get the qualified mass spectrum associated to this peptide evidence
   * @param data boolean if true, retrieves the peak list, if false, only give
   * mass spectrum informations
   * @return QualifiedMassSpectrum or an exception
   */
  pappso::QualifiedMassSpectrum getQualifiedMassSpectrum(bool data) const;

  /** @brief get the spectrum index of the mass spectrum associated to this
   * peptide evidence
   * @return spectrum index or not found exception
   */
  std::size_t getSpectrumIndex() const;


  /** @brief get the spectrum index from the scan number
   *
   * finds a spectrum index using a scan number if necessary
   *
   * @return spectrum_index or not found exception
   *
   */
  std::size_t getSpectrumIndexByScanNumber() const;


  /** @brief get a unique index, but we don't know if it is a scan or index
   *
   * use with caution
   *
   */
  std::size_t getUniqueIndex() const;

  /** @brief get HTML sequence of the peptide
   * HTML sequence can be colorized depending on modifications
   */
  QString getHtmlSequence() const;

  /** @brief tells to peptide evidence that the scan index is a spectrum index
   *
   * @param is_a_spectrum_index boolean true if the scan index is a spectrum
   * index
   */
  void setIsSpectrumIndex(bool is_a_spectrum_index);


  /** @brief get the peptide model in ProForma notation
   * https://github.com/HUPO-PSI/ProForma/blob/master/README.md
   * @return QString as described in ProForma
   */
  QString toProForma() const;

  bool isSpectrumIndex() const;

  private:
  static std::hash<std::string> _hash_fn;
  MsRun *_msrunid_sp;
  std::size_t m_scan_number = 0;
  bool m_isSpectrumIndex    = false;
  size_t _hash_sample_scan;
  pappso::GrpPeptideSp _sp_grp_peptide;
  PeptideXtpSp _peptide_sp;
  pappso::pappso_double _rt;
  pappso::pappso_double _evalue = 0;
  pappso::pappso_double _exp_mass;
  unsigned int _charge;
  IdentificationDataSource *_p_identification_source = nullptr;
  std::map<PeptideEvidenceParam, QVariant> _params;

  /** @brief manually checked by user (true by default)
   */
  bool _checked = true;

  /** @brief automatic filter result (false by default)
   */
  bool _proxy_valid = false;

  /** @brief the search/identification engine that found this evidence
   */
  IdentificationEngine _identification_engine;
};
