#include <cmath>
#include "AdvEquipmentManagerDNA.hh"
//#include "AdvPhysicalParameterDNA.hh"
#include "UtsusemiUnitConverter.hh"
#include "UtsusemiHeader.hh"
#include "AdvNeutronManagerDNA.hh"
#include "AdvDetectorManagerDNA.hh"

#include <iostream>
#include <fstream>
#include <string>

/**
 * A constructor.
 *
 * - Set filename of DNA data, and read data
 * - Set default value for wBin, offset, phi560, phi127, d12, psdRadius, theta0, wTheta.
 *
 */
AdvEquipmentManagerDNA:: AdvEquipmentManagerDNA(void){
  wBin=4.0*MLF_MM2M;
  offset=0.0*MLF_MM2M;
  phi560=560*MLF_MM2M;
  phi127=12.7*MLF_MM2M;
  d12=0.8*MLF_MM2M; // the opening length between right and left part of U-shaped PSD
  psdRadius=(phi127+d12)/2; // length between the center of PSD and of right ( or left ) part of PSD

  theta0=165.0*MLF_DEGREE2RADIAN; // maxmum value of psdTheta
  wTheta=6.0*MLF_DEGREE2RADIAN; //degree of one PSD

  //filename="/home/dnaadmin/ana/setup/equipment_data.dat";
  filename=UtsusemiEnvGetUserDir()+"/ana/DNA/setup/equipment_data.dat";

  ReadEquipmentDefaultData();

//  ScatAbsoDetector detector;
   AdvDetectorManagerDNA detector;
  epsilon=detector.GetIntegThresholdValue();
  epsilonRatio=detector.GetIntegThresholdRatio();

};

AdvEquipmentManagerDNA:: AdvEquipmentManagerDNA(std::string filepath){
  wBin=4.0*MLF_MM2M;
  offset=0.0*MLF_MM2M;
  phi560=560*MLF_MM2M;
  phi127=12.7*MLF_MM2M;
  d12=0.8*MLF_MM2M; // the opening length between right and left part of U-shaped PSD
  psdRadius=(phi127+d12)/2; // length between the center of PSD and of right ( or left ) part of PSD

  theta0=165.0*MLF_DEGREE2RADIAN; // maxmum value of psdTheta
  wTheta=6.0*MLF_DEGREE2RADIAN; //degree of one PSD

  filename=filepath;

  ReadEquipmentDefaultData();

//  ScatAbsoDetector detector;
   AdvDetectorManagerDNA detector;
  epsilon=detector.GetIntegThresholdValue();
  epsilonRatio=detector.GetIntegThresholdRatio();

};


/**
 * A destructor.
 *
 * Delete dynamical variables, upperDetInfo[][] and lowerDetInfo[][].
 */
AdvEquipmentManagerDNA:: ~AdvEquipmentManagerDNA(void){
  // delete upperDetInfo
  for(UInt4 i=0; i<numUnit; i++) delete[] upperDetInfo[i];
  delete[] upperDetInfo;
  // delete lowerDetInfo
  for(UInt4 i=0; i<numUnit; i++) delete[] lowerDetInfo[i];
  delete[] lowerDetInfo;
};

/**
 * Read the DNA data from file.
 *
 * Read the DNA data from file whose name is "std::string AdvEquipmentManagerDNA::filename".
 */
void AdvEquipmentManagerDNA :: ReadEquipmentDefaultData(void){
  // open data file of DNA data
  std::fstream fo(filename.c_str(), std::ios::in);
  if (fo.fail()){
    std::cerr<<"can't open file"<< filename <<std::endl;
  }

  // set temporary variable value
  std::string p;
  UInt4 lengthBuffer=256;
  //Char *buffer=new (Char[lengthBuffer]); // buffer for stock of line data in file
  Char *buffer=new Char[lengthBuffer]; // buffer for stock of line data in file
//  Double phi560=0.560; //default value of diagmeter of PSD group

  // get line data in file and set the value to corresponding variable.
  //while (fo.getline(buffer, lengthBuffer)!=NULL) {
  while (fo.getline(buffer, lengthBuffer)) {
    // check line data. if line is blank, read next line.
    if(std::strlen(buffer)>lengthBuffer) {
//      std::printf("something wrong\n");
    }
    else if(std::strlen(buffer)==0) {
      continue;
    }

    // analyze line-data and set the value to corresponding variable of SI unit.
    // MLF_MM2M ;; mili meter to meter
    // ANGSTROM2M : anstrom to meter
    // DEGREEE2RADIAN : degree to radian
    p=std::strtok(buffer, " =,");
    if (p=="L1") {
      p=std::strtok(NULL, " =,/");
      L1=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="phi625") {
      p=std::strtok(NULL, " =,/");
      phi625=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="w120") {
      p=std::strtok(NULL, " =,/");
      w120=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="w92") {
      p=std::strtok(NULL, " =,/");
      w92=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upper_r2300") {
      p=std::strtok(NULL, " =,/");
      upper_r2300=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="lower_r2300") {
      p=std::strtok(NULL, " =,/");
      lower_r2300=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upper_d_miller") {
      p=std::strtok(NULL, " =,/");
      upper_d_miller=atof(p.c_str())*MLF_ANGSTROM2M;
    }
    else if (p=="lower_d_miller") {
      p=std::strtok(NULL, " =,/");
      lower_d_miller=atof(p.c_str())*MLF_ANGSTROM2M;
    }
    else if (p=="upper_center_x") {
      p=std::strtok(NULL, " =,/");
      upper_center.x=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upper_center_y") {
      p=std::strtok(NULL, " =,/");
      upper_center.y=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upper_center_z") {
      p=std::strtok(NULL, " =,/");
      upper_center.z=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="lower_center_x") {
      p=std::strtok(NULL, " =,/");
      lower_center.x=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="lower_center_y") {
      p=std::strtok(NULL, " =,/");
      lower_center.y=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="lower_center_z") {
      p=std::strtok(NULL, " =,/");
      lower_center.z=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upper_theta_upper") {
      p=std::strtok(NULL, " =,/");
      upper_theta_upper=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="upper_theta_lower") {
      p=std::strtok(NULL, " =,/");
      upper_theta_lower=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="lower_theta_upper") {
      p=std::strtok(NULL, " =,/");
      lower_theta_upper=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="lower_theta_lower") {
      p=std::strtok(NULL, " =,/");
      lower_theta_lower=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="upper_detector_y_upper") {
      p=std::strtok(NULL, " =,/");
      upper_detector_y_upper=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upper_detector_y_lower") {
      p=std::strtok(NULL, " =,/");
      upper_detector_y_lower=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="lower_detector_y_upper") {
      p=std::strtok(NULL, " =,/");
      lower_detector_y_upper=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="lower_detector_y_lower") {
      p=std::strtok(NULL, " =,/");
      lower_detector_y_lower=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="phi560") {
      p=std::strtok(NULL, " =,/");
      phi560=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upperDetectorWindowLower") {
      p=std::strtok(NULL, " =,/");
      upperDetectorWindowLower=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upperDetectorWindowUpper") {
      p=std::strtok(NULL, " =,/");
      upperDetectorWindowUpper=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="lowerDetectorWindowLower") {
      p=std::strtok(NULL, " =,/");
      lowerDetectorWindowLower=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="upperDetectorWindowUpper") {
      p=std::strtok(NULL, " =,/");
      lowerDetectorWindowUpper=atof(p.c_str())*MLF_MM2M;
    }
  }


  // set default value for variables of each PSD
  numUnit=7;
  numPsdPerUnit=8;

  upperDetInfo = new struct detectorInfo*[numUnit];
  for (UInt4 i=0; i<numUnit; i++) {
    upperDetInfo[i]=new struct detectorInfo[numPsdPerUnit];
  }
  lowerDetInfo = new struct detectorInfo*[numUnit];
  for (UInt4 i=0; i<numUnit; i++) {
    lowerDetInfo[i]=new struct detectorInfo[numPsdPerUnit];
  }

  Double psdTheta; // theta of the psd point in the ZX plane in the NeXus-coordinate system.
  for (UInt4 i=0; i<numUnit; i++) {
    for (UInt4 j=0; j<numPsdPerUnit; j++) {
      upperDetInfo[i][j].phi560=phi560;
      psdTheta=theta0-wTheta*(numPsdPerUnit*i+j);
      upperDetInfo[i][j].theta=psdTheta;
      psdPosZ=0.5*phi560*cos(psdTheta);
      psdPosX=0.5*phi560*sin(psdTheta);
      psdPosY=upper_detector_y_lower;
      upperDetInfo[i][j].Dtec1Pos.z=psdPosZ+psdRadius*sin(psdTheta);
      upperDetInfo[i][j].Dtec1Pos.x=psdPosX-psdRadius*cos(psdTheta);
      upperDetInfo[i][j].Dtec1Pos.y=psdPosY;
      upperDetInfo[i][j].Dtec2Pos.z=psdPosZ-psdRadius*sin(psdTheta);
      upperDetInfo[i][j].Dtec2Pos.x=psdPosX+psdRadius*cos(psdTheta);
      upperDetInfo[i][j].Dtec2Pos.y=psdPosY;
      upperDetInfo[i][j].wBin1=wBin;
      upperDetInfo[i][j].wBin2=wBin;
      upperDetInfo[i][j].offset1=offset;
      upperDetInfo[i][j].offset2=offset;
      upperDetInfo[i][j].status1=true;
      upperDetInfo[i][j].status2=true;

      lowerDetInfo[i][j].phi560=phi560;
      psdTheta=theta0-wTheta*(numPsdPerUnit*i+j);
      lowerDetInfo[i][j].theta=psdTheta;
      psdPosZ=0.5*phi560*cos(psdTheta);
      psdPosX=0.5*phi560*sin(psdTheta);
      psdPosY=lower_detector_y_lower;
      lowerDetInfo[i][j].Dtec1Pos.z=psdPosZ+psdRadius*sin(psdTheta);
      lowerDetInfo[i][j].Dtec1Pos.x=psdPosX-psdRadius*cos(psdTheta);
      lowerDetInfo[i][j].Dtec1Pos.y=psdPosY;
      lowerDetInfo[i][j].Dtec2Pos.z=psdPosZ-psdRadius*sin(psdTheta);
      lowerDetInfo[i][j].Dtec2Pos.x=psdPosX+psdRadius*cos(psdTheta);
      lowerDetInfo[i][j].Dtec2Pos.y=psdPosY;

      lowerDetInfo[i][j].wBin1=wBin;
      lowerDetInfo[i][j].wBin2=wBin;
      lowerDetInfo[i][j].offset1=offset;
      lowerDetInfo[i][j].offset2=offset;
      lowerDetInfo[i][j].status1=true;
      lowerDetInfo[i][j].status2=true;
    }
  }
  fo.clear();
  fo.seekg(0);

  // get line data in file and set the offset value to corresponding variable.
  //while (fo.getline(buffer, lengthBuffer)!=NULL) {
  while (fo.getline(buffer, lengthBuffer)) {
    // check line data. if line is blank, read next line.
    if (std::strlen(buffer)==0) {
      continue;
    }
    // analyze line-data and set the offset value to corresponding variable of SI unit.
    // MM2M ;; mili meter to meter
    // ANGSTROM2M : anstrom to meter
    // DEGREEE2RADIAN : degree to radian
    p=std::strtok(buffer, " =,");
    if (p=="d_L1") {
      p=std::strtok(NULL, " =,/");
      L1+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_phi625") {
      p=std::strtok(NULL, " =,/");
      phi625+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_w120") {
      p=std::strtok(NULL, " =,/");
      w120+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_w92") {
      p=std::strtok(NULL, " =,/");
      w92+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_upper_r2300") {
      p=std::strtok(NULL, " =,/");
      upper_r2300+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_lower_r2300") {
      p=std::strtok(NULL, " =,/");
      lower_r2300+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_upper_d_miller") {
      p=std::strtok(NULL, " =,/");
      upper_d_miller+=atof(p.c_str())*MLF_ANGSTROM2M;
    }
    else if (p=="d_lower_d_miller") {
      p=std::strtok(NULL, " =,/");
      lower_d_miller+=atof(p.c_str())*MLF_ANGSTROM2M;
    }
    else if (p=="d_upper_center_x") {
      p=std::strtok(NULL, " =,/");
      upper_center.x+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_upper_center_y") {
      p=std::strtok(NULL, " =,/");
      upper_center.y+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_upper_center_z") {
      p=std::strtok(NULL, " =,/");
      upper_center.z+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_lower_center_x") {
      p=std::strtok(NULL, " =,/");
      lower_center.x+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_lower_center_y") {
      p=std::strtok(NULL, " =,/");
      lower_center.y+=atof(p.c_str())*MLF_MM2M;
    }
    else if(p=="d_lower_center_z") {
      p=std::strtok(NULL, " =,/");
      lower_center.z+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_upper_theta_upper") {
      p=std::strtok(NULL, " =,/");
      upper_theta_upper+=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="d_upper_theta_lower") {
      p=std::strtok(NULL, " =,/");
      upper_theta_lower+=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="d_lower_theta_upper") {
      p=std::strtok(NULL, " =,/");
      lower_theta_upper+=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="d_lower_theta_lower") {
      p=std::strtok(NULL, " =,/");
      lower_theta_lower+=atof(p.c_str())*MLF_DEGREE2RADIAN;
    }
    else if (p=="d_upper_detector_y_upper") {
      p=std::strtok(NULL, " =,/");
      upper_detector_y_upper+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_upper_detector_y_lower") {
      p=std::strtok(NULL, " =,/");
      upper_detector_y_lower+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_lower_detector_y_upper") {
      p=std::strtok(NULL, " =,/");
      lower_detector_y_upper+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_lower_detector_y_lower") {
      p=std::strtok(NULL, " =,/");
      lower_detector_y_lower+=atof(p.c_str())*MLF_MM2M;
    }
    else if (p=="d_phi560") {
      p=std::strtok(NULL, " =,/");
      phi560+=atof(p.c_str())*MLF_MM2M;
    }
    else if (strncmp(p.c_str(), "d_upper_unit", 12)==0) {
      SetUpperDetInfo(p);
    }
    else if (strncmp(p.c_str(), "d_lower_unit", 12)==0) {
      SetLowerDetInfo(p);
    }
  }

// value check
/*
  std::printf("\n");
  std::printf("*** equip info ***\n");
  std::printf( " in unit of SI\n");
  std::printf("L1=%f\n",L1);
  std::printf("phi625=%f\n", phi625);
  std::printf("w120=%f\n", w120);
  std::printf("w92=%f\n", w92);

  std::printf("upper_2300=%f\n", upper_r2300);
  std::printf("upper_d_miller=%e\n", upper_d_miller);
  std::printf("upper_center :: %f %f %f\n", upper_center.x, upper_center.y, upper_center.z);
  std::printf("upper_theta_upper=%f\n", upper_theta_upper);
  std::printf("upper_theta_lower=%f\n", upper_theta_lower);

  std::printf("lower_2300=%f\n", lower_r2300);
  std::printf("lower_d_miller=%e\n", lower_d_miller);
  std::printf("lower_center :: %f %f %f\n", lower_center.x, lower_center.y, lower_center.z);
  std::printf("lower_theta_upper=%f\n", lower_theta_upper);
  std::printf("lower_theta_lower=%f\n", lower_theta_lower);

  std::printf("upper_detector_y_upper=%f\n", upper_detector_y_upper);
  std::printf("upper_detector_y_lower=%f\n", upper_detector_y_lower);
  std::printf("lower_detector_y_upper=%f\n", lower_detector_y_upper);
  std::printf("lower_detector_y_lower=%f\n", lower_detector_y_lower);


  std::printf("*** upper-detector info ***\n");
  for(int i=0; i<numUnit; i++){
    for(int j=0; j<numPsdPerUnit; j++){
      std::printf(" *** unit :: %d,  psd :: %d ***\n", i, j);
      std::printf("  position d1 = %f %f %f\n", upperDetInfo[i][j].Dtec1Pos.x,
                                             upperDetInfo[i][j].Dtec1Pos.y,
                                             upperDetInfo[i][j].Dtec1Pos.z);
      std::printf("  position d2 = %f %f %f\n", upperDetInfo[i][j].Dtec2Pos.x,
                                             upperDetInfo[i][j].Dtec2Pos.y,
                                             upperDetInfo[i][j].Dtec2Pos.z);
      std::printf("  phi560=%f, theta=%f\n", upperDetInfo[i][j].phi560, upperDetInfo[i][j].theta);
      std::printf("  wBin1=%f, wBin2=%f\n", upperDetInfo[i][j].wBin1, upperDetInfo[i][j].wBin2);
      std::printf("  offset1=%f, offset2=%f\n", upperDetInfo[i][j].offset1, upperDetInfo[i][j].offset2);
      std::printf("  status1=%d, status2=%d\n", upperDetInfo[i][j].status1, upperDetInfo[i][j].status2);
    }
  }

  std::printf("*** lower-detector info ***\n");
  for(int i=0; i<numUnit; i++){
    for(int j=0; j<numPsdPerUnit; j++){
      std::printf(" *** unit :: %d,  psd :: %d ***\n", i, j);
      std::printf("  position d1 = %f %f %f\n", lowerDetInfo[i][j].Dtec1Pos.x,
                                             lowerDetInfo[i][j].Dtec1Pos.y,
                                             lowerDetInfo[i][j].Dtec1Pos.z);
      std::printf("  position d2 = %f %f %f\n", lowerDetInfo[i][j].Dtec2Pos.x,
                                             lowerDetInfo[i][j].Dtec2Pos.y,
                                             lowerDetInfo[i][j].Dtec2Pos.z);
      std::printf("  phi560=%f, theta=%f\n", lowerDetInfo[i][j].phi560, lowerDetInfo[i][j].theta);
      std::printf("  wBin1=%f, wBin2=%f\n", lowerDetInfo[i][j].wBin1, lowerDetInfo[i][j].wBin2);
      std::printf("  offset1=%f, offset2=%f\n", lowerDetInfo[i][j].offset1, lowerDetInfo[i][j].offset2);
      std::printf("  status1=%d, status2=%d\n", lowerDetInfo[i][j].status1, lowerDetInfo[i][j].status2);
    }
  }
*/

  delete[] buffer;
  fo.close();
}

/**
 * Set data for the upper detector
 *
 * Set data for the upper detector of the j-th PSD in the i-th unit.
 * @param[in] i i-th unit
 * @param[in] j j-th PSD
 */
void AdvEquipmentManagerDNA:: SetUpperDetInfoPos(UInt4 i, UInt4 j){
  Double psdTheta=upperDetInfo[i][j].theta; // theta of the psd point in the ZX plane in the NeXus-coordinate system.
  psdPosZ=0.5*upperDetInfo[i][j].phi560*cos(psdTheta); //coordinate of the cetner of right ( or left ) part of PSD
  psdPosX=0.5*upperDetInfo[i][j].phi560*sin(psdTheta); //coordinate of the cetner of right ( or left ) part of PSD
  psdPosY=upper_detector_y_lower;                      //coordinate of the cetner of right ( or left ) part of PSD
  upperDetInfo[i][j].Dtec1Pos.z=psdPosZ+psdRadius*sin(psdTheta); //coordinate of the cetner of right part of U-shaped PSD
  upperDetInfo[i][j].Dtec1Pos.x=psdPosX-psdRadius*cos(psdTheta); //coordinate of the cetner of right part of U-shaped PSD
  upperDetInfo[i][j].Dtec1Pos.y=psdPosY;                         //coordinate of the cetner of right part of U-shaped PSD
  upperDetInfo[i][j].Dtec2Pos.z=psdPosZ-psdRadius*sin(psdTheta); //coordinate of the cetner of left part of U-shaped PSD
  upperDetInfo[i][j].Dtec2Pos.x=psdPosX+psdRadius*cos(psdTheta); //coordinate of the cetner of left part of U-shaped PSD
  upperDetInfo[i][j].Dtec2Pos.y=psdPosY;                         //coordinate of the cetner of left part of U-shaped PSD
}

/**
 * Set data for the lower detector
 *
 * Set data for the lower detector of the j-th PSD in the i-th unit.
 * @param[in] i i-th unit
 * @param[in] j j-th PSD
 */
void AdvEquipmentManagerDNA:: SetLowerDetInfoPos(UInt4 i, UInt4 j){
  Double psdTheta=lowerDetInfo[i][j].theta; // theta of the psd point in the ZX plane in the NeXus-coordinate system.
  psdPosZ=0.5*lowerDetInfo[i][j].phi560*cos(psdTheta); // coordinate of the cetner of right ( or left ) part of PSD
  psdPosX=0.5*lowerDetInfo[i][j].phi560*sin(psdTheta); // coordinate of the cetner of right ( or left ) part of PSD
  psdPosY=lower_detector_y_lower;                      // coordinate of the cetner of right ( or left ) part of PSD
  lowerDetInfo[i][j].Dtec1Pos.z=psdPosZ+psdRadius*sin(psdTheta); //coordinate of the cetner of right part of U-shaped PSD
  lowerDetInfo[i][j].Dtec1Pos.x=psdPosX-psdRadius*cos(psdTheta); //coordinate of the cetner of right part of U-shaped PSD
  lowerDetInfo[i][j].Dtec1Pos.y=psdPosY;                         //coordinate of the cetner of right part of U-shaped PSD
  lowerDetInfo[i][j].Dtec2Pos.z=psdPosZ-psdRadius*sin(psdTheta); //coordinate of the cetner of left part of U-shaped PSD
  lowerDetInfo[i][j].Dtec2Pos.x=psdPosX+psdRadius*cos(psdTheta); //coordinate of the cetner of left part of U-shaped PSD
  lowerDetInfo[i][j].Dtec2Pos.y=psdPosY;                         //coordinate of the cetner of left part of U-shaped PSD
}


/**
 * Set the upper detector information.
 *
 * Set the upper detector information for each PSD.
 * If phi560(, or theta, or offset, or status)  is changed, the value of variables dependent on phi560 should be also modified.
 * @param[in] p parameter for detector
 */
void AdvEquipmentManagerDNA:: SetUpperDetInfo(std::string p){
  UInt4 unitNum, psdNum;
  if (p.find("phi560")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_upper_unit%d_psd%d_phi560", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    upperDetInfo[unitNum][psdNum].phi560+=atof(p.c_str())*MLF_MM2M;
    SetUpperDetInfoPos(unitNum, psdNum);
  }
  if (p.find("theta")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_upper_unit%d_psd%d_theta", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    upperDetInfo[unitNum][psdNum].theta+=atof(p.c_str())*MLF_DEGREE2RADIAN;
    SetUpperDetInfoPos(unitNum, psdNum);
  }
  if (p.find("offset")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_upper_unit%d_psd%d_offset", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    upperDetInfo[unitNum][psdNum].offset1+=atof(p.c_str())*MLF_MM2M;
    upperDetInfo[unitNum][psdNum].offset2+=atof(p.c_str())*MLF_MM2M;
  }
  if (p.find("status")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_upper_unit%d_psd%d_statust", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    if (p.find("false")!=std::string::npos) {
      upperDetInfo[unitNum][psdNum].status1=false;
      upperDetInfo[unitNum][psdNum].status2=false;
    }
    else {
      std::printf("wrong keyword :: %s\n", p.c_str());
    }
  }

}

/**
 * Set the lower detector information.
 *
 * Set the lower detector information for each PSD.
 * If phi560(, or theta, or offset, or status)  is changed, the value of variables dependent on phi560 should be also modified.
 * @param[in] p parameter for detector
 */
void AdvEquipmentManagerDNA:: SetLowerDetInfo(std::string p){
  UInt4 unitNum, psdNum;
  if (p.find("phi560")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_lower_unit%d_psd%d_phi560", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    lowerDetInfo[unitNum][psdNum].phi560+=atof(p.c_str())*MLF_MM2M;
    SetLowerDetInfoPos(unitNum, psdNum);
  }
  if (p.find("theta")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_lower_unit%d_psd%d_theta", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    lowerDetInfo[unitNum][psdNum].theta+=atof(p.c_str())*MLF_DEGREE2RADIAN;
    SetLowerDetInfoPos(unitNum, psdNum);
  }
  if (p.find("offset")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_lower_unit%d_psd%d_offset", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    lowerDetInfo[unitNum][psdNum].offset1+=atof(p.c_str())*MLF_MM2M;
    lowerDetInfo[unitNum][psdNum].offset2+=atof(p.c_str())*MLF_MM2M;
  }
  if (p.find("status")!=std::string::npos) {
    std::sscanf(p.c_str(), "d_lower_unit%d_psd%d_status", &unitNum, &psdNum);
    unitNum-=1;
    psdNum-=1;
    p=std::strtok(NULL, " =,/");
    if (p.find("false")!=std::string::npos) {
      lowerDetInfo[unitNum][psdNum].status1=false;
      lowerDetInfo[unitNum][psdNum].status2=false;
    }
    else {
      std::printf("wrong keyword :: %s\n", p.c_str());
    }
  }
}

/**
 * get the value of center position of the sphere of the upper analyzer mirror
 *
 * @param[out] r value of center position of the sphere of the upper analyzer mirror
 */
Int4 AdvEquipmentManagerDNA:: GetCenterPosUpperMirror(struct coordinate *r){
  r->x=upper_center.x;
  r->y=upper_center.y;
  r->z=upper_center.z;
  return 0;
};

/**
 * get the value of center position of the sphere of the lower analyzer mirror
 *
 * @param[out] r value of center position of the sphere of the lower analyzer mirror
 */
Int4 AdvEquipmentManagerDNA:: GetCenterPosLowerMirror(struct coordinate *r){
  r->x=lower_center.x;
  r->y=lower_center.y;
  r->z=lower_center.z;
  return 0;
};


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

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

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

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

/**
 * generate neutron scattered by sample, reflected by analyzer and  detected by detector.
 *
 * - generate neutron scattered by sample, reflected by analyzer and  detected by detector.
 * - calculate TOF and the efficiency of detector at each detection point.
 *
 * @param[in]  measType 0: calculation of delt TOF data. 1: calculation of delta Einc data.
 * @param[in]  nBrag  Brag reflection rule; 2d sin(theta) = nBrag lambda
 * @param[in]  startValue starting value of TOF (in the case of measType=0) or Einc (in the case of measType=1).
 * @param[in]  endValue   ending value of TOF (in the case of measType=0) or Einc (in the case of measType=1).
 * @param[in]  intervalValue interval value of TOF (in the case of measType=0) or Einc (in the case of measType=1).
 * @param[in]  scaPos position of scattering point
 */

/*
void AdvEquipmentManagerDNA:: GenerateNeutron(UInt4 measType, UInt4 nBrag, Double startValue,
                                          Double endValue, Double intervalValue,
                                          struct coordinate scaPos){

*/
void AdvEquipmentManagerDNA:: GenerateNeutron(UInt4 measType, UInt4 nBrag, Double startValue,
                                          Double endValue, Double intervalValue,
                                          Double scaPosX, Double scaPosY, Double scaPosZ){

// time
  clock_t start, end;
  start=clock();

// Unit translation
  switch (measType) {
    case 0:
      startValue*=MLF_MICROSEC2SEC;
      endValue*=MLF_MICROSEC2SEC;
      intervalValue*=MLF_MICROSEC2SEC;
      break;
    case 1:
      startValue*=MLF_MEV2J;
      endValue*=MLF_MEV2J;
      intervalValue*=MLF_MEV2J;
      break;
    default :
      std::printf("something wrong for input value measType\n");
      exit(1);
  }

  struct coordinate scaPos;
  scaPos.x=scaPosX;
  scaPos.y=scaPosY;
  scaPos.z=scaPosZ;

//  UInt4 unitNum, psdNum, position;
  UInt4 i, j, k;
  struct neutronInfo neutron;

  // detection point
  Double detPosX;
  Double detPosY;
  Double detPosZ;

//  ScatAbsoDetector detector;
//  detector.SetIntegThresholdValue(epsilon);
//  detector.SetIntegThresholdRatio(epsilonRatio);

  Double length=upper_detector_y_upper-upper_detector_y_lower; // suppose length of upper detector is equal to that of lower detector
  Double bin; //bin of detector. Suppose bin of each detector is equal.
  UInt4 i2;
  // loop for each detection point
  for (j=0; j<numUnit; j++) { // j-th unit
    for (k=0; k<numPsdPerUnit; k++) { // k-th PSD
      //length=upper_detector_y_upper-upper_detector_y_lower;
      bin=upperDetInfo[j][k].wBin1;
      //std::printf("** length=%f, bin=%f\n", length, bin);
      for (i=0; i<length/bin; i++) { // detection point loop for j-th PSD in i-th unit
       for (i2=0; i2<4; i2++) { // i2=9 : upper right, i2=1 : upper left, i2=2 : lower right , i2=3 : lower left
        switch(i2){
          case 0:
            detPosX=upperDetInfo[j][k].Dtec1Pos.x;
            detPosY=upperDetInfo[j][k].Dtec1Pos.y+upperDetInfo[j][k].offset1+i*bin;
            detPosZ=upperDetInfo[j][k].Dtec1Pos.z;
            break;
          case 1:
            detPosX=upperDetInfo[j][k].Dtec2Pos.x;
            detPosY=upperDetInfo[j][k].Dtec2Pos.y+upperDetInfo[j][k].offset2+i*bin;
            detPosZ=upperDetInfo[j][k].Dtec2Pos.z;
            break;
          case 2:
            detPosX=lowerDetInfo[j][k].Dtec1Pos.x;
            detPosY=lowerDetInfo[j][k].Dtec1Pos.y+lowerDetInfo[j][k].offset1+i*bin;
            detPosZ=lowerDetInfo[j][k].Dtec1Pos.z;
            break;
          case 3:
            detPosX=lowerDetInfo[j][k].Dtec2Pos.x;
            detPosY=lowerDetInfo[j][k].Dtec2Pos.y+lowerDetInfo[j][k].offset2+i*bin;
            detPosZ=lowerDetInfo[j][k].Dtec2Pos.z;
            break;
          default:
            break;
        }
//        std::printf("\n");
        AdvNeutronManagerDNA *neutronManager = new AdvNeutronManagerDNA(this);
        neutronManager->PutScaPos(scaPos.x, scaPos.y, scaPos.z); // set scattering point of neutron
        neutronManager->PutDetPos(detPosX, detPosY, detPosZ); // set detection point of neutron
        //if(neutronManager->CalcFinEnergyThetaDetectorTofSD(nBrag)==0){ // in the case where neutron scattering path is valid
        if(neutronManager->SetNeutronData(nBrag)==0){ // in the case where neutron scattering path is valid
          if (measType==0) { // in the case of delta TOF
            neutronManager->CalcIncEnergies(startValue, endValue, intervalValue); // calculate corresponding Einc
          }
          else { // in the case of delta Einc
            neutronManager->CalcTof(startValue, endValue, intervalValue); // calculate corresponding TOF
          }
          neutronManager->GetNeutronInfo(&neutron); // get neutron information


          Double val=neutronManager->ReturnEfficiencyDetector(epsilon, epsilonRatio); // calculate efficiency of detector at detection point


          for (UInt4 j2=0; j2<neutron.incEnergy.size(); j2++) {
/*
            std::printf("%2d::diff_energy=%f, tof_sd=%e, tof_ss=%e, tof=%e, efficiency=%f\n", j2,
                   (neutron.incEnergy[j2]-neutron.finEnergy)*MLF_J2MEV,
                   neutron.tofSD*SEC2MICROSEC, neutron.tofSS[j2]*SEC2MICROSEC, neutron.tof[j2]*SEC2MICROSEC, val);
*/
          }
        }
        delete neutronManager;
       }
      }
    }
  }
  end=clock();
  std::printf("%e second need for calculation\n", (double) (end-start)/CLOCKS_PER_SEC);
}

/*
PyObject*  AdvEquipmentManagerDNA:: GetThetaEnergyFromPython(UInt4 nBrag, Double scaPosX, Double scaPosY, Double scaPosZ,
                                                       Double detPosX, Double detPosY, Double detPosZ){
  thetaEnergy=GetThetaEnergy(nBrag, scaPosX, scaPosY, scaPosZ, detPosX, detPosY, detPosZ);
  PyObject *thetaEnergyList=__gCppToPython.VectorDoubleToList(thetaEnergy);
  return thetaEnergyList;
}
*/

/*
std::vector <Double>  AdvEquipmentManagerDNA:: GetThetaEnergy(UInt4 nBrag, Double scaPosX, Double scaPosY, Double scaPosZ,
                                                   Double detPosX, Double detPosY, Double detPosZ){
  std::vector <Double> thetaEnergy;

  neutronManager->PutScaPos(scaPos.x, scaPos.y, scaPos.z); // set scattering point of neutron
  neutronManager->PutDetPos(detPosX, detPosY, detPosZ); // set detection point of neutron
  if(neutronManager->SetNeutronData(nBrag)==0){ // in the case where neutron scattering path is valid
    neutronManager->GetNeutronInfo(&neutron);
    thetaEnergy.push_back(neutron.thetaDetector*MLF_RADIAN2DEGREE);
    thetaEnergy.push_back(neutron.
*/

PyObject* AdvEquipmentManagerDNA:: GetThetaEnergy(){

  Double startValue=10.0*MLF_MEV2J;
  Double endValue=startValue;
  Double intervalValue=startValue;

  struct coordinate scaPos;
  scaPos.x=0.0;
  scaPos.y=0.0;
  scaPos.z=0.0;

//  UInt4 unitNum, psdNum, position;
  UInt4 i, j, k;
  struct neutronInfo neutron;

  // detection point
  Double detPosX;
  Double detPosY;
  Double detPosZ;

  int nBrag=1;

//  ScatAbsoDetector detector;
//  detector.SetIntegThresholdValue(epsilon);
//  detector.SetIntegThresholdRatio(epsilonRatio);

  Double length=upper_detector_y_upper-upper_detector_y_lower; // suppose length of upper detector is equal to that of lower detector
  Double bin; //bin of detector. Suppose bin of each detector is equal.
  UInt4 i2;

  std::vector <Double> thetaEnergy;
  // loop for each detection point
  for (j=0; j<numUnit; j++) { // j-th unit
    for (k=0; k<numPsdPerUnit; k++) { // k-th PSD
      //length=upper_detector_y_upper-upper_detector_y_lower;
      bin=upperDetInfo[j][k].wBin1;
      //std::printf("** length=%f, bin=%f\n", length, bin);
      for (i=0; i<length/bin; i++) { // detection point loop for j-th PSD in i-th unit
       for (i2=0; i2<4; i2++) { // i2=9 : upper right, i2=1 : upper left, i2=2 : lower right , i2=3 : lower left
        switch(i2){
          case 0:
            detPosX=upperDetInfo[j][k].Dtec1Pos.x;
            detPosY=upperDetInfo[j][k].Dtec1Pos.y+upperDetInfo[j][k].offset1+i*bin;
            detPosZ=upperDetInfo[j][k].Dtec1Pos.z;
            break;
          case 1:
            detPosX=upperDetInfo[j][k].Dtec2Pos.x;
            detPosY=upperDetInfo[j][k].Dtec2Pos.y+upperDetInfo[j][k].offset2+i*bin;
            detPosZ=upperDetInfo[j][k].Dtec2Pos.z;
            break;
          case 2:
            detPosX=lowerDetInfo[j][k].Dtec1Pos.x;
            detPosY=lowerDetInfo[j][k].Dtec1Pos.y+lowerDetInfo[j][k].offset1+i*bin;
            detPosZ=lowerDetInfo[j][k].Dtec1Pos.z;
            break;
          case 3:
            detPosX=lowerDetInfo[j][k].Dtec2Pos.x;
            detPosY=lowerDetInfo[j][k].Dtec2Pos.y+lowerDetInfo[j][k].offset2+i*bin;
            detPosZ=lowerDetInfo[j][k].Dtec2Pos.z;
            break;
          default:
            break;
        }
//        std::printf("\n");
        AdvNeutronManagerDNA *neutronManager = new AdvNeutronManagerDNA(this);
        neutronManager->PutScaPos(scaPos.x, scaPos.y, scaPos.z); // set scattering point of neutron
        neutronManager->PutDetPos(detPosX, detPosY, detPosZ); // set detection point of neutron
        //if(neutronManager->CalcFinEnergyThetaDetectorTofSD(nBrag)==0){ // in the case where neutron scattering path is valid

        neutronManager->SetNeutronData(nBrag);
        neutronManager->GetNeutronInfo(&neutron); // get neutron information

        thetaEnergy.push_back(neutron.thetaDetector*MLF_RADIAN2DEGREE);
        thetaEnergy.push_back(neutron.finEnergy*MLF_J2MEV);

       }
      }
    }
  }
  //std::printf("%e second need for calculation\n", (double) (end-start)/CLOCKS_PER_SEC);

  PyObject *returnThetaEnergy=__gCppToPython.VectorDoubleToList(thetaEnergy);

  return returnThetaEnergy;
}






