/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#ifndef mitkGIFGreyLevelDistanceZone_h
#define mitkGIFGreyLevelDistanceZone_h

#include <mitkAbstractGlobalImageFeature.h>
#include <mitkBaseData.h>
#include <MitkCLUtilitiesExports.h>

#include <itkeigen/Eigen/src/Core/Array.h>

namespace mitk
{
  /**
   * \brief Data structure holding all Grey Level Distance Zone feature values.
   *
   * \sa GIFGreyLevelDistanceZone
   */
  struct GreyLevelDistanceZoneFeatures
  {
    GreyLevelDistanceZoneFeatures() :
      SmallDistanceEmphasis(0),
      LargeDistanceEmphasis(0),
      LowGreyLevelEmphasis(0),
      HighGreyLevelEmphasis(0),
      SmallDistanceLowGreyLevelEmphasis(0),
      SmallDistanceHighGreyLevelEmphasis(0),
      LargeDistanceLowGreyLevelEmphasis(0),
      LargeDistanceHighGreyLevelEmphasis(0),
      GreyLevelNonUniformity(0),
      GreyLevelNonUniformityNormalized(0),
      ZoneDistanceNonUniformity(0),
      ZoneDistanceNoneUniformityNormalized(0),
      ZonePercentage(0),
      GreyLevelMean(0),
      GreyLevelVariance(0),
      ZoneDistanceMean(0),
      ZoneDistanceVariance(0),
      ZoneDistanceEntropy(0)
    {
    }

  public:
    double SmallDistanceEmphasis;                   ///< Emphasis on zones with small distance to the border.
    double LargeDistanceEmphasis;                   ///< Emphasis on zones with large distance to the border.
    double LowGreyLevelEmphasis;                    ///< Emphasis on zones with low grey level values.
    double HighGreyLevelEmphasis;                   ///< Emphasis on zones with high grey level values.
    double SmallDistanceLowGreyLevelEmphasis;       ///< Combined emphasis on small distance and low grey level.
    double SmallDistanceHighGreyLevelEmphasis;      ///< Combined emphasis on small distance and high grey level.
    double LargeDistanceLowGreyLevelEmphasis;       ///< Combined emphasis on large distance and low grey level.
    double LargeDistanceHighGreyLevelEmphasis;      ///< Combined emphasis on large distance and high grey level.
    double GreyLevelNonUniformity;                  ///< Measures variability in grey level distribution.
    double GreyLevelNonUniformityNormalized;        ///< Normalized grey level non-uniformity.
    double ZoneDistanceNonUniformity;               ///< Measures variability in zone distance distribution.
    double ZoneDistanceNoneUniformityNormalized;     ///< Normalized zone distance non-uniformity.
    double ZonePercentage;                          ///< Ratio of realized zones to total voxels.
    double GreyLevelMean;                           ///< Mean grey level of all zones.
    double GreyLevelVariance;                       ///< Variance of grey levels across zones.
    double ZoneDistanceMean;                        ///< Mean distance of all zones.
    double ZoneDistanceVariance;                    ///< Variance of zone distances.
    double ZoneDistanceEntropy;                     ///< Entropy of the zone distance distribution.
  };


  class MITKCLUTILITIES_EXPORT GIFGreyLevelDistanceZone : public AbstractGlobalImageFeature
  {
    /**
     * \brief Calculates the Grey Level Distance Zone
     *
     * This class can be used to calculate Grey Level Distance Zone as presented in Thibault et al. 2014.
     *
     * The basic idea behind the Grey Level Distance Zone based features is to count the connected areas
     * with a given intensity value \f$x_i\f$ and a given distance to the border of each segmentation \f$d_i\f$.
     * Several features are then calculated based on a matrix, that gives the number of occurrence for each
     * combination of \f$x_i\f$ and \f$ d_i \f$ as \f$m_{x,d}\f$.
     *
     * This feature calculator is activated by the option <b>-grey-level-distance-zone</b> or <b>-gldz</b>.
     *
     * The connected areas are based on the binned image, the binning parameters can be set via the default
     * parameters as described in AbstractGlobalImageFeature. It is also possible to determine the
     * dimensionality of the neighbourhood using direction-related commands as described in AbstractGlobalImageFeature.
     * No other options are possible beside these two options.
     *
     * The features are calculated based on a mask. It is assumed that the mask is
     * of the type of an unsigned short image. It is expected that the image contains only voxels with value 0 and 1,
     * of which all voxels with an value equal to one are treated as masked.
     *
     * The features depend on the distance to the border of the segmentation ROI. In some cases, the border
     * definition might be different from the definition of the masked area, for example, if small openings
     * in the mask should not influence the distance. Due to that, it is possible to submit a second mask,
     * named Morphological Mask to the features that is then used to calculate the distance of each voxel to
     * border of the segmented area. The morpological mask can be either set by the function call SetMorphMask()
     * or by the corresponding global option. (Not parsed by the filter itself, but by the command line tool).
     *
     * Beside the complete matrix, which is represented by its individual elements \f$m_{x,d}\f$, som eadditional
     * values are used for the definition. \f$N_g\f$ is the number of discrete grey levels, \f$ N_d\f$ the number
     * (or maximum value) of possible distances, and  \f$N_s\f$ the total number of zones.
     * \f$m_{x,d}\f$ gives the number of connected areas with the discrete
     * grey level x and distance to the boarder of d. Corresponding, \f$p_{x,d} = \frac{m_{x,d}}{N_s} gives the relativ
     * probability of this matrix cell. \f$ \f$N_v\f$ is the number of voxels. In addition, the marginal
     * sums \f$m_{x,\cdot} = m_x = \sum_d m_{x,d} \f$ , representing the sum of all zones with a given intensity, and
     * sums \f$m_{\cdot, d} = m_d = \sum_x m_{x,d} \f$ , representing the sum of all zones with a given distance, are used.
     * The distance are given as the number of voxels to the border and the voxel intensity is given as the
     * bin number of the binned image, starting with 1.
     *
     * The following features are then defined:
     * - <b>Grey Level Distance Zone::Small Distance Emphasis</b>:
     * \f[ \textup{Small Distance Emphasis}= \frac{1}{N_s} \sum_d \frac{m_d}{d^2} \f]
     * - <b>Grey Level Distance Zone::Large Distance Emphasis</b>:
     * \f[ \textup{Large Distance Emphasis}= \frac{1}{N_s} \sum_d d^2 m_d \f]
     * - <b>Grey Level Distance Zone::Low Grey Level Emphasis</b>:
     * \f[ \textup{Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x  \frac{m_x}{x^2} \f]
     * - <b>Grey Level Distance Zone::High Grey Level Emphasis</b>:
     * \f[ \textup{High Grey Level Emphasis}= \frac{1}{N_s} \sum_x x^2 m_x \f]
     * - <b>Grey Level Distance Zone::Small Distance Low Grey Level Emphasis</b>:
     * \f[ \textup{Small Distance Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \frac{ m_{x,d}}{x^2 d^2}\f]
     * - <b>Grey Level Distance Zone::Small Distance High Grey Level Emphasis</b>:
     * \f[ \textup{Small Distance High Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \frac{x^2  m_{x,d}}{d^2}\f]
     * - <b>Grey Level Distance Zone::Large Distance Low Grey Level Emphasis</b>:
     * \f[ \textup{Large Distance Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \frac{d^2 m_{x,d}}{x^2}\f]
     * - <b>Grey Level Distance Zone::Large Distance High Grey Level Emphasis</b>:
     * \f[ \textup{Large Distance High Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \x^2 d^2 m_{x,d} \f]
     * - <b>Grey Level Distance Zone::Grey Level Non-Uniformity</b>:
     * \f[ \textup{Grey Level Non-Uniformity}= \frac{1}{N_s} \sum_x m_x^2 \f]
     * - <b>Grey Level Distance Zone::Grey Level Non-Uniformity Normalized</b>:
     * \f[ \textup{Grey Level Non-Uniformity Normalized}= \frac{1}{N_s^2} \sum_x m_x^2 \f]
     * - <b>Grey Level Distance Zone::Zone Distance Non-Uniformity</b>:
     * \f[ \textup{Grey Level Non-Uniformity}= \frac{1}{N_s} \sum_d m_d^2 \f]
     * - <b>Grey Level Distance Zone::Zone Distance Non-Uniformity Normalized</b>:
     * \f[ \textup{Grey Level Non-Uniformity Normalized}= \frac{1}{N_s^2} \sum_d m_d^2 \f]
     * - <b>Grey Level Distance Zone::Zone Percentage</b>: The ratio of zones to the possible zones:
     * \f[ \textup{Zone Percentage}= \frac{N_s}{N_v} \f]
     * - <b>Grey Level Distance Zone::Grey Level Mean</b>:
     * \f[ \textup{Grey Level Mean}= \mu_x = \sum_x \sum_d x p_{x,d} \f]
     * - <b>Grey Level Distance Zone::Grey Level Variance</b>:
     * \f[ \textup{Grey Level Variance} = \sum_x \sum_d \left(x - \mu_x \right)^2 p_{x,d} \f]
     * - <b>Grey Level Distance Zone::Zone Distance Mean</b>:
     * \f[ \textup{Zone Distance Mean}= \mu_d = \sum_x \sum_d d p_{x,d} \f]
     * - <b>Grey Level Distance Zone::Zone Distance Variance</b>:
     * \f[ \textup{Zone Distance Variance} = \sum_x \sum_d \left(d - \mu_d \right)^2 p_{x,d} \f]
     * - <b>Grey Level Distance Zone::Zone Distance Entropy </b>:
     * \f[ \textup{Zone Distance Entropy} = - \sum_x \sum_d p_{x,d} \textup{log}_2 ( p_{x,d} ) \f]
     * - <b>Grey Level Distance Zone::Grey Level Entropy </b>:
     * \f[ \textup{Grey Level Entropy} = - \sum_x \sum_d p_{x,d} \textup{log}_2 ( p_{x,d} ) \f]
     */
    public:
      mitkClassMacro(GIFGreyLevelDistanceZone, AbstractGlobalImageFeature);
      itkFactorylessNewMacro(Self);
      itkCloneMacro(Self);

      GIFGreyLevelDistanceZone();

      /**
       * \brief Calculate grey level distance zone features for the given image and mask.
       *
       * \param[in] image The input intensity image.
       * \param[in] mask The binary mask defining the region of interest.
       * \param[in] maskNoNAN The mask with NaN voxels excluded.
       * \return A list of computed feature name-value pairs.
       */
      FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override;
      using Superclass::CalculateFeatures;

      /**
       * \brief Add command line arguments for configuring this feature class.
       * \param[in,out] parser The command line parser to add arguments to.
       */
      void AddArguments(mitkCommandLineParser& parser) const override;

    protected:
      FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override;
  };

}
#endif
