/**
 * \file pappsomspp/filers/filtermorpho.h
 * \date 02/05/2019
 * \author Olivier Langella
 * \brief collection of morphological filters
 */

/*******************************************************************************
 * 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 "filtersuite.h"
#include <cstddef>

namespace pappso
{

struct DataPoint;

/** @brief base class that apply a signal treatment based on a window
 */
class FilterMorphoWindowBase : public FilterInterface
{
  protected:
  std::size_t m_halfWindowSize = 0;

  virtual double
  getWindowValue(std::vector<DataPoint>::const_iterator begin,
                 std::vector<DataPoint>::const_iterator end) const = 0;

  public:
  FilterMorphoWindowBase(std::size_t half_window_size);
  FilterMorphoWindowBase(const FilterMorphoWindowBase &other);
  virtual ~FilterMorphoWindowBase(){};

  FilterMorphoWindowBase &operator=(const FilterMorphoWindowBase &other);

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

  virtual std::size_t getHalfWindowSize() const;
};

/** @brief test purpose
 */
class PMSPP_LIB_DECL FilterMorphoSum : public FilterMorphoWindowBase
{

  public:
  FilterMorphoSum(std::size_t half_window_size);
  FilterMorphoSum(const FilterMorphoSum &other);
  virtual ~FilterMorphoSum(){};

  FilterMorphoSum &operator=(const FilterMorphoSum &other);

  double
  getWindowValue(std::vector<DataPoint>::const_iterator begin,
                 std::vector<DataPoint>::const_iterator end) const override;
};

/** @brief transform the trace into its maximum over a window
 */
class PMSPP_LIB_DECL FilterMorphoMax : public FilterMorphoWindowBase
{

  public:
  FilterMorphoMax(std::size_t half_window_size);
  FilterMorphoMax(const FilterMorphoMax &other);
  virtual ~FilterMorphoMax(){};

  FilterMorphoMax &operator=(const FilterMorphoMax &other);
  double
  getWindowValue(std::vector<DataPoint>::const_iterator begin,
                 std::vector<DataPoint>::const_iterator end) const override;

  std::size_t getMaxHalfEdgeWindows() const;
};

/** @brief transform the trace into its minimum over a window
 */
class PMSPP_LIB_DECL FilterMorphoMin : public FilterMorphoWindowBase
{

  public:
  FilterMorphoMin(std::size_t half_window_size);
  FilterMorphoMin(const FilterMorphoMin &other);
  virtual ~FilterMorphoMin(){};

  FilterMorphoMin &operator=(const FilterMorphoMin &other);
  double
  getWindowValue(std::vector<DataPoint>::const_iterator begin,
                 std::vector<DataPoint>::const_iterator end) const override;

  std::size_t getMinHalfEdgeWindows() const;
};

/** @brief transform the trace with the minimum of the maximum
 * equivalent of the dilate filter for pictures
 */
class PMSPP_LIB_DECL FilterMorphoMinMax : public FilterInterface
{
  private:
  FilterMorphoMax m_filterMax;
  FilterMorphoMin m_filterMin;

  public:
  FilterMorphoMinMax(std::size_t half_window_size);
  FilterMorphoMinMax(const FilterMorphoMinMax &other);
  virtual ~FilterMorphoMinMax(){};

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

  std::size_t getMinMaxHalfEdgeWindows() const;
};

/** @brief transform the trace with the maximum of the minimum
 * equivalent of the erode filter for pictures
 */
class PMSPP_LIB_DECL FilterMorphoMaxMin : public FilterInterface
{
  private:
  FilterMorphoMin m_filterMin;
  FilterMorphoMax m_filterMax;

  public:
  FilterMorphoMaxMin(std::size_t half_window_size);
  FilterMorphoMaxMin(const FilterMorphoMaxMin &other);
  virtual ~FilterMorphoMaxMin(){};

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

  std::size_t getMaxMinHalfEdgeWindows() const;
};

/** @brief anti spike filter
 * set to zero alone values inside the window
 */
class PMSPP_LIB_DECL FilterMorphoAntiSpike : public FilterNameInterface
{
  private:
  std::size_t m_halfWindowSize = 0;

  public:
  FilterMorphoAntiSpike(std::size_t half_window_size);
  /**
   * @param strBuildParams string to build the filter
   * "antiSpike|2"
   */
  FilterMorphoAntiSpike(const QString &strBuildParams);

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

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

  std::size_t getHalfWindowSize() const;


  void buildFilterFromString(const QString &strBuildParams) override;

  QString toString() const override;

  QString name() const override;
};


/** @brief median filter
 * apply median of y values inside the window
 */
class PMSPP_LIB_DECL FilterMorphoMedian : public FilterMorphoWindowBase
{

  public:
  FilterMorphoMedian(std::size_t half_window_size);
  FilterMorphoMedian(const FilterMorphoMedian &other);
  virtual ~FilterMorphoMedian(){};

  FilterMorphoMedian &operator=(const FilterMorphoMedian &other);
  double
  getWindowValue(std::vector<DataPoint>::const_iterator begin,
                 std::vector<DataPoint>::const_iterator end) const override;
};


/** @brief mean filter
 * apply mean of y values inside the window : this results in a kind of
 * smoothing
 */
class PMSPP_LIB_DECL FilterMorphoMean : public FilterMorphoWindowBase
{

  public:
  FilterMorphoMean(std::size_t half_window_size);
  FilterMorphoMean(const FilterMorphoMean &other);
  virtual ~FilterMorphoMean(){};

  FilterMorphoMean &operator=(const FilterMorphoMean &other);
  double
  getWindowValue(std::vector<DataPoint>::const_iterator begin,
                 std::vector<DataPoint>::const_iterator end) const override;

  std::size_t getMeanHalfEdgeWindows() const;
};

/** @brief compute background of a trace
 * compute background noise on a trace
 */
class PMSPP_LIB_DECL FilterMorphoBackground : public FilterInterface
{
  private:
  FilterMorphoMedian m_filterMorphoMedian;
  FilterMorphoMinMax m_filterMorphoMinMax;

  public:
  FilterMorphoBackground(std::size_t median_half_window_size,
                         std::size_t minmax_half_window_size);
  FilterMorphoBackground(const FilterMorphoBackground &other);
  virtual ~FilterMorphoBackground(){};

  FilterMorphoBackground &operator=(const FilterMorphoBackground &other);
  const FilterMorphoMedian &getFilterMorphoMedian() const;
  const FilterMorphoMinMax &getFilterMorphoMinMax() const;

  Trace &filter(Trace &data_points) const override;
};
} // namespace pappso
