/*=========================================================================
*
*  Copyright NumFOCUS
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0.txt
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*=========================================================================*/
#ifndef sitkLabelIntensityStatisticsImageFilter_h
#define sitkLabelIntensityStatisticsImageFilter_h

/*
 * WARNING: DO NOT EDIT THIS FILE!
 * THIS FILE IS AUTOMATICALLY GENERATED BY THE SIMPLEITK BUILD PROCESS.
 * Please look at sitkDualImageFilterTemplate.h.in to make changes.
 */

#include <memory>

#include "sitkImageFilter.h"
#include "sitkDualMemberFunctionFactory.h"
#include "sitkBasicFilters.h"

namespace itk::simple {

    /**\class LabelIntensityStatisticsImageFilter
\brief a convenient class to convert a label image to a label map and valuate the statistics attributes at once

\author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France.


This implementation was taken from the Insight Journal paper: https://doi.org/10.54294/q6auw4 

\see StatisticsLabelObject , LabelStatisticsOpeningImageFilter , LabelStatisticsOpeningImageFilter

\sa itk::LabelImageToStatisticsLabelMapFilter for the Doxygen on the original ITK class.
     */
    class SITKBasicFilters_EXPORT LabelIntensityStatisticsImageFilter : public ImageFilter {
    public:
      using Self = LabelIntensityStatisticsImageFilter;

      /** Destructor */
      virtual ~LabelIntensityStatisticsImageFilter();

      /** Default Constructor that takes no arguments and initializes
       * default parameters */
      LabelIntensityStatisticsImageFilter();

      /** Define the pixels types supported by this filter */
      using PixelIDTypeList = IntegerPixelIDTypeList;

\

      /**
       * Set/Get the value used as "background" in the output image. Defaults to NumericTraits<PixelType>::NonpositiveMin() .
       */
      SITK_RETURN_SELF_TYPE_HEADER SetBackgroundValue ( double BackgroundValue ) { this->m_BackgroundValue = BackgroundValue; return *this; }

      /**
       * Set/Get the value used as "background" in the output image. Defaults to NumericTraits<PixelType>::NonpositiveMin() .
       */
      double GetBackgroundValue() const { return this->m_BackgroundValue; }\

      /**
       * Set/Get whether the maximum Feret diameter should be computed or not. The default value is false, because of the high computation time required.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetComputeFeretDiameter ( bool ComputeFeretDiameter ) { this->m_ComputeFeretDiameter = ComputeFeretDiameter; return *this; }

      /** Set the value of ComputeFeretDiameter to true or false respectfully. */
      SITK_RETURN_SELF_TYPE_HEADER ComputeFeretDiameterOn() { return this->SetComputeFeretDiameter(true); }
      SITK_RETURN_SELF_TYPE_HEADER ComputeFeretDiameterOff() { return this->SetComputeFeretDiameter(false); }

      /**
       * Set/Get whether the maximum Feret diameter should be computed or not. The default value is false, because of the high computation time required.
       */
      bool GetComputeFeretDiameter() const { return this->m_ComputeFeretDiameter; }\

      /**
       * Set/Get whether the perimeter should be computed or not. The default value is false, because of the high computation time required.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetComputePerimeter ( bool ComputePerimeter ) { this->m_ComputePerimeter = ComputePerimeter; return *this; }

      /** Set the value of ComputePerimeter to true or false respectfully. */
      SITK_RETURN_SELF_TYPE_HEADER ComputePerimeterOn() { return this->SetComputePerimeter(true); }
      SITK_RETURN_SELF_TYPE_HEADER ComputePerimeterOff() { return this->SetComputePerimeter(false); }

      /**
       * Set/Get whether the perimeter should be computed or not. The default value is false, because of the high computation time required.
       */
      bool GetComputePerimeter() const { return this->m_ComputePerimeter; }\

      /**
       * Set/Get the number of bins in the histogram. Note that the histogram is used to compute the median value, and that this option may have an effect on the value of the median.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetNumberOfBins ( uint32_t NumberOfBins ) { this->m_NumberOfBins = NumberOfBins; return *this; }

      /**
       * Set/Get the number of bins in the histogram. Note that the histogram is used to compute the median value, and that this option may have an effect on the value of the median.
       */
      uint32_t GetNumberOfBins() const { return this->m_NumberOfBins; }
     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<unsigned int> GetBoundingBox(int64_t label) const { return this->m_pfGetBoundingBox(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<unsigned int> GetRegion(int64_t label) const { return this->m_pfGetRegion(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<double> GetCentroid(int64_t label) const { return this->m_pfGetCentroid(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetElongation(int64_t label) const { return this->m_pfGetElongation(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<double> GetEquivalentEllipsoidDiameter(int64_t label) const { return this->m_pfGetEquivalentEllipsoidDiameter(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetEquivalentSphericalPerimeter(int64_t label) const { return this->m_pfGetEquivalentSphericalPerimeter(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetEquivalentSphericalRadius(int64_t label) const { return this->m_pfGetEquivalentSphericalRadius(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetFeretDiameter(int64_t label) const { return this->m_pfGetFeretDiameter(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetFlatness(int64_t label) const { return this->m_pfGetFlatness(label); };

     /**
      *
      *
      * This is a measurement. Its value is updated in the Execute
      * methods, so the value will only be valid after an execution.
      */
     std::vector<int64_t> GetLabels() const { return this->m_Labels; };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     uint64_t GetNumberOfPixels(int64_t label) const { return this->m_pfGetNumberOfPixels(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     uint64_t GetNumberOfPixelsOnBorder(int64_t label) const { return this->m_pfGetNumberOfPixelsOnBorder(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetPerimeter(int64_t label) const { return this->m_pfGetPerimeter(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetPerimeterOnBorder(int64_t label) const { return this->m_pfGetPerimeterOnBorder(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetPerimeterOnBorderRatio(int64_t label) const { return this->m_pfGetPerimeterOnBorderRatio(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetPhysicalSize(int64_t label) const { return this->m_pfGetPhysicalSize(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<double> GetPrincipalAxes(int64_t label) const { return this->m_pfGetPrincipalAxes(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<double> GetPrincipalMoments(int64_t label) const { return this->m_pfGetPrincipalMoments(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetRoundness(int64_t label) const { return this->m_pfGetRoundness(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<double> GetCenterOfGravity(int64_t label) const { return this->m_pfGetCenterOfGravity(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetKurtosis(int64_t label) const { return this->m_pfGetKurtosis(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetMaximum(int64_t label) const { return this->m_pfGetMaximum(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<uint32_t> GetMaximumIndex(int64_t label) const { return this->m_pfGetMaximumIndex(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetMean(int64_t label) const { return this->m_pfGetMean(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetMedian(int64_t label) const { return this->m_pfGetMedian(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetMinimum(int64_t label) const { return this->m_pfGetMinimum(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<uint32_t> GetMinimumIndex(int64_t label) const { return this->m_pfGetMinimumIndex(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetSkewness(int64_t label) const { return this->m_pfGetSkewness(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetStandardDeviation(int64_t label) const { return this->m_pfGetStandardDeviation(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetSum(int64_t label) const { return this->m_pfGetSum(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetVariance(int64_t label) const { return this->m_pfGetVariance(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetWeightedElongation(int64_t label) const { return this->m_pfGetWeightedElongation(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetWeightedFlatness(int64_t label) const { return this->m_pfGetWeightedFlatness(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<double> GetWeightedPrincipalAxes(int64_t label) const { return this->m_pfGetWeightedPrincipalAxes(label); };

     /**
      *
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     std::vector<double> GetWeightedPrincipalMoments(int64_t label) const { return this->m_pfGetWeightedPrincipalMoments(label); };


      /** Name of this class */
      std::string GetName() const { return std::string ("LabelIntensityStatisticsImageFilter"); }

      /** Print ourselves out */
      std::string ToString() const;


      /** Execute the filter on the input image */

      void Execute ( const Image & image, const Image & featureImage );


      /** Does the specified label exist? Can only be called after a call a call to Update(). */
      bool HasLabel(int64_t label );

      /** Return the number of labels after execution. */
      uint64_t GetNumberOfLabels( );


    private:
      /** Setup for member function dispatching */
      using MemberFunctionType = void (Self::*)( const Image * image, const Image * featureImage );

      friend struct detail::DualExecuteInternalAddressor<MemberFunctionType>;
      template <class TImageType1, class TImageType2> void DualExecuteInternal ( const Image * image, const Image * featureImage );


      std::unique_ptr<detail::DualMemberFunctionFactory<MemberFunctionType> > m_DualMemberFactory;



      /*  */
      double  m_BackgroundValue{0};

      bool  m_ComputeFeretDiameter{false};

      bool  m_ComputePerimeter{true};

      uint32_t  m_NumberOfBins{128u};

      /* Docs */
      std::function<std::vector<unsigned int>(int64_t)> m_pfGetBoundingBox;
      /* Docs */
      std::function<std::vector<unsigned int>(int64_t)> m_pfGetRegion;
      /* Docs */
      std::function<std::vector<double>(int64_t)> m_pfGetCentroid;
      /* Docs */
      std::function<double(int64_t)> m_pfGetElongation;
      /* Docs */
      std::function<std::vector<double>(int64_t)> m_pfGetEquivalentEllipsoidDiameter;
      /* Docs */
      std::function<double(int64_t)> m_pfGetEquivalentSphericalPerimeter;
      /* Docs */
      std::function<double(int64_t)> m_pfGetEquivalentSphericalRadius;
      /* Docs */
      std::function<double(int64_t)> m_pfGetFeretDiameter;
      /* Docs */
      std::function<double(int64_t)> m_pfGetFlatness;
      /* Docs */
      std::vector<int64_t> m_Labels{std::vector<int64_t>()};
      /* Docs */
      std::function<uint64_t(int64_t)> m_pfGetNumberOfPixels;
      /* Docs */
      std::function<uint64_t(int64_t)> m_pfGetNumberOfPixelsOnBorder;
      /* Docs */
      std::function<double(int64_t)> m_pfGetPerimeter;
      /* Docs */
      std::function<double(int64_t)> m_pfGetPerimeterOnBorder;
      /* Docs */
      std::function<double(int64_t)> m_pfGetPerimeterOnBorderRatio;
      /* Docs */
      std::function<double(int64_t)> m_pfGetPhysicalSize;
      /* Docs */
      std::function<std::vector<double>(int64_t)> m_pfGetPrincipalAxes;
      /* Docs */
      std::function<std::vector<double>(int64_t)> m_pfGetPrincipalMoments;
      /* Docs */
      std::function<double(int64_t)> m_pfGetRoundness;
      /* Docs */
      std::function<std::vector<double>(int64_t)> m_pfGetCenterOfGravity;
      /* Docs */
      std::function<double(int64_t)> m_pfGetKurtosis;
      /* Docs */
      std::function<double(int64_t)> m_pfGetMaximum;
      /* Docs */
      std::function<std::vector<uint32_t>(int64_t)> m_pfGetMaximumIndex;
      /* Docs */
      std::function<double(int64_t)> m_pfGetMean;
      /* Docs */
      std::function<double(int64_t)> m_pfGetMedian;
      /* Docs */
      std::function<double(int64_t)> m_pfGetMinimum;
      /* Docs */
      std::function<std::vector<uint32_t>(int64_t)> m_pfGetMinimumIndex;
      /* Docs */
      std::function<double(int64_t)> m_pfGetSkewness;
      /* Docs */
      std::function<double(int64_t)> m_pfGetStandardDeviation;
      /* Docs */
      std::function<double(int64_t)> m_pfGetSum;
      /* Docs */
      std::function<double(int64_t)> m_pfGetVariance;
      /* Docs */
      std::function<double(int64_t)> m_pfGetWeightedElongation;
      /* Docs */
      std::function<double(int64_t)> m_pfGetWeightedFlatness;
      /* Docs */
      std::function<std::vector<double>(int64_t)> m_pfGetWeightedPrincipalAxes;
      /* Docs */
      std::function<std::vector<double>(int64_t)> m_pfGetWeightedPrincipalMoments;

      // Holder of process object for active measurements
      itk::ProcessObject *m_Filter{nullptr};

    };


}
#endif
