#ifndef MLFDETECTOREFFICIENCYCORRECTION
#define MLFDETECTOREFFICIENCYCORRECTION

#include "HeaderBase.hh"
#include "ElementContainer.hh"
#include "ElementContainerArray.hh"
#include "ElementContainerMatrix.hh"
#include "MlfHeader.hh"
#include "MlfScatAbsoBodyManager.hh"
#include "MlfPhysicalConstants.hh"
#include "StringTools.hh"

////////////////////////////////////
// MlfDetectorEfficiencyCorrection
////////////////////////////////////

//! Data Correction of Detector Efficiency
/*!
 *  This codes are used for the detector efficiency correction.
 *
 *  @author Yasuhiro Inamura (J-PARC,MLF)
 *
 *  Usage : direct calculation for each pixel
 *  DEC = MlfDetectorEfficiencyCorrection( "/path/to/DetectorInfo.xml", "SUS-304-3He-PSD" )
 *  DEC.Execute( dat )
 *
 *  Usage : using approximate values
 *  DEC = MlfDetectorEfficiencyCorrection( "/path/to/DetEffi_SIK-SUS-304-3He-PSD.dat" )
 *  DEC.Execute( dat )
 *
 *  The pixel position info must be included in HeaderBase for each ElementContainer
 *  with format std::vector<Double> [Px,Py,Pz];
 *
 */

class MlfDetectorEfficiencyCorrection
{

private:
    void ClearMNG();
    UInt4 _NumOfMulTh;
    std::vector<std::string> _XmlSearchPaths;
    static const UInt4 _APPROXDATA_HEADER_BUF_SIZE;
    std::string _MessageTag;
    std::string _DetectorName;
    bool Initialize();
    StringTools* _st;

protected:
    std::vector< MlfScatAbsoBodyManager* > *_MNG;
    Double **EffiApproxBox;
    UInt4 _num_of_Lambda;
    UInt4 _num_of_Th;
    Double _min_Lambda;
    Double _delta_Lambda;
    Double _min_Th;
    Double _delta_Th;
public:
    MlfDetectorEfficiencyCorrection();
    MlfDetectorEfficiencyCorrection( std::string _detInfo, std::string _detName, std::string _xsecDataPath="", std::string _xmlPath="" );
    MlfDetectorEfficiencyCorrection( std::string _apDataPath );
        //!< Constructor
        /*!<
         *    MlfDetectorEfficiencyCorrection()
         *    MlfDetectorEfficiencyCorrection( std::string _detInfo, std::string _detName="" )
         *
         *    @param _detInfo (std::string) path to DetectorInfo.xml which must include <detectorStructure>.
         *    @param _detName (std::string) Detector Name like "SUS304-3He-PSD". This name must be included <detectorStructure>.
         *    @param _xsecDataPath (std::string) path to Xsection table xml file
         *    @param _xmlPath (std::string) path to the directory including xml files
         *    @return None
         */
    ~MlfDetectorEfficiencyCorrection();
        //!< Destructor
        /*!<
         */
    bool Initialize( std::string _detInfoName, std::string _detName, std::string _xsecDataName="");
        //!< Sets DetectorInfo and detNmae
        /*!<
         *    Sets DetectorInfo (including  <detectorStructure>) and detName
         *    to set parameters for calculations of detector efficiency.
         *
         *    @param _detInfo (std::string) path to DetectorInfo.xml which must include <detectorStructure>.
         *    @param _detName (std::string) Detector Name like "SUS304-3He-PSD". This name must be included <detectorStructure>.
         *    @retval  true   suceeded.
         *    @retval  false  failed.
         */
    void SetXmlPath( std::string path );
    void SetXmlPath( std::vector<std::string> paths );
    void AddXmlPath( std::string path );
        //!< Set path(s) to find xml files
        /*!<
         *
         *    @param path  (std::string)
         *    @param paths (std::vector<std::string>)
         *    @return None
         */
    void Execute( ElementContainerMatrix* _ecm );
        //!< Executes Detector Efficiency correction
        /*!<
         *
         *    @param _ecm (ElementContainerMatrix)  Target Data
         *    @return None
         */
    void ReplaceWithEfficiency( ElementContainerMatrix* _ecm );
        //!< Set Detector Efficiency values into ElementContainer
        /*!<
         *   This replaces the intensity of given ElementContainer with the calculated detector efficiency.
         *
         *    @param _ecm (ElementContainerMatrix)  Target Data
         *    @return None
         */
    Double GetEfficiency( double Ef, double theta );
        //!< Gets detector efficiency value
        /*!<
         *    @param Ef    (Double)  [meV]
         *    @param theta (Double)  [degree] angle from perpendicular to detector to the incident direction
         *    @return double value of efficiency
         */
    bool MakeApproximateData( std::string path, double Ef_min, double Ef_max, UInt4 Ef_num, double th_min, double th_max, UInt4 th_num );
        //!< Makes data file storing approximate value of detector efficiency
        /*!<
         *    @param path   (std::string)  path of data file to be saved
         *    @param Ef_min (Double)  min value of Ef range [meV]
         *    @param Ef_min (Double)  max value of Ef range [meV]
         *    @param Ef_num (UInt4)   the number of Ef range divisions [meV]
         *    @param th_min (Double)  min value of theta range [meV]
         *    @param th_min (Double)  max value of theta range [meV]
         *    @param th_num (UInt4)   the number of theta range divisions [meV]
         *    @retval true  : succeeded.
         *    @retval false : failed.
         */
    bool LoadApproximateData( std::string path );
        //!< Loads data from file storing approximate values of detector efficiency
        /*!<
         *    @param path   (std::string)  path of data file to be saved
         *    @retval true  : succeeded.
         *    @retval false : failed.
         */
    Double GetEfficiencyApproximateVal(double Ef, double theta);
        //!< Gets detector efficiency approximate value from loaded data file
        /*!< Aproximate value is calculated by interpolation using values matrix with lambda and theta axes.
         *
         *    @param Ef    (Double)  [meV]
         *    @param theta (Double)  [degree] angle from perpendicular to detector to the incident direction
         *    @return double value of efficiency
         */
    Double EToLambda( Double ene);
        //!< Converts enrgy value [meV] to wave length [1/Ang] of neutrons
        /*!<
         *    @param ene    (Double)  [meV]
         *    @return double value of wave length
         */
    Double LambdaToE( Double lambda );
        //!< Converts wave length [1/Ang] to enrgy value [meV] of neutrons
        /*!<
         *    @param lambda (Double)  [1/Ang]
         *    @return double value of eneryg
         */
    std::vector<Double> PutApproximateDataRange( std::string path="" );
        //!< Returns data range from file storing approximate values of detector efficiency
        /*!<
         *    @param path   (std::string)  path of data file to be saved
         *    @return std::vector<double> [<Ef_min>, <Ef_max>, <num_of_Ef>, <Th_min>, <Th_max>, <num_of_Th> ]
         */
};

#endif
