
/*******************************************************************************
 * 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 <QColor>
#include <vector>
#include <set>
#include <pappsomspp/core/types.h>
#include "proteinxtp.h"
#include "peptidematch.h"
#include "automaticfilterparameters.h"
#include "../grouping/groupingexperiment.h"
#include "../utils/groupstore.h"
#include "../grouping/groupinggroup.h"

#pragma once

class IdentificationGroup;

class ProteinMatch
{
  friend IdentificationGroup;

  public:
  ProteinMatch();
  virtual ~ProteinMatch();

  const ProteinXtpSp &getProteinXtpSp() const;

  /** @brief compute protein log10(Evalue) within samples
   * */
  pappso::pappso_double getLogEvalue(const MsRun *sp_msrun_id = nullptr) const;


  /** @brief get the maximum SVM probability among validated PSM list of this
   * protein
   *
   * if MSrun is provided, restrict the PSM list this MSrun
   *
   * @param p_msrun_id pointer on the msrun
   * */
  pappso::pappso_double
  getMaxPsmSvmProb(const MsRun *p_msrun_id = nullptr) const;

  /** @brief compute protein Evalue within samples
   * */
  pappso::pappso_double getEvalue(const MsRun *sp_msrun_id = nullptr) const;


  /** @brief protein coverage overall samples
   * */
  pappso::pappso_double getCoverage() const;

  /** @brief get coverage sequence (html representation)
   * @param peptide_match_to_locate pointer to optional peptide match to locate
   *on protein sequence
   **/
  const QString
  getHtmlSequence(PeptideEvidence *peptide_evidence_to_locate = nullptr) const;

  /** @brief compute proto NSAF within msrun : spectral abundance factor (SAF)
   * Warning: this is not NSAF, just a part
   * @param p_msrun_id pointer on the msrun to get NSAF.
   * */
  pappso::pappso_double getProtoNsaf(const MsRun *p_msrun_id,
                                     const Label *p_label = nullptr) const;

  /** @brief compute NSAF within msrun : normalized spectral abundance factor
   * (NSAF) Florens L., Carozza M. J. C., Swanson S. K., et al. Analyzing
   * chromatin remodeling complexes using shotgun proteomics and normalized
   * spectral abundance factors. Methods. 2006;40(4):303–311.
   * doi: 10.1016/j.ymeth.2006.07.028.
   * https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1815300/
   * @param proto_nsaf_sum the sum of SAF of all proteins within the msrun
   * @param p_msrun_id pointer on the msrun to get NSAF
   * */
  pappso::pappso_double getNsaf(pappso::pappso_double proto_nsaf_sum,
                                const MsRun *p_msrun_id,
                                const Label *p_label = nullptr) const;

  /** @brief compute Protein Abundance Index (PAI) within sample
   * PAI computation (Rappsilber et al. 2002)
   * */
  pappso::pappso_double getPAI(const MsRun *sp_msrun_id = nullptr,
                               const Label *p_label     = nullptr) const;

  /** @brief compute emPAI within sample
   * Ishihama 2005
   * */
  pappso::pappso_double getEmPAI(const MsRun *sp_msrun_id = nullptr,
                                 const Label *p_label     = nullptr) const;

  void setProteinXtpSp(ProteinXtpSp protein_sp);
  void addPeptideMatch(const PeptideMatch &peptide_match);
  std::vector<PeptideMatch> &getPeptideMatchList();
  const std::vector<PeptideMatch> &getPeptideMatchList() const;

  /** @brief get peptide match sublist with required validation state
   * @param state the validation state to select
   * @param sp_msrun_id the msrun to look for, if nullptr, then get peptide
   * match overall MSruns
   * */
  std::vector<PeptideMatch>
  getPeptideMatchList(ValidationState state,
                      const MsRun *sp_msrun_id = nullptr) const;

  void setChecked(bool arg1);

  bool isChecked() const;
  bool isValid() const;
  bool isValidAndChecked() const;
  bool isGrouped() const;

  ValidationState getValidationState() const;

  /** @brief count peptide match (psm) listed in this protein match
   */
  std::size_t countPeptideMatch(ValidationState state) const;

  /** @brief count distinct sample + scans implied in this protein
   * identification
   */
  std::size_t countSampleScan(ValidationState state,
                              const MsRun *p_msrun_id = nullptr,
                              const Label *p_label    = nullptr) const;

  /** @brief count peptide (peptide+mass)
   */
  void countPeptideMass(std::vector<pappso::GrpPeptide *> &count_peptide_mass,
                        ValidationState state) const;

  /** @brief count peptide (peptide+mass+sample)
   */
  void countPeptideMassSample(std::vector<size_t> &count_peptide_mass_sample,
                              ValidationState state) const;

  const pappso::GrpProteinSp &getGrpProteinSp() const;
  const GroupingGroupSp &getGroupingGroupSp() const;

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


  /** @brief collect distinct peptide evidences
   */
  void collectPeptideEvidences(
    std::vector<const PeptideEvidence *> &peptide_evidence_set,
    ValidationState state) const;
  void
  collectPeptideEvidences(std::vector<PeptideEvidence *> &peptide_evidence_set,
                          ValidationState state);

  /** @brief count distinct sequence taking into account equivalence between
   * Leucine and Isoleucine
   * @param state validation state of peptides to count
   * @param p_msrun_id count within the specified sample
   */
  size_t countSequenceLi(ValidationState state,
                         const MsRun *p_msrun_id = nullptr,
                         const Label *p_label    = nullptr) const;

  /** @brief count distinct peptide+mass+charge
   * peptide is the peptide sequence LI (Leucine => Isoleucine)
   * mass is the peptide mass, not considering labelled residues (if any)
   * @param state validation state of peptides to count
   * @param p_msrun_id count within the specified sample
   */
  std::size_t countPeptideMassCharge(ValidationState state,
                                     const MsRun *sp_msrun_id = nullptr,
                                     const Label *p_label     = nullptr) const;

  /** @brief count distinct MS samples in which the protein is observed
   * @param state validation state of peptides to count
   */
  std::size_t countDistinctMsSamples(ValidationState state) const;

  /** @brief get the flanking protein sequence at the Nter side of the peptide
   * @param peptide_match the peptide from which we want flanking region
   * @param length size of the protein flanking region
   */
  QString getFlankingNterRegion(const PeptideMatch &peptide_match,
                                int length) const;

  /** @brief get the flanking protein sequence at the Cter side of the peptide
   * @param peptide_match the peptide from which we want flanking region
   * @param length size of the protein flanking region
   */
  QString getFlankingCterRegion(const PeptideMatch &peptide_match,
                                int length) const;

  /** @brief tells if the protein match contains this peptide evidence
   *
   * @param p_pe the targeted peptide evidence
   */
  bool contains(const PeptideEvidence *p_pe) const;


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

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

  protected:
  void setGroupingExperiment(GroupingExperiment *p_grp_experiment);

  void setGroupInstance(GroupStore &group_store);


  private:
  static QColor _color_peptide_background;
  static QColor _color_highlighted_peptide_background;


  pappso::GrpProteinSp _sp_grp_protein = nullptr;
  GroupingGroupSp _sp_group;

  std::vector<PeptideMatch> _peptide_match_list;
  ProteinXtpSp _protein_sp = nullptr;


  std::map<ProteinParam, QVariant> m_params;

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

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