#ifndef SASCALCAZIMUTHPROFILE
#define SASCALCAZIMUTHPROFILE

#include "Header.hh"
#include "CppToPython.hh"
#include "ManipulatorBase.hh"
#include "ElementContainerMatrix.hh"
#include "UtsusemiHeader.hh"

//////////////////////////////////
// CalcAzimuthProfile
/////////////////////////////////

//! Function to calculate azimuth profile for SAS
/*!
 *
 * tt=CalcAzimuthProfile( ECM ) // ECM is output from ConvertToQspace
 * tt.SetQRadius( 5.6, 0.1 )    // Q circle with radius of 5.6 [1/A] and width of 0.1 [1/A]
 * tt.SetAzimuthBinning( 0.5 )  // Binning along azimuth angle direction
 * EC = tt.GetAverage()         // Get result.
 *
 */

class CalcAzimuthProfile :
    public ManipulatorBase< ElementContainerMatrix >
{
private:
    std::vector<double> _AzimBin;         /**< Azimuth binning */
    double _AzimBinWidth;            /**< Azimuth binning width */
    std::pair<double,double> _AzimRange;  /**< Azimuth binning range (first:min, second:max) */
    std::pair<double,double> _QRange;     /**< |Q| range (first:min, second:max) */
    std::pair<double,double> _QzRange;    /**< Qz range (first:min, second:max) */
    std::pair<double,double> _LambRange;  /**< Lambda range (first:min, second:max) */

    UInt4 _NumOfMulth;

    std::vector< std::vector<double> > _Iazim; /**< Azimuth Profile intensity [multh][azim] */
    std::vector< std::vector<double> > _Error; /**< Azimuth Profile error [multh][azim] */
    std::vector< std::vector<double> > _Count; /**< Azimuth Profile number of pixels [multh][azim] */
    std::pair<double,double> MakeBinsZeroCenter( double s_val, double e_val, double step );
    void Initialize();
    std::string _MessageTag;

public:
    CalcAzimuthProfile();
        //!< Constructor
        /*!<
         *
         */
    CalcAzimuthProfile( ElementContainerMatrix* ecm );
        //!< Constructor
        /*!<
         *  @param ecm ElementContainerMatrix for the target
         */
    ~CalcAzimuthProfile();
        //!< Destructor
        /*!<
         *
         */
    bool SetAzimuthBinning( double azim_bin, double azim_min=0.0, double azim_max=360.0 );
        //!< Sets binning information along azimuth direction [degree]
        /*!<
         *  @param azim_bin (Double) binning width
         *  @param azim_min (Double) minimum value on azimuth axis
         *  @param azim_max (Double) max value on azimuth axis
         *  @retval true   succeeded.
         *  @retval false  failed.
         */
    bool SetQRadius( double q_center, double q_width );
        //!< Sets the radius and width on |Q| used to make profile.
        /*!<
         *  @param q_center (Double) the radius |Q| [1/Ang]
         *  @param q_width  (Double) |Q| width used to make profile. [1/Ang]
         *  @retval true   succeeded.
         *  @retval false  failed.
         */
    bool SetQzRange( double qz_min, double qz_max );
        //!< Sets Qz axis range used to make profile.
        /*!< If not set, all Qz are used.
         *
         *  @param qz_min (Double) [1/Ang]
         *  @param qz_max (Double) [1/Ang]
         *  @retval true   succeeded.
         *  @retval false  failed.
         */
    bool SetLambRange( double lamb_min, double lamb_max );
        //!< Sets lambda range used to make profile.
        /*!< If not set, all lambda range are used.
         *
         *  @param lamb_min (Double) [Ang]
         *  @param lamb_max (Double) [Ang]
         *  @retval true   succeeded.
         *  @retval false  failed.
         */
    ElementContainer Execute( bool isIncludeQz=true, bool isAverage=true );
        //!< Makes and return the azimuth profile
        /*!<
         *
         *  @param isIncludeQz (bool) true: Qz value is included in calcurating |Q|
         *  @param isAverage   (bool) true: takes intensity average to make profile, false: just intensity summation
         *  @return ElementContainer
         */
    ElementContainer GetProfileAverage( bool isIncludeQz=false ){ return Execute( isIncludeQz, true ); }
        //!< Makes and return the azimuth profile with intensity averaging
        /*!<
         *
         *  @param isIncludeQz (bool) true: Qz value is included in calcurating |Q|
         *  @return ElementContainer
         */
    ElementContainer GetProfileSum( bool isIncludeQz=false ){ return Execute( isIncludeQz, false ); }
        //!< Makes and return the azimuth profile with intensity summation
        /*!<
         *
         *  @param isIncludeQz (bool) true: Qz value is included in calcurating |Q|
         *  @return ElementContainer
         */
};
#endif
