#ifndef EQUIPMENTMANAGER
#define EQUIPMENTMANAGER

#include <vector>
#include <string>
#include "Header.hh"
#include "CppToPython.hh"


//#include "./2A/detector_manager.hh"

//using namespace std;

/**
* struct coordinate
* @param x, y, z :: coordinate
*/

struct coordinate{
  Double x;
  Double y;
  Double z;
};


struct detectorInfo{
  struct coordinate Dtec1Pos, Dtec2Pos;
  Double phi560, theta;
  Double wBin1, wBin2;
  Double offset1, offset2;
  Bool status1, status2;
};


/*
struct equipInformation{
  //equipment
  Double L1, d_L1;
  Double phi625, d_phi625;
  Double w120, d_w120;
  Double w92, d_w92;

  //analyzer
  Double upper_r2300, d_upper_r2300;
  Double upper_d_miller, d_upper_d_miller;
  struct coordinate upper_center, d_upper_center;
  Double upper_theta_upper, d_upper_theta_upper;
  Double upper_theta_lower, d_upper_theta_lower;

  Double lower_r2300, d_lower_r2300;
  Double lower_d_miller, d_lower_d_miller;
  struct coordinate lower_center, d_lower_center;
  Double lower_theta_upper, d_lower_theta_upper;
  Double lower_theta_lower, d_lower_theta_lower;

  //detector
  Double upperDetectorWindowLower;
  Double upperDetectorWindowUpper;
  Double lowerDetectorWindowLower;
  Double lowerDetectorWindowUpper;

  Double upper_detector_y_upper;
  Double upper_detector_y_lower;
  Double lower_detector_y_upper;
  Double lower_detector_y_lower;
  struct detectorInfo **upperDetInfo;
  struct detectorInfo **lowerDetInfo;
};
*/


/**
 * AdvEquipmentManagerDNA Class manages the data of DNA equipment.
 *
 * @author skoike@advacnesoft
 * @version 1.0
*/
class AdvEquipmentManagerDNA{
  private:
    std::string filename; /**< filename described of the data of DNA equipment */
    std::string filepath; /**< filename described of the data of DNA equipment */

//    struct equipInformation equipInfo;
    //equipment
    Double L1; /**< Length between moderator and sample */
    Double d_L1; /**< Offset of "L1" */
    Double phi625; /**< Diameter of sample room */
    Double d_phi625; /**< Offset of "phi625" */
    Double w120; /**< Upper hight of sample room measured from sample position */
    Double d_w120; /**< Offset of "w120" */
    Double w92; /**<  Lower hight of sample room measured from sample position */
    Double d_w92; /**< Offset of "w92" */

    //analyzer
    Double upper_r2300; /**< Radius of the upper analyzer mirror */
    Double d_upper_r2300; /**< Offset of "upper_r2300" */
    Double upper_d_miller; /**< Distance between atomic surface of the upper analyzer mirror */
    Double d_upper_d_miller; /**< Offset of "upper_d_miller" */
    struct coordinate upper_center; /**< Center position of the sphere of the upper analyzer mirror */
    struct coordinate d_upper_center; /**< Offset of "upper_center" */
    Double upper_theta_upper; /**< Polar angle of the highest point of the upper analyzer mirror in NeXus-coordinate system */
    Double d_upper_theta_upper; /**< Offset of "upper_theta_upper" */
    Double upper_theta_lower; /**< Polar angle of the lowest point of the upper analyzer mirror in NeXus-coordinate system */
    Double d_upper_theta_lower; /**< Offset of "upper_theta_lower" */

    Double lower_r2300; /**< Radius of the lower analyzer mirror */
    Double d_lower_r2300; /**< Offset of "lower_r2300" */
    Double lower_d_miller; /**< Distance between atomic surface of the lower analyzer mirror */
    Double d_lower_d_miller; /**< Offset of "lower_d_miller */
    struct coordinate lower_center; /**< Center position of the sphere of the lower analyzer mirror */
    struct d_lower_center; /**< Offset of "lower_center" */
    Double lower_theta_upper; /**< Polar angle of the highest point of the lower analyzer mirror in NeXus-coordinate system */
    Double d_lower_theta_upper; /**< Offset of "lower_theta_upper" */
    Double lower_theta_lower; /**< Polar angle of the lowest point of the lower analyzer mirror in NeXus-coordinate system */
    Double d_lower_theta_lower; /**< Offset of "lower_theta_lower" */

    //detector
    Double upperDetectorWindowLower; /**< The lowest height of the window for the upper detector */
    Double upperDetectorWindowUpper; /**< The highest height of the window for the upper detector */
    Double lowerDetectorWindowLower; /**< The lowest height of the window for the lower detector */
    Double lowerDetectorWindowUpper; /**< The highest height of the window for the lower detector */

    Double upper_detector_y_upper; /**< height of the highest detecting point of upper detector */
    Double upper_detector_y_lower; /**< height of the lowest detecting point of upper detector */
    Double lower_detector_y_upper; /**< height of the highest detecting point of lower detector */
    Double lower_detector_y_lower; /**< height of the lowest detecting point of lower detector */
    struct detectorInfo **upperDetInfo; /**< struct-type variable which include each upper PSD information */
    struct detectorInfo **lowerDetInfo; /**< struct-type variable which include each lower PSD information */
    Double wBin; /**< value of bin of detector */
    Double offset; /**< offset value for detector.*/
    Double phi560; /**< value of diameter of PSD group */
    Double phi127; /**< value of diameter of a PSD */
    Double d12; /**< the opening length between right and left part of U-shaped PSD */
    Double psdRadius; /**< length between the center of PSD and of right ( or left ) part of PSD */
    Double psdPosX; /**< x coordinate of the cetner of right ( or left ) part of PSD */
    Double psdPosY; /**< y coordinate of the cetner of right ( or left ) part of PSD */
    Double psdPosZ; /**< z coordinate of the cetner of right ( or left ) part of PSD */
    Double theta0; /**< degree. maxmum value of psdTheta */
    Double wTheta; /**< degree. degree of one PSD */

    void ReadEquipmentDefaultData(void);

    UInt4 numPsdPerUnit; /**< number of PSDs in unit */
    UInt4 numUnit; /**< number of PSD units */

    void SetUpperDetInfo(std::string); /**< set upper detector info */
    void SetLowerDetInfo(std::string); /**< set lower detector info */
    void SetUpperDetInfoPos(UInt4, UInt4); /**< set upper detector position */
    void SetLowerDetInfoPos(UInt4, UInt4); /**< set lower detector position */

    Double epsilon;       /**< the threshold value of convergence of integral */
    Double epsilonRatio;  /**< the threshold value of convergence of integral */

  public:
    /** constructor */
    AdvEquipmentManagerDNA(void);
    AdvEquipmentManagerDNA(std::string);

//    AdvEquipmentManagerDNA(Double, Double);
    /** destructor */
    ~AdvEquipmentManagerDNA(void);

    /**
     * return L1 value.
     *
     * @return value of "L1"
     */
    Double GetL1(void) { return L1; };

    /**
     * return the value of radius of the upper analyzer mirror
     *
     * @return value of radius of the upper analyzer mirror
     */
    Double GetUpperRadius(void) { return upper_r2300; };

    /**
     * return the value of radius of the lower analyzer mirror
     *
     * @return value of radius of the lower analyzer mirror
     */
    Double GetLowerRadius(void) { return lower_r2300; };

    /**
     * return the value of distance between atomic surface of the upper analyzer mirror
     *
     * @return value of distance between atomic surface of the upper analyzer mirror
     */
    Double GetUppLtcSpc(void) { return upper_d_miller; };

    /**
     * return the value of distance between atomic surface of the lower analyzer mirror
     *
     * @return value of distance between atomic surface of the lower analyzer mirror
     */
    Double GetLowLtcSpc(void) { return lower_d_miller; };

    /**
     * return the value of the polar angle of the highest point of the upper analyzer mirror in NeXus-coordinate system
     *
     * @return value of the polar angle of the highest point of the upper analyzer mirror in NeXus-coordinate system
     */
    Double GetMaxThetaUpperMirror(void) { return upper_theta_upper; };

    /**
     * return the value of the polar angle of the lowest point of the upper analyzer mirror in NeXus-coordinate system
     *
     * @return value of the polar angle of the lowest point of the upper analyzer mirror in NeXus-coordinate system
     */
    Double GetMinThetaUpperMirror(void) { return upper_theta_lower; };

    /**
     * return the value of the polar angle of the highest point of the lower analyzer mirror in NeXus-coordinate system
     *
     * @return value of the polar angle of the highest point of the lower analyzer mirror in NeXus-coordinate system
     */
    Double GetMaxThetaLowerMirror(void) { return lower_theta_upper; };

    /**
     * return the value of the polar angle of the lowest point of the lower analyzer mirror in NeXus-coordinate system
     *
     * @return value of the polar angle of the lowest point of the lower analyzer mirror in NeXus-coordinate system
     */
    Double GetMinThetaLowerMirror(void) { return lower_theta_lower; };

    Int4 GetCenterPosUpperMirror(struct coordinate*);
    Int4 GetCenterPosLowerMirror(struct coordinate*);

/*
    void GenerateNeutron(UInt4, UInt4, Double, Double, Double, struct coordinate);
*/
    void GenerateNeutron(UInt4, UInt4, Double, Double, Double, Double, Double, Double);


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

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

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

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



    /**
     * return the value of diameter of sample room
     *
     * @return value of diameter of sample room
     */
    Double GetPhi625(void) { return phi625; };

    /**
     * return the value of diameter for group of PSD units
     *
     * @param[in] i PSD unit number in group
     * @param[in] j PSD number in unit
     * @return value of diameter for group of PSD units
     */
    Double GetUpperDetectorPhi(int i, int j) { return upperDetInfo[i][j].phi560; };

    /**
     * return the value of upper hight of sample room measured from sample position
     *
     * @return value of upper hight of sample room measured from sample position
     */
    Double GetW120(void) { return w120; };

    /**
     * return the value of lower hight of sample room measured from sample position
     *
     * @return value of lower hight of sample room measured from sample position
     */
    Double GetW92(void) { return w92; };

    /**
     * return the value of the lowest height of the window for the upper detector
     *
     * @return value of the lowest height of the window for the upper detector
     */
    Double GetUpperDetectorWindowLower(void){ return upperDetectorWindowLower; };

    /**
     * return the value of the highest height of the window for the upper detector
     *
     * @return value of the highest height of the window for the upper detector
     */
    Double GetUpperDetectorWindowUpper(void){ return upperDetectorWindowUpper; };

    /**
     * return the value of the lowest height of the window for the lower detector
     *
     * @return value of the lowest height of the window for the lower detector
     */
    Double GetLowerDetectorWindowLower(void){ return lowerDetectorWindowLower; };

    /**
     * return the value of the highest height of the window for the lower detector
     *
     * @return value of the highest height of the window for the lower detector
     */
    Double GetLowerDetectorWindowUpper(void){ return lowerDetectorWindowUpper; };

    PyObject* GetThetaEnergy(void);
};

#endif
