/**
 * \file pappsomspp/filers/filterpass.h
 * \date 26/04/2019
 * \author Olivier Langella
 * \brief collection of filters concerned by Y selection
 */

/*******************************************************************************
 * 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 "filternameinterface.h"
#include <cstddef>
#include "pappsomspp/export-import-config.h"


namespace pappso
{

/** @brief remove datapoints higher or equal to a given Y value (intensity)
 */
class PMSPP_LIB_DECL FilterLowPass : public FilterInterface
{
  private:
  double m_passY = 0;

  public:
  FilterLowPass(double pass_y);
  FilterLowPass(const FilterLowPass &other);
  virtual ~FilterLowPass(){};

  FilterLowPass &operator=(const FilterLowPass &other);

  Trace &filter(Trace &data_points) const override;
};

/** @brief remove datapoints below or equal to the given Y value (intensity)
 */
class PMSPP_LIB_DECL FilterHighPass : public FilterInterface
{
  private:
  double m_passY = 0;

  public:
  FilterHighPass(double pass_y);
  FilterHighPass(const FilterHighPass &other);
  virtual ~FilterHighPass(){};

  FilterHighPass &operator=(const FilterHighPass &other);

  Trace &filter(Trace &data_points) const override;
};

/** @brief remove datapoints below a given intensity percentage (ratio) of the
 * maximum intensity
 */
class PMSPP_LIB_DECL FilterHighPassPercentage : public FilterInterface
{

  public:
  FilterHighPassPercentage(double y_ratio);
  FilterHighPassPercentage(const FilterHighPassPercentage &other);
  virtual ~FilterHighPassPercentage(){};

  FilterHighPassPercentage &operator=(const FilterHighPassPercentage &other);

  Trace &filter(Trace &data_points) const override;


  private:
  double m_ratioPassY = 0;
};


/** @brief keep N datapoints form the greatest intensities to the lowest
 */
class PMSPP_LIB_DECL FilterGreatestY : public FilterInterface
{
  public:
  /** @brief constructor with the number of datapoints to keep
   *
   * @param number_of_points maximum number of points accepted in resulting
   * spectrum
   */
  FilterGreatestY(std::size_t number_of_points = 0);
  FilterGreatestY(const FilterGreatestY &other);
  virtual ~FilterGreatestY(){};

  FilterGreatestY &operator=(const FilterGreatestY &other);
  Trace &filter(Trace &data_points) const override;

  std::size_t getNumberOfPoints() const;


  private:
  std::size_t m_numberOfPoints = 0;
};


/** @brief keep N datapoints form the greatest intensities to the lowest within
 * a mass range in dalton
 */
class PMSPP_LIB_DECL FilterGreatestYperWindow : public FilterInterface
{
  public:
  /** @brief constructor with the number of datapoints to keep
   *
   * @param window_range mass range to consider (must be greater than 0.5)
   * @param number_of_points_per_window maximum number of points accepted per
   * mass window in resulting spectrum
   */
  FilterGreatestYperWindow(double window_range, std::size_t number_of_points_per_window);
  FilterGreatestYperWindow(const FilterGreatestYperWindow &other);
  virtual ~FilterGreatestYperWindow(){};

  FilterGreatestYperWindow &operator=(const FilterGreatestYperWindow &other);
  Trace &filter(Trace &data_points) const override;

  std::size_t getNumberOfPoints() const;


  private:
  double m_xWindowRange        = 1;
  std::size_t m_numberOfPoints = 0;
};

class PMSPP_LIB_DECL MassSpectrumFilterGreatestItensities : public MassSpectrumFilterInterface
{
  private:
  FilterGreatestY m_filterGreatestY;

  public:
  MassSpectrumFilterGreatestItensities(std::size_t number_of_points = 0);
  MassSpectrumFilterGreatestItensities(const MassSpectrumFilterGreatestItensities &other);
  virtual ~MassSpectrumFilterGreatestItensities(){};

  MassSpectrumFilterGreatestItensities &
  operator=(const MassSpectrumFilterGreatestItensities &other);
  MassSpectrum &filter(MassSpectrum &spectrum) const override;
};

/** @brief apply std::floor (round to lowest integer) to all Y values
 */
class PMSPP_LIB_DECL FilterFloorY : public FilterInterface
{

  public:
  FilterFloorY();
  FilterFloorY(const FilterFloorY &other);
  virtual ~FilterFloorY(){};

  FilterFloorY &operator=(const FilterFloorY &other);
  Trace &filter(Trace &data_points) const override;
};


/** @brief apply std::round (round to nearest integer) to all Y values
 */
class PMSPP_LIB_DECL FilterRoundY : public FilterInterface
{

  public:
  FilterRoundY();
  FilterRoundY(const FilterRoundY &other);
  virtual ~FilterRoundY(){};

  FilterRoundY &operator=(const FilterRoundY &other);
  Trace &filter(Trace &data_points) const override;
};

/** @brief rescales Y values into a dynamic range
 * if the dynamic range is set to 0, this filter is ignored
 */
class PMSPP_LIB_DECL FilterRescaleY : public FilterInterface
{
  private:
  double m_dynamic = 0;

  public:
  FilterRescaleY(double dynamic);
  FilterRescaleY(const FilterRescaleY &other);
  virtual ~FilterRescaleY(){};

  FilterRescaleY &operator=(const FilterRescaleY &other);
  double getDynamicRange() const;

  Trace &filter(Trace &data_points) const override;
};


/** @brief rescales Y values given a tranformation factor
 */
class PMSPP_LIB_DECL FilterScaleFactorY : public FilterInterface
{
  private:
  double m_factor = 0;

  public:
  FilterScaleFactorY(double m_factor);
  FilterScaleFactorY(const FilterScaleFactorY &other);
  virtual ~FilterScaleFactorY(){};

  FilterScaleFactorY &operator=(const FilterScaleFactorY &other);

  Trace &filter(Trace &data_points) const override;

  double getScaleFactorY() const;
};


/** @brief removes a value to all Y values
 */
class PMSPP_LIB_DECL FilterRemoveY : public FilterNameInterface
{
  public:
  FilterRemoveY(const QString &strBuildParams);
  FilterRemoveY(double valueToRemove);
  FilterRemoveY(const FilterRemoveY &other);
  virtual ~FilterRemoveY(){};

  FilterRemoveY &operator=(const FilterRemoveY &other);

  Trace &filter(Trace &data_points) const override;

  double getValue() const;


  void buildFilterFromString(const QString &strBuildParams) override;

  QString toString() const override;

  QString name() const override;

  private:
  double m_valueToRemove = 0;
};


/** @brief removes a value found by quantile to all Y values
 *
 * sort all values by Y intensity and take the iest value located at the defined
 * quantile the use it to remove this value to all Y intensities
 */
class PMSPP_LIB_DECL FilterQuantileBasedRemoveY : public FilterNameInterface
{
  public:
  FilterQuantileBasedRemoveY(double quantile_threshold);

  /**
   * @param strBuildParams string to build the filter
   * "passQuantileBasedRemoveY|0.6"
   */
  FilterQuantileBasedRemoveY(const QString &strBuildParams);

  FilterQuantileBasedRemoveY(const FilterQuantileBasedRemoveY &other);
  virtual ~FilterQuantileBasedRemoveY(){};

  FilterQuantileBasedRemoveY &operator=(const FilterQuantileBasedRemoveY &other);

  Trace &filter(Trace &data_points) const override;

  double getQuantileThreshold() const;

  virtual QString name() const override;
  QString toString() const override;

  protected:
  void buildFilterFromString(const QString &strBuildParams) override;

  private:
  double m_quantile = 0;
};

} // namespace pappso
