#ifndef DETECTORMANAGER
#define DETECTORMANAGER

#include <vector>

#include "Header.hh"
#include "CppToPython.hh"
#include "ElementContainer.hh"

//#include "AdvScatAbsoBodyManagerDNA.hh"
#include "AdvScatAbsoBodyManagerMLF.hh"

//using namespace std;

/** detector's absorption correction
 *
 *  @author KOIKE Soh, AdvanceSoft Corp. (original, core)
 *  @author TANIMORI Souichirou, AdvanceSoft Corp. (rewrite comment, interface)
 *  @version 0.0
 *  @since   0.0
 */
//class AdvDetectorManagerDNA : public AdvScatAbsoBodyManagerDNA {
class AdvDetectorManagerDNA : public AdvScatAbsoBodyManagerMLF {
  private:
    std::string filename;
    std::string filepath;


//    Double epsilon;
//    Double epsilonRatio;
    Double sigmaDetectorA;
    Double sigmaWallA;
    Double sigmaWallS;
    struct ScatAbsoInfo detectorInfo;
    struct ScatAbsoInfo wallInfo;

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector1(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector2(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector3(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector4(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector5(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector6(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector7(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    /** return absorption by detector
     *  @param[in] x                ?
     *  @param[in] theta            angle
     *  @param[in] sigmaDA          detector's effective absorption cross section
     *  @param[in] sigmaWS          wall's effective scattering cross section
     *  @param[in] sigmaWA          wall's effective absorption cross section
     *  @param[in] radiusDetector   detector's outor radius
     *  @param[in] radiusWall       wall's outor radius
     *  @param[in] n3He             detector's total density
     *  @param[in] nwall            wall's total density
     *  @param[in] T                wall's ratioT
     */
    Double ReturnAbsorptionByDetector8(Double, Double, Double, Double, Double, Double, Double, Double, Double, Double, Double);

    void GetCorrectionTableLambda(Double, Double, Double*, Double*, Double*, Double*, Double*);
    void GetCorrectionTableTheta(Double, Double, Double*, Double*, Double*, Double*, Double*);



/*
    struct EffCoef{
      Double i0;
      Double i1;
      Double i2;
      Double i3;
      Double i4;
    } efficiencyCoefTable;
*/

  public:
    /** constructor */
    AdvDetectorManagerDNA(void);
    AdvDetectorManagerDNA(std::string filepath);

    /** destructor */
    ~AdvDetectorManagerDNA(void);

    /** get the values of effective cross sections from an energy value
     *  @param[in]  energy  neutron's energy in meV
     *  @param[out] sigmaDA detector's effective absorption cross section
     *  @param[out] sigmaWA wall's effective absorption cross section
     *  @param[out] sigmaWS wall's effective scattering cross section
     */
    void GetSigmas(Double energy, Double* sigmaDA, Double* sigmaWA, Double* sigmaWS);

    /** evaluate detector's effective absorption cross section from energy.
     *  @param[in] energy neutron's enenrgy, unit meV
     */
    Double GetSigmaDA(Double enenrgy);

    /** evaluate wall's effective absorption cross section from energy.
     *  @param[in] energy neutron's enenrgy, unit meV
     */
    Double GetSigmaWA(Double enenrgy);

    /** evaluate wall's effective scatterring cross section from energy.
     *  @param[in] energy neutron's enenrgy, unit meV
     */
    Double GetSigmaWS(Double enenrgy);

    /** evaluate detection efficiency.
     *  @param[in] angle   incedent angle in degrees
     *  @param[in] sigmeDA detector's effective absorption cross section
     *  @param[in] sigmeWA wall's effective absorption cross section
     *  @param[in] sigmeWS wall's effective scattering cross section
     */
    Double CalcEfficiencyDetector(Double angle, Double sigmaDA, Double sigmaWA, Double sigmaWS);

//    Double return_integral_efficiency_detector(Double, coordinate*, Double, Double, Double);

    /** evaluate the efficiency from nutrin's enenrgy and theta
     *  @param[in] eneNeutron     neutron's energy
     *  @param[in] thetaDetector  theta
     */
    Double GetEfficiency(Double eneNutron, Double thetaDetector);

    /** evaluate the efficiency of detector
     *  @param[in] num            ?
     *  @param[in] thetaDetector  angle
     *  @param[in] sigmaDA        detector's effective absorption cross section
     *  @param[in] sigmaWS        wall's effective scattering cross section
     *  @param[in] sigmaWA        wall's effective absorption cross section
     *  @param[in] lamda0         ?
     */
    Double CalcCoefEfficiencyDetector(UInt4 num, Double thetaDetector, Double sigmaDA, Double sigmaWS, Double sigmaWA, Double lamda0);

    /** evaluate the efficiency from nutrin's enenrgy and theta and print out coefficients
     *  @param[in] eneNeutron     neutron's energy
     *  @param[in] thetaDetector  theta
     */
    Double GetEfficiencyTable(Double, Double);

    /** evaluate the 2nd order correction
     *  @param[in] eneNeutron     neutron's energy
     *  @param[in] thetaDetector  angle
     *  @param[in] deltaEne       delta energy
     *  @param[in] hosei0         0-th. order coefficient for correction
     *  @param[in] hosei1         1st. order coefficient for correction
     *  @param[in] hosei2         2nd.  order coefficient for correction
     *  @param[in] hosei3         dummy
     *  @param[in] hosei4         dummy
     */
    Double GetCorrectEff2(Double eneNeutron, Double thetaDetector, Double deltaEne, Double hosei0, Double hosei1, Double hosei2, Double hosei3, Double hosei4);

    /** evaluate up to the 4th. order correction
     *  @param[in] eneNeutron     neutron's energy
     *  @param[in] thetaDetector  angle
     *  @param[in] deltaEne       delta energy
     *  @param[in] hosei0         0th. order coefficient for correction
     *  @param[in] hosei1         1st. order coefficient for correction
     *  @param[in] hosei2         2nd. order coefficient for correction
     *  @param[in] hosei3         3rd. order coefficient for correction
     *  @param[in] hosei4         4th. order coefficient for correction
     */
    Double GetCorrectEff4(Double eneNeutron, Double thetaDetector, Double deltaEne, Double hosei0, Double hosei1, Double hosei2, Double hosei3, Double hosei4);

    /** evaluate up to the 4th. order correction
     *  @param[in] eneNeutron     neutron's energy
     *  @param[in] thetaDetector  angle
     *  @param[in] deltaTheta     delta theta
     *  @param[in] hosei0         0th. order coefficient for correction
     *  @param[in] hosei1         1st. order coefficient for correction
     *  @param[in] hosei2         2nd. order coefficient for correction
     *  @param[in] hosei3         dummy
     *  @param[in] hosei4         dummy
     */
    Double GetCorrectThetaEff2(Double eneNutron, Double thetaDetector, Double deltaTheta, Double hosei0, Double hosei1, Double hoseie2, Double hosei3, Double energy);

    /** evaluate up to the 4th. order correction
     *  @param[in] eneNeutron     neutron's energy
     *  @param[in] thetaDetector  angle
     *  @param[in] deltaTheta     delta theta
     *  @param[in] hosei0         0th. order coefficient for correction
     *  @param[in] hosei1         1st. order coefficient for correction
     *  @param[in] hosei2         2nd. order coefficient for correction
     *  @param[in] hosei3         3rd. order coefficient for correction
     *  @param[in] hosei4         4th. order coefficient for correction
     */
    Double GetCorrectThetaEff4(Double, Double, Double, Double, Double, Double, Double, Double);


    /** output integral values to table file.
     *  @param[in] inputMinEnergy  the lower bound of energy range (in m eV)
     *  @param[in] inputMaxEnergy  the upper bound of energy range (in m eV
     *  @param[in] divnum          the number of division of the energy range
     *  @paran[in] thetaDetector   angle (in Degree)
     *  @paran[out] ec             a container for results
     */
    void MakeTable(Double inputMiniEnenrgy, Double inputMaxEnenrgy, UInt4 devnum, Double inputThetaDetector, ElementContainer& ec);
    //void MakeTable(Double inputMiniEnenrgy, Double inputMaxEnenrgy, UInt4 devnum, Double inputThetaDetector);

    /** output integral values to table file.
     *  @param[in] inputMinTheta  the lower bound of angle range (in degrees)
     *  @param[in] inputMaxTheta  the upper bound of angle range (in degrees)
     *  @param[in] divnum         the number of division of the angle range
     *  @paran[in] inputEnergyr   neutron's energy (in meV)
     *  @paran[out] ec            a container for results
     */
    void MakeTableTheta(Double inputMinTheta, Double inputMaxTheta, UInt4 divnum, Double inputEnergy, ElementContainer& ec);
    //void MakeTableTheta(Double inputMinTheta, Double inputMaxTheta, UInt4, Double);

    /** get corrected intensity.
     *  @param[in] inputEnenrgyList
     *  @param[in] inputIntensityList
     *  @param[in] thetaDetactor
     *  @return a list of corrected intensity value
     */
    std::vector<Double> GetCorrectIntensity(std::vector<Double> inputEnenrgyList, std::vector<Double> inputIntensityList, Double thetaDetector);

    /** get correctord intensity forPython.
     *  @param[in] value1 a list of input energy, Python's llist
     *  @param[in] value2 a list of input intensity, Python's list
     *  @param[in] thetaDetactor
     *  @return a list of corrected intensity value, Python's list
     */
    PyObject* GetCorrectIntensityFromPython(PyObject *value1, PyObject *value2, Double thetaDetector);

    /**
     * set threshold value used for judgement of convergence in numerial integral
     *
     * @set epsilon
     */
    void SetIntegThresholdValue(Double a) {epsilon=a;};

    /**
     * set threshold value Ratio used for judgement of convergence in numerial integral
     *
     * @set epsilonRatio
     */
    void SetIntegThresholdRatio(Double a) {epsilonRatio=a;};


    /**
     * return threshold value used for judgement of convergence in numerial integral
     *
     * @return epsilon
     */
    Double GetIntegThresholdValue(void) {return epsilon;};

    /**
     * return threshold value of ratio used for judgement of convergence in numerial integral
     *
     * @return epsilonRatio
     */
    Double GetIntegThresholdRatio(void) {return epsilonRatio;};

};

#endif
