#ifndef NEUTRONMANAGER
#define NEUTRONMANAGER

#include <vector>

#include "AdvEquipmentManagerDNA.hh"
#include "Header.hh"

//using namespace std;

/**
* struct neutron_info stock each neutron data. Stocked data is as follows. SI unit is employed.
*
* @param incEnergy energies of considered incident neutrons
* @param finEnergy energy of detected neutron
* @param finLambda wave length of detected neutron
* @param qincX x-component of wave vector of incident neutron
* @param qincY y-component of wave vector of incident neutron
* @param qincZ z-component of wave vector of incident neutron
* @param qoutX x-component of wave vector of scattered neutron
* @param qoutY y-component of wave vector of scattered neutron
* @param qoutZ z-component of wave vector of scattered neutron
* @param qfinX x-component of wave vector of detected neutron
* @param qfinY y-component of wave vector of detected neutron
* @param qfinZ z-component of wave vector of detected neutron
* @param detPosX x-coordinate of detected position
* @param detPosY y-coordinate of detected position
* @param detPosZ z-coordinate of detected position
* @param scaPosX x-coordinate of scattering position
* @param scaPosY y-coordinate of scattering position
* @param scaPosZ z-coordinate of scattering position
* @param tofSS TOF from source to sample
* @param tofSD TOF from sample to detector
* @param tof   TOF from source to detector
* @param thetaBrag angle of incidence of scatterd neutron at analyzer
* @param thetaDetector angle of incidence of detected neutron at detector
* @param judge 0: prohibited neutron due to physical shape of equipment, 1: valid neutron
*
* @author Koike Soh, AdvanceSoft Corp.
* @version 0.0
* @sice    0.0
*/
struct neutronInfo{
  // SI unit
  std::vector <Double> incEnergy; /**< energies of considered incident neutrons */
  Double finEnergy;          /**< energy of detected neutron */
  Double finLambda;          /**< wave length of detected neutron */

  std::vector <Double> qincX;     /**< x-component of wave vector of incident neutron */
  std::vector <Double> qincY;     /**< y-component of wave vector of incident neutron */
  std::vector <Double> qincZ;     /**< z-component of wave vector of incident neutron */

  Double qoutX;              /**< x-component of wave vector of scattered neutron */
  Double qoutY;              /**< y-component of wave vector of scattered neutron */
  Double qoutZ;              /**< z-component of wave vector of scattered neutron */

  Double qfinX;              /**< x-component of wave vector of detected neutron */
  Double qfinY;              /**< y-component of wave vector of detected neutron */
  Double qfinZ;              /**< z-component of wave vector of detected neutron */

  Double detPosX;            /**< x-coordinate of detected position */
  Double detPosY;            /**< y-coordinate of detected position */
  Double detPosZ;            /**< z-coordinate of detected position */

  Double scaPosX;            /**< x-coordinate of scattering position */
  Double scaPosY;            /**< y-coordinate of scattering position */
  Double scaPosZ;            /**< z-coordinate of scattering position */

  std::vector <Double> tofSS;     /**< TOF from source to sample */
  Double tofSD;              /**< TOF from sample to detector */
  std::vector <Double> tof;       /**< TOF from source to detector */

  Double thetaBrag;          /**< angle of incidence of scatterd neutron at analyzer */
  Double thetaDetector;      /**< angle of incidence of detected neutron at detector */
  int judge;                 /**< 0: prohibited neutron due to physical shape of equipment, 1: valid neutron */
};

/**
* Class AdvNeutronManagerDNA
* This class manages each neutron information scattered at sample.
*
* @author Koike Soh, AdvanceSoft Corp.
* @version 0.0
* @since   0.0
*/
class AdvNeutronManagerDNA{

  private:
    /** max_iter_theta :: max iteration number to perform by Newton method for f(theta) */
    static const UInt4 MAX_ITER_THETA;  // =  10;
    /** max_iter_phi   :: max iteration number to perform by Newton method for f(phi)   */
    static const UInt4 MAX_ITER_PHI;    // =  10;
    /** max_iter_Newton:: max iteration number to perform by Newton method for f(theta, phi) */
    static const UInt4 MAX_ITER_NEWTON; // = 100;

    /** threshold_Newton :: threshold value for judgement of convergence in the Newton method */
    static const Double THRESHOLD_NEWTON; // =1.0e-06;
    /** threshold_judge :: threshold value for judgement whether obtained wave vector q is valid or not. */
    static const Double THRESHOLD_JUDGE; // =1.0e-08;

    static const Double THRESHOLD_ZERO; // =1.0e-08;

    /** d_phi_default :: delta phi which is used for the numerical differential calculus */
    static const Double D_PHI_DEFAULT; // =0.0001;
    /** d_theta_default :: delta theta which is used for the numerical differential calculus */
    static const Double D_THETA_DEFAULT; // =0.0001;

  private:
    class AdvEquipmentManagerDNA *equipmentManager; /**< instance of EquipmentManager class */
    Double L1;                                /**< Length between moderator and sample */
    Double radiusUpperAnal; /**< radius of the upper analyzer mirror */
    Double radiusLowerAnal; /**< radius of the lower analyzer mirror */
    struct coordinate detPos; /**< position of detected  point */
     struct coordinate scaPos; /**< position of scattered point */
    struct coordinate centerPosUpperAnal; /**< center position of the sphere of the upper analyzer mirror */
    struct coordinate centerPosLowerAnal; /**< cneter position of the sphere of the lower analyzer mirror*/
    Double UppLtcSpc; /**< distance between atomic surface of the upper analyzer mirror */
    Double LowLtcSpc; /**< distance between atomic surface of the lower analyzer mirror */

    struct neutronInfo neutron; /** struct variable which stock the various data of neutron */

    Int4 DetPhiRefPos(struct coordinate, struct coordinate, struct coordinate, struct coordinate, Double, Double, Double*);
    Int4 DetThetaRefPos(struct coordinate, struct coordinate, struct coordinate, struct coordinate, Double, Double*, Double);
    Double ReturnDistancePoints(struct coordinate, struct coordinate);
    Double ObtainLamda(Int4, Double, Double);
//    Double CalcEfficiency(void);

  public:
    AdvNeutronManagerDNA(void);
    AdvNeutronManagerDNA(class AdvEquipmentManagerDNA*);
    ~AdvNeutronManagerDNA(void);

//    Int4 CalcFinEnergyThetaDetectorTofSD(Int4);
    Int4 SetNeutronData(Int4);
    Int4 GetNeutronInfo(struct neutronInfo*);
    Int4 PutDetPos(Double, Double, Double);
    Int4 PutScaPos(Double, Double, Double);
    Int4 CalcIncEnergies(Double, Double, Double);
    Int4 CalcTof(Double, Double, Double);
    Double ReturnEfficiencyDetector(Double, Double);

};

#endif
