
/*******************************************************************************
 * Copyright (c) 2019 Olivier Langella <Olivier.Langella@u-psud.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/>.
 *
 ******************************************************************************/

#pragma once

#include "../msrunid.h"
#include "../msrunreader.h"
#include <vector>
#include "pappsomspp/core/processing/filters/filtermorpho.h"

namespace pappso
{

template <class T>
struct MsRunRetentionTimeSeamarkPoint
{
  T entityHash;
  double retentionTime;
  double intensity;
};


template <class T>
class PMSPP_LIB_DECL MsRunRetentionTime
{
  private:
  struct PeptideMs2Point
  {
    double retentionTime;
    double precursorIntensity;
    T entityHash;
  };

  enum class ComputeRetentionTimeReference
  {
    maximum_intensity,
    weighted_intensity,
    last
  };

  public:
  MsRunRetentionTime(const std::vector<double> &msrun_retention_time_line);
  MsRunRetentionTime(const MsRunRetentionTime<T> &other);
  ~MsRunRetentionTime();

  void setMs2MedianFilter(const FilterMorphoMedian &ms2MedianFilter);
  void setMs2MeanFilter(const FilterMorphoMean &ms2MeanFilter);
  void setMs1MeanFilter(const FilterMorphoMean &ms1MeanFilter);

  const FilterMorphoMedian &getMs2MedianFilter() const;
  const FilterMorphoMean &getMs2MeanFilter() const;
  const FilterMorphoMean &getMs1MeanFilter() const;

  Trace
  getCommonDeltaRt(const std::vector<MsRunRetentionTimeSeamarkPoint<T>> &other_seamarks) const;

  /** @brief collects all peptide evidences of a given MSrun
   * seamarks has to be converted to peptide retention time using
   * computePeptideRetentionTimes
   *
   * @param peptide_id unique identifier (whichever type) of a peptide
   * @param retentionTime retention time of this peptide observation
   * @param precursorIntensity MS2 precursorIntensity of this peptide
   */
  void addPeptideAsSeamark(const T &peptide_id, double retentionTime, double precursorIntensity);


  std::size_t getNumberOfCorrectedValues() const;

  /** @brief align the current msrunretentiontime object using the given
   * reference
   * @param msrun_retention_time_reference the reference
   * @return a trace containing aligned MS1 retention times
   */
  Trace align(const MsRunRetentionTime<T> &msrun_retention_time_reference);

  /** @brief get common seamarks between msrunretentiontime objects and their
   * deltart
   * @param msrun_retention_time_reference the reference
   * @return a trace containing MS2 common points and their deltart
   */
  Trace getCommonSeamarksDeltaRt(const MsRunRetentionTime<T> &msrun_retention_time_reference) const;

  const std::vector<MsRunRetentionTimeSeamarkPoint<T>> &getSeamarks() const;

  /** @brief get aligned retention time vector
   * @return vector of seconds (as double)
   */
  const std::vector<double> &getAlignedRetentionTimeVector() const;

  void setAlignedRetentionTimeVector(const std::vector<double> &aligned_times);

  /** @brief get orginal retention time vector (not aligned)
   * @return vector of seconds (as double)
   */
  const std::vector<double> &getMs1RetentionTimeVector() const;

  bool isAligned() const;

  double translateOriginal2AlignedRetentionTime(double original_retention_time) const;


  double translateAligned2OriginalRetentionTime(double aligned_retention_time) const;

  /** @brief convert PeptideMs2Point into Peptide seamarks
   * this is required before computing alignment
   */
  void computeSeamarks();

  protected:
  double getFrontRetentionTimeReference() const;
  double getBackRetentionTimeReference() const;
  const std::vector<MsRunRetentionTimeSeamarkPoint<T>> getSeamarksReferences() const;

  private:
  /** @brief get a trace of common MS2 retention times (x values) by their
   * deltart (y values)
   * @param delta_rt the trace result (common MS2 retention times vs counter
   * part deltart)
   * @param other_seamarks seamarks of the counter part (reference)
   */
  void getCommonDeltaRt(Trace &delta_rt,
                        const std::vector<MsRunRetentionTimeSeamarkPoint<T>> &other_seamarks) const;
  void correctNewTimeValues(Trace &ms1_aligned_points, double correction_parameter);

  void linearRegressionMs2toMs1(Trace &ms1_aligned_points, const Trace &common_points);

  private:
  FilterMorphoMedian m_ms2MedianFilter;
  FilterMorphoMean m_ms2MeanFilter;
  FilterMorphoMean m_ms1MeanFilter;
  std::vector<double> m_ms1RetentionTimeVector;
  std::vector<double> m_alignedRetentionTimeVector;

  std::vector<MsRunRetentionTimeSeamarkPoint<T>> m_seamarks;
  std::size_t m_valuesCorrected = 0;

  std::vector<PeptideMs2Point> m_allMs2Points;

  ComputeRetentionTimeReference m_retentionTimeReferenceMethod =
    ComputeRetentionTimeReference::maximum_intensity;
};

} // namespace pappso
