#ifndef UTSUSEMINEUNETEVENTDECORDERDNA
#define UTSUSEMINEUNETEVENTDECORDERDNA
#include "UtsusemiNeunetEventDecoderBase.hh"
#include "BoostXmlParser.hh"
#include "StringTools.hh"
//#include <fstream>
//#include <numeric>
//#include <vector>
//#include <iostream>
#include <cmath>
#include <algorithm>

///////////////////////////////////////////
//  UtsusemiNeunetEventDecoderDNA
///////////////////////////////////////////

//! Decode Event Data of NEUNET for Utsusemi of DNA
/*!
 *

 */

class UtsusemiNeunetEventDecoderDNA:
    public UtsusemiNeunetEventDecoderBase
{
private:
    UInt4 _tof_pat_id;
    // <tofBinInfo> patternId, described in WiringInfo

    //put binning calculated by Efix in DNA
    std::vector<Double> GetArithmeticSequenceVect(Double start, Double end, Double delta);

    //put binning calculated by Efix in DNA
    std::vector<Double> GetUserDefinedVect();

    // get arithmetic sequence
    Double GetPixelSize();
    // get pixel size by using UtsusemiNeunetEventDecoderBase:PutPixelPosition
    std::vector<Double> GetPixelPosition(Double outerPixelId,Double offset,Double pixelSize);
    // return Arithmetic Sequence between "start" and "end". common difference is "delta"
    Double PutDeltaIncidentAngleAtMirrorDNA(std::vector<Double> posVect,std::vector<Double> sposHvect, std::vector<Double> sposLvect);
    // put neutron incident angle for analyzer mirror in DNA
    void CalcPhiAnalyzer(std::vector<Double> posVect,Double LaticeSpace,Double &L2,Double &L3,Double &Ef,Double &polarAngle,Double &thetaDetector,Double &azimAngle,std::vector<Double> &scatPos);
    // execute of neutron transport analysis. results are L2,L3,Ef,polar angle,theta detector,azimuthal angle,scattring position
    Double PutPsdPixelSolidAngleDNA(Double pos1,std::vector<Double> sposHvect, std::vector<Double> sposLvect);
    // solid angle calculation

    std::vector<Double> _CalcPhiAnalyzer(std::vector<Double> posVect,Double LaticeSpace);
    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 _ObtainLambda(Int4, Double, Double);
    struct _coordinate _SphericalCoordinate(Double yposition, Double radius_up, Double radius_down, Double theta, Double phi, struct _coordinate r2, struct _coordinate r3);

    //static const Double MASS_NEUTRON    = 1.674928e-27; // in unit of [kg]
    //static const Double HBAR            = 1.054571596e-34; // in unit of [J][s]
    static const Double MASS_NEUTRON; // in unit of [kg]
    static const Double HBAR;         // in unit of [J][s]
    // max_iter_theta :: max iteration number to perform by Newton method for f(theta)
    static const UInt4 MAX_ITER_THETA   = 20;
    // max_iter_phi   :: max iteration number to perform by Newton method for f(phi)
    static const UInt4 MAX_ITER_PHI     = 20;
    // max_iter_Newton:: max iteration number to perform by Newton method for f(theta, phi)
    static const UInt4 MAX_ITER_NEWTON  = 200;
    // threshold_Newton :: threshold value for judgement of convergence in the Newton method
    // static const Double THRESHOLD_NEWTON = 1.0e-08;
    static const Double THRESHOLD_NEWTON;
    // threshold_judge :: threshold value for judgement whether obtained wave std::vector q is valid or not.
    //static const Double THRESHOLD_JUDGE = 1.0e-08;
    static const Double THRESHOLD_JUDGE;
    // threshold_zero :: threshold value for judgement
    //static const Double THRESHOLD_ZERO  = 1.0e-08;
    static const Double THRESHOLD_ZERO;
    // d_phi_default :: delta phi which is used for the numerical differential calculus
    //static const Double D_PHI_DEFAULT   = 0.0001;
    static const Double D_PHI_DEFAULT;
    // d_theta_default :: delta theta which is used for the numerical differential calculus
    //static const Double D_THETA_DEFAULT = 0.0001;
    static const Double D_THETA_DEFAULT;

    std::vector< Double > _pixelTofMax;                 /**< pixel tof Max              ( index : outer pixel id ) */
    std::vector< Double > _pixelTofMin;                 /**< pixel tof Min              ( index : outer pixel id ) */
    std::vector< UInt4 > _pixelNumOfFrame;

    BoostXmlParser *_parserDetInfo;                  /**< XML parser  */
    BoostXmlParser *_parserWirInfo;                  /**< XML parser  */
    BoostXmlParser *_parserChopInfo;                 /**< XML parser  */

    StringTools* _st;

    Double GetParamFromXmlFile(std::string basepath,std::string tag,BoostXmlParser *parser);

    Double radiusUpperAnal;
    Double radiusLowerAnal;
    Double centerPosUpperAnalx;
    Double centerPosUpperAnaly;
    Double centerPosUpperAnalz;
    Double centerPosLowerAnalx;
    Double centerPosLowerAnaly;
    Double centerPosLowerAnalz;
    Double scaPosx;
    Double scaPosy;
    Double scaPosz;
    Double dthetaDetDeg;

    Double l1;
    Double lMonitor;
    Double lChopper;
    Double lbandChopper;

    bool useFastChopper;

protected:
    void Clear();
        //!< Clear some parameters
        /*!<
         *   @return None
         */
public:
    UtsusemiNeunetEventDecoderDNA();
        //!< Constructor
        /*!<
         */
    ~UtsusemiNeunetEventDecoderDNA();
        //!< Destructor
        /*!<
         */

    Int4 SetParametersFromFiles( std::string wiring_file, std::string detector_file );
        //!< set parameters from files
        /*!<
         *   @param wiring_file (std::string) Wiring Info xml file
         *   @param detector_file (std::string) DetectorInfo xml file
         *   @retval 0   no error
         *   @retval -1  Troubles happened
         */

    Int4 SetChopperParametersFromFiles( std::string chopper_file );

    std::vector<Double> PutHistBin( UInt4 outerPixelId );
        //!< put binning calculated by Efix
        /*!< For direct convertion from tof to phisical values,
         *   calculated binning(tof) is required to construct histograms.
         *
         *   @params outerPixelId (UInt4) pixel id
         *   @return binning std::vector
         */

    std::vector<Double> PutHistBinHW( UInt4 outerPixelId );

    std::vector<Double> PutXaxis();
        //!< put x axis values
        /*!< When TofBinType is for direct conversion from event data to energy,
         *   this returns calculated x-axis values.
         *
         *   @params None
         *   @return std::vector for values on calculated x-axis
         */

    UInt4 DecodeEventData( UInt4 daqId, UInt4 modNo, const UChar *data, UInt4 *pixel_id, double *tof, std::vector<Double>* Clock, UInt4 ThNum );
       //!< decode Event data
        /*!< This decodes any one event data and return type of event.
         *   If a given event is neutron, this sets pixel_id and tof and return 1 (_isNeutronEvent)
         *   If T0 event, this event is stored and return 2 (_isT0Event)
         *   If clock event, return 3
         *   If any other event, return 0
         *   @param daqId (UInt4) daq ID
         *   @param modNo (UInt4) module No
         *   @param data  (UChar) one event data
         *   @param pixel_id (UInt4) Pixel ID calculated by given event
         *   @param tof (double) TOF calculated by given event
         *   @param Clock (std::vector<Double>)
         *   @param ThNum (UInt4) Thread number
         *   @retval _isNeutronEvent if neutron event
         *   @retval _isT0Event if T0 event
         *   @retval _isClockEvent if clock event
         *   @retval 0 if any other event
         */

    //////////////////////////////////////////////////////////////////////////
    // public variables
    //////////////////////////////////////////////////////////////////////////

    std::string _wiring_file;
    std::string _detector_file;

    std::vector< Double > _pixelEfVect;                 /**< pixel Ef                   ( index : outer pixel id ) */
    std::vector< Double > _pixelL1Vect;                 /**< pixel L1                   ( index : outer pixel id ) */
    std::vector< Double > _pixelL2Vect;                 /**< pixel L2                   ( index : outer pixel id ) */
    std::vector< Double > _pixelL3Vect;                 /**< pixel L3                   ( index : outer pixel id ) */
    std::vector< Double > _pixelTOFOffsetFileVect;
    std::vector< Double > _pixelPolarAngleVect;         /**< pixel polar angle          ( index : outer pixel id ) */
    std::vector< Double > _pixelAzimAngleVect;          /**< pixel azimt angle          ( index : outer pixel id ) */
    std::vector< Double > _pixelThetaDetectorVect;      /**< pixel detector angle       ( index : outer pixel id ) */
    std::vector< Double > _pixelDThetaDetectorVect;     /**< pixel delta detector angle ( index : outer pixel id ) */
    std::vector< Double > _pixelDOmega;                 /**< pixel solid angle          ( index : outer pixel id ) */

    std::vector< Double > _pixelT0Detector;             /**< pixel t0Detector           ( index : outer pixel id ) */
};

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

#endif

