#ifndef UTSUSEMID4MATRIX2
#define UTSUSEMID4MATRIX2

#include "Header.hh"
#include "HeaderBase.hh"
#include "ElementContainer.hh"
#include "ElementContainerArray.hh"
#include "ElementContainerMatrix.hh"
#include "UtsusemiSqeCalc2.hh"
#include "UtsusemiCalcContainers.hh"
#include "WriteSerializationFile.hh"
#include "ReadSerializationFile.hh"
#include "StringTools.hh"
#include "UtsusemiHeader.hh"
#include "BoostXmlParser.hh"
#include "UtsusemiEventDataConverterNeunet.hh"
#include "UtsusemiEventDataMonitorNeunet.hh"
#include "UtsusemiReductionInEla.hh"
#include "UtsusemiSetMask.hh"
#include "UtsusemiUnitConverter.hh"
#include "UtsusemiSqeCalcXtalParams.hh"
#include "UtsusemiDetectorEfficiencyCorrection.hh"
#include "CppToPython.hh"
#include "Map.hh"
#include <omp.h>
#include <zlib.h>

#define UTSUSEMID4MATRIX2_CMP_COMFBUFSIZE 8
class D4MatOne
{
private:
    void _Initialize();
    void _Allocate( UInt4 bins_size=0);
    unsigned char* _compbuf1;
    unsigned long _compbuf1_size;
    bool _compress1(UInt4 bins_size);
    /* compress Energy, Intensity, Error, PolarAngle, ..., EFs into _compbuf1*/
    bool _uncompress1(UInt4 bins_size);
    /* uncompress _compbuf1 to Energy, Intensity, Error, PolarAngle, ..., EFs */
    //unsigned char* _compbuf2;
    //bool _compress2();
    //bool _uncompress2();

public:
    D4MatOne();
    D4MatOne(const D4MatOne &p);
    ~D4MatOne();
    HeaderBase* _HH;
    UInt4 NumOfPixels;
    std::vector<float>* Energy;
    std::vector<float>* Intensity;
    std::vector<float>* Error;
    std::vector<float>* Vx;
    std::vector<float>* Vy;
    std::vector<float>* Vz;
    std::vector<float>* Vw;
    std::vector<float>* PolarAngles;
    std::vector<float>* PolarAnglesW;
    std::vector<float>* AzimAngles;
    std::vector<float>* AzimAnglesW;
    std::vector<float>* L2;
    std::vector<float>* EFs;
    HeaderBase* PutHeaderPointer(){ return _HH; }
    static const std::string D4MAT2LABEL;
    static const std::string D4MAT2NUMOFPIXELS;
    static const std::string D4MAT2ANGLE;
    bool Save(std::string filepath);
    bool Save(std::ofstream &ofs);
    bool Savez(std::ofstream &ofs);
    bool Load(std::ifstream &ifs);
    bool DumpSqeAsText(std::string filepath);
    bool DumpSqeAsText(FILE* fp);
};
class D4MatGroup{
private:
    void _initialize();
public:
    D4MatGroup();
    D4MatGroup(HeaderBase *hh);
    ~D4MatGroup();
    HeaderBase* _HH;
    std::vector< D4MatOne* >* data;
    std::string _XtalParam;
    std::string _savedDate;
    HeaderBase* PutHeaderPointer(){ return _HH; }
    D4MatOne* PutPointer( UInt4 i ){ return data->at(i); }
    UInt4 PutSize(){ return (UInt4)(data->size()); }
    bool Save(std::string filepath, bool withComp=false);
    bool Load(std::string filepath);
    bool DumpSqeAsText(std::string filepath);
    static const UInt4 D4MAT2BINARYVERSION;
    static const std::string D4MAT2BINARYSIGNATURE;
    static const UInt4 D4MAT2BINARYSIGNATURESIZE;
    static const UInt4 D4MAT2BINARYDATESIZE;
};
class TreatD4Matrix2XmlParams{
private:
    void _initialize();
    BoostXmlParser* _BP;
public:
    TreatD4Matrix2XmlParams();
    TreatD4Matrix2XmlParams(std::string);
    ~TreatD4Matrix2XmlParams();
    UInt4 mode;
    std::vector< std::pair<UInt4,Double> > runNoAngleList;
    Double ei;
    Double energyBin;
    Double energyMin;
    Double energyMax;
    std::string maskFile;
    Double normFactor;
    std::string timeIndepBack;
    std::string detEffi;
    Double angleMin;
    Double angleMax;
    Double angleStep;
    Double timeSlice0;
    Double timeSlice1;
    Double anglePerEncode;
    std::string deviceEncode;
    Map<Double> deviceEncodeDic;
    UInt4 dio;
    Double SBS_gonioAtZero;
    Map<std::string> RunList;
    Map<std::string> dataReductions;
    void AddRunNo( UInt4 _runNo, Double _startAngle );
    void ClearRunNo(){ runNoAngleList.clear(); }
    bool ImportXmlString(std::string xmlstring, bool withDR=false);
    std::string PutXmlString();
    void Clear(bool onlyD4Mat2=true);
    Double PutDeviceEncode(std::string _devName){return deviceEncodeDic.Put(_devName) ;}
    UInt4 CheckDeviceEncodeName(std::string _devName){return deviceEncodeDic.Check(_devName);}
    static const std::string KEY_ROOT;
    static const std::string KEY_D4MAT2;
    static const std::string KEY_PARAMS;
    static const std::string KEY_MODE;
    static const std::string KEY_RUNNO;
    static const std::string KEY_EI;
    static const std::string KEY_EBIN;
    static const std::string KEY_EMIN;
    static const std::string KEY_EMAX;
    static const std::string KEY_MASK;
    static const std::string KEY_NORMFACT;
    static const std::string KEY_TIMEBACK;
    static const std::string KEY_DETEFFI;
    static const std::string KEY_ANGS;
    static const std::string KEY_ANGMIN;
    static const std::string KEY_ANGMAX;
    static const std::string KEY_ANGT;
    static const std::string KEY_TSLS;
    static const std::string KEY_DEVICEENCODE;
    static const std::string KEY_ANGPERENCODE;
    static const std::string KEY_DIO;
    static const std::string KEY_DRC;
    static const std::string KEY_DRC_F;
    static const std::string KEY_SBS_GONIO;
    static const std::string KEY_RUNLIST;
    static const std::string KEY_RUNLIST_NUM;
    static const std::string KEY_RUNLIST_RUN;
};
//////////////////////////////////
// UtsusemiD4mat2
/////////////////////////////////

//! D4Mat on memory
/*!
 *
 */

class UtsusemiD4Matrix2
{
private:

    void _Initialize();
    void _Clear();
    std::string MessageTag;
    Double MASKVALUE;
    D4MatGroup* _D4mat;
    HeaderBase* _HH;
    UInt4 _NumOfMulTh;
    StringTools * _stools;
    UtsusemiSqeCalcXtalParams* _XP;
    TreatD4Matrix2XmlParams* _TP;
    UtsusemiReductionInEla* _URI;
    bool _useAveOnSlice; /**< Culculate averaging intensity (default) or summation in _Slice3D and _Slice2D */
    float *****dArray4, *****eArray4, *****cArray4;
    UInt4 _n_XArray4, _n_YArray4, _n_ZArray4, _n_TArray4;
    std::vector<Double> _XbinArray4, _YbinArray4, _ZbinArray4, _TbinArray4;
    std::vector<Double> _viewAxis;

public:
    UtsusemiD4Matrix2();
        //!< Constructor
        /*!<
         *   @return None
         */
    ~UtsusemiD4Matrix2();
        //!< Destructor
        /*!<
         *   @return None
         */
    Int4 SetCrystalParametersToHeader( HeaderBase* head,std::vector<Double> LatticeConsts, std::vector<Double> Uvec, std::vector<Double> Vvec, std::vector<Double> Rvec );
        //!< Sets crystal parameters
        /*!< This sets crystal parameters to HeaderBase.
         *   @param head (HeaderBase*) target HeaderBase
         *   @param LatticeConsts (std::vector<Double>) Lattice constants <a, b, c, alpha, beta, gamma>
         *   @param Uvec (std::vector<Double>) U std::vector (ki parallel std::vector in coordinate system inside sample)
         *   @param Vvec (std::vector<Double>) V std::vector (ki perpendicular in coordinate system inside sample)
         *   @param Rvec (std::vector<Double>) Rotation Steps
         *   @retval 0   no trouble
         *   @retval -1  trouble happened.
         */
    bool SetCrystalParametersFromInnerHead( ElementContainerMatrix* ecm, Double phi=0.0 );
        //!< Sets crystal parameters from the crystal parameters stored in the header of given data container
        /*!<
         *   @param ecm (ElementContainerMatrix) Target data conatainer
         *   @param phi (Double) Rotation angle around Y-axis
         *   @retval true succeeded.
         *   @retval false failed.
         */
    Int4 SetD4MatParameters( Int4 runNo, std::vector<Double> dataRedParam,std::vector<Double> LatticeConsts, std::vector<Double> Uvec, std::vector<Double> Vvec, std::vector<Double> Rvec);
        //!< Sets D4Mat2 parameters into Header
        /*!< This sets D4Mat2 parameters to HeaderBase.
         *   @param runNo (Int4) runNo
         *   @param dataRedParam (std::vector<Double>) time_slice_start, time_slice_end, Ei, dHW, hw_min, hw_max, start_deg, end_deg, step_deg
         *   @param LatticeConsts (std::vector<Double>) Lattice constants <a, b, c, alpha, beta, gamma>
         *   @param Uvec (std::vector<Double>) U std::vector (ki parallel std::vector in coordinate system inside sample)
         *   @param Vvec (std::vector<Double>) V std::vector (ki perpendicular in coordinate system inside sample)
         *   @param Rvec (std::vector<Double>) Rotation Steps
         *   @retval 0   no trouble
         *   @retval -1  trouble happened.
         */
    bool SetD4MatParameters( Int4 runNo, PyObject* dataRedParam, PyObject* LatticeConsts, PyObject* Uvec, PyObject* Vvec, PyObject* Rvec);
        //!< Sets D4Mat2 parameters into Header
        /*!< This sets D4Mat2 parameters to HeaderBase.
         *   @param runNo (Int4) runNo
         *   @param dataRedParam (PyObject list) time_slice_start, time_slice_end, Ei, dHW, hw_min, hw_max, start_deg, end_deg, step_deg
         *   @param LatticeConsts (PyObject list) Lattice constants <a, b, c, alpha, beta, gamma>
         *   @param Uvec (PyObject list) U std::vector (ki parallel std::vector in coordinate system inside sample)
         *   @param Vvec (PyObject list) V std::vector (ki perpendicular in coordinate system inside sample)
         *   @param Rvec (PyObject list) Rotation Steps
         *   @retval 0   no trouble
         *   @retval -1  trouble happened.
         */
    bool SetD4MatMode(UInt4 mode);
        //!< Sets D4Mat2 measurement mode ( Step-by-step mode / Continuous rotation mode )
        /*!<
         *   @param mode (UInt4) 0:Continuous rotation mode / 1:Step-by-step mode
         *   @retval true succeeded.
         *   @retval false failed.
         */
    void SetD4MatContinousMode(){ SetD4MatMode(0); }
        //!< Sets D4Mat2 measurement mode ( Step-by-step mode / Continuous rotation mode )
        /*!<
         *   @param None
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatSampleInfo( std::vector<Double> LatticeConsts, std::vector<Double> Uvec, std::vector<Double> Vvec, std::vector<Double> Rvec);
        //!< Sets Sample information ( Lattice constants, U-vector, V-vector and rotations )
        /*!<
         *   @param None
         *   @param LatticeConsts (std::vector<Double>) Lattice constants <a, b, c, alpha, beta, gamma>
         *   @param Uvec (std::vector<Double>) U std::vector (ki parallel std::vector in coordinate system inside sample)
         *   @param Vvec (std::vector<Double>) V std::vector (ki perpendicular in coordinate system inside sample)
         *   @param Rvec (std::vector<Double>) Rotation Steps
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatSampleInfo( PyObject* LatticeConsts, PyObject* Uvec, PyObject* Vvec, PyObject* Rvec);
        //!< Sets Sample information ( Lattice constants, U-vector, V-vector and rotations )
        /*!<
         *   @param None
         *   @param LatticeConsts (PyObject list) Lattice constants <a, b, c, alpha, beta, gamma>
         *   @param Uvec (PyObject list) U std::vector (ki parallel std::vector in coordinate system inside sample)
         *   @param Vvec (PyObject list) V std::vector (ki perpendicular in coordinate system inside sample)
         *   @param Rvec (PyObject list) Rotation Steps
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatDataReductionInfo( std::vector<Double> dataRedParam );
        //!< Sets D4Mat2 data reduction information
        /*!<
         *   @param dataRedParam (std::vector<Double>) time_slice_start, time_slice_end, Ei, dHW, hw_min, hw_max, start_deg, end_deg, step_deg
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatDataReductionInfo( PyObject* dataRedParam );
        //!< Sets D4Mat2 data reduction base information
        /*!<
         *   @param dataRedParam (PyObject list) time_slice_start, time_slice_end, Ei, dHW, hw_min, hw_max, start_deg, end_deg, step_deg
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatDataReductionOptions(std::string maskInfo, Double normFactor,  std::string timeIndepBack="", std::string detEffi="", std::string script="");
        //!< Sets D4Mat2 data reduction option parameters
        /*!<
         *   @param maskInfo (std::string) Path to MaskInfo file to be used.
         *   @param normFactor (Double) The factor for the nomalization
         *   @param timeIndepBack (std::string) The parameter for the time-independed background corrections
         *   @param detEffi (std::string) Path to the parameter file used for the detector efficiency correction
         *   @param script (std::string) Path to the script file used for the data reduction users want to do
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatDataReductionContinuosAddRunNo(UInt4 runNo, Double startAngle);
        //!< Add run number and the start angle of the continuous rotation measurement to be used on its data reduction.
        /*!<
         *   @param runNo (UInt4) the run number of the measurement
         *   @param startAngle (Double) the start angle parameter for the measurement
         *   @retval true succeeded.
         *   @retval false failed.
         */
    void SetD4MatDataReductionContinuosClearRunNo();
        //!< Delete all run numbers and start angles of the continuous rotation measurement.
        /*!<
         *   @param None
         *   @retval None
         */
    bool SetD4MatDataReductionContinuosSetDeviceEncode(std::string device);
        //!< Set the device like "BL01-TL" of the continuous rotation measurement
        /*!<
         *   @param device (std::string) the name of the device "BL01-TL", "BL14-TL"
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatDataReductionContinuosSetAnglePerEncode(Double ape);
        //!< Set the parameter used to calculate the angle from the encoded value from the raw data of the continuous rotation measurement
        /*!<
         *   @param ape (Double) the conversion value from the counter value encoded from TrigNET event data to the angle.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatDataReductionContinuosSetTrigNETDIO(UInt4 dio=1);
        //!< Set the dio signal used to encode from TrigNET event data to the counter value for the continuous rotation measurement
        /*!<
         *   @param dio (UInt4) DIO number of TrigNET to encode to the counter value.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatDataReductionStepByStepGonioAtZero(Double gaz);
        //!< Set the parameter of the gonio-at-zero used to calculate the sample orientation for the step-by-step measurement
        /*!<
         *   @param gaz (Double) The gonio-at-zero value.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    void SetD4MatDataReductionStepByStepAddRunAngles(std::string runNos, double ang, double norm, double normFactor );
        //!< Add the measurement data information each angle for the step-by-step measurement
        /*!<
         *   @param runNos (std::string) Run numbers for an angle
         *   @param ang (Double) An angle
         *   @param norm (Double) The value for normalization (ex. the number of protons)
         *   @param normFactor (Double) The factor of the normalization correction
         *   @retval None
         */
    bool SetD4MatProjectionAxesInfo( std::vector<Double> PA );
        //!< Set the parameters for the projection
        /*!<
         *   @param PA (std::vector<Double>) The size of std::vector must be 16 |4x4|.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatProjectionAxesInfo( PyObject* PA );
        //!< Set the parameters for the projection
        /*!<
         *   @param PA (PyObject list) The size of list must be 16 |4x4|.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatProjectionAxesInfo( std::vector<Double> PA, std::vector<std::string> titles, std::vector<std::string> units );
        //!< Set the parameters for the projection with the titles and the units.
        /*!<
         *   @param PA (std::vector<Double>) The size of list must be 16 |4x4|.
         *   @param titles (std::vector<std::string>) [Ax1, Ax2, Ax3, Energy]
         *   @param units (std::vector<std::string>) units of Ax1, Ax2, Ax3 and Energy
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatProjectionAxesInfo( PyObject* PA, PyObject* titles, PyObject* units );
        //!< Set the parameters for the projection with the titles and the units.
        /*!<
         *   @param PA (PyObject list of float) The size of list must be 16 |4x4|.
         *   @param titles (PyObject list of std::string) [Ax1, Ax2, Ax3, Energy]
         *   @param units (PyObject list of std::string) units of Ax1, Ax2, Ax3 and Energy
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatSliceAxis(std::string _id, std::string _type, double _min, double _max, double _width, double _folding);
        //!< Set the parameters for the slicing
        /*!< These parameters are used directly for calling UtsusemiSqeCalcXtalParams::SetSliceAxis.
         *
         *   @param _id (std::string) The index of axis
         *   @param _type (std::string) Type of axis, "X", "Y", "Z" and "T"
         *   @param _min (Double) The minimum value of the slicing range
         *   @param _max (Double) The maximum value of the slicing range
         *   @param _width (Double) The width of bin
         *   @param _folding (Double) The folding value
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetD4MatRunNo( Int4 runNo );
        //!< Set the run number
        /*!<
         *   @param runNo (Int4) the run number
         *   @retval true succeeded.
         *   @retval false failed.
         */
    Int4 PutD4MatRunNo();
        //!< Puts RunNo from D4Mat2 parameters in Header
        /*!< This return run number from D4Mat2 parameters in HeaderBase.
         *   @param None
         *   @return runNo (Int4)
         */
    std::vector<Double> PutD4MatDataRedParams(bool fromData=false);
        //!< Puts Data Reduction Parameters from Header
        /*!< This return data reduction parameters of D4Mat2 from HeaderBase.
         *   @param fromDATA where is DR params obtained. True:From DATA False: from _HH
         *   @return std::vector<Double>
         */
    std::vector<Double> PutD4MatLatticeConsts();
        //!< Puts Lattice Constants parameters from Header
        /*!< This return lattice constants parameters of D4Mat2 from HeaderBase.
         *   @param None
         *   @return std::vector<Double>
         */
    std::vector<Double> PutD4MatUVvects();
        //!< Puts U-vector and V-vector parameters from Header
        /*!< This return U and V vectors of D4Mat2 from HeaderBase.
         *   @param None
         *   @return std::vector<Double>
         */
    Int4 ImportEcmsContRot( UtsusemiEventDataConverterNeunet* EDC,
                            const std::vector<UInt4> CaseId, const std::vector<Double> Phi, const std::vector<Double> Kickers,
                            const std::string maskfile, const Double dOmega,
                            const Double normFactor, const std::string detEffi, const UInt4 reductCase=15 );
        //!< Import data after data reduction into D4Matrix on the continuous rotation method.
        /*!<
         *   @param EDC (UtsusemiEventDataConverterNeunet) Instanse of UtsusemiEventDataConverterNeunet after loading event data with caseinfo.
         *   @param CaseId (std::vector<UInt4>) CaseID list used to pick a series of data at an angle
         *   @param Phi (std::vector<Double>) Angle list (the number of vector is same as that of CaseId)
         *   @param Kickers (std::vector<Double>) Kicker list used for normalization between data of angles
         *   @param maskfile (std::string) The path of maskinfo file
         *   @param dOmega (Double) The standard solid angle used for the solid angle correction
         *   @param normFactor (Double) The factor used to correct the normalization
         *   @param detEffi (std::string) The path to the data file used for the detector efficiency corrections
         *   @param reductCase (UInt4) The pattern of the data reduction proceedure
         *   @retval true succeeded.
         *   @retval false failed.
         */

    bool ImportEcmsContRot( UtsusemiEventDataConverterNeunet* EDC,
                            PyObject* CaseId, PyObject* Phi, PyObject* Kickers,
                            const std::string maskfile, const Double dOmega,
                            const Double normFactor, const std::string detEffi, const UInt4 reductCase=15 );
        //!< Import data after data reduction into D4Matrix on the continuous rotation method on the Python codes
        /*!<
         *   @param EDC (UtsusemiEventDataConverterNeunet) Instanse of UtsusemiEventDataConverterNeunet after loading event data with caseinfo.
         *   @param CaseId (PyObject int list) CaseID list used to pick a series of data at an angle
         *   @param Phi (PyObject float list) Angle list (the number of vector is same as that of CaseId)
         *   @param Kickers (PyObject float list) Kicker list used for normalization between data of angles.
         *   @param maskfile (std::string) The path of maskinfo file.
         *   @param dOmega (Double) The standard solid angle used for the solid angle correction.
         *   @param normFactor (Double) The factor used to correct the normalization
         *   @param detEffi (std::string) The path to the data file used for the detector efficiency corrections
         *   @param reductCase (UInt4) The pattern of the data reduction proceedure
         *   @retval true succeeded.
         *   @retval false failed.
         */
    Int4 ImportEcmsContRotPseudoOnLine( UtsusemiEventDataMonitorNeunet* EDC,
                                        const std::vector<UInt4> CaseId, const std::vector<Double> Phi,
                                        const std::string maskfile, const Double dOmega,
                                        const Double normFactor, const std::string detEffi,
                                        const bool isRefresh=false, const UInt4 reductCase=15 );
        //!< Import data after data reduction into D4Matrix on the continuous rotation method with on-line mode.
        /*!<
         *   @param EDC (UtsusemiEventDataMonitorNeunet) Instanse ofUtsusemiEventDataMonitorNeunet
         *   @param CaseId (std::vector<UInt4>) CaseID list used to pick a series of data at an angle
         *   @param Phi (std::vector<Double>) Angle list (the number of vector is same as that of CaseId)
         *   @param maskfile (std::string) The path of maskinfo file
         *   @param dOmega (Double) The standard solid angle used for the solid angle correction
         *   @param normFactor (Double) The factor used to correct the normalization
         *   @param detEffi (std::string) The path to the data file used for the detector efficiency corrections
         *   @param isRefresh (bool) The refresh mode of the on-line treatment.
         *   @param reductCase (UInt4) The pattern of the data reduction proceedure
         *   @retval 0 succeeded.
         *   @retval -1 failed.
         */
    bool ImportEcmContRot( ElementContainerMatrix* ecm, const UInt4 caseId, const double ang, const UInt4 reductCase=15 );
        //!< Import data after data reduction into D4Matrix on the continuous rotation method (now used in on-line mode only)
        /*!<
         *   @param ecm (ElementContainerMatrix) The data to be imported
         *   @param CaseId (UInt4) CaseID of the given data
         *   @param ang (double) The angle of the given data
         *   @param reductCase (UInt4) The pattern of the data reduction proceedure
         *   @retval true succeeded.
         *   @retval false failed.
         */
    UInt4 PutNumOfAngles(){return (UInt4)(_D4mat->data->size());}
        //!< Put the number of angles
        /*!<
         *   @param None
         *   @return the number of angles
         */
    bool ExportDataAsEcm(ElementContainerMatrix* ecm, UInt4 index);
        //!< Export the data of a single angle as ElementContainerMatrix from the imported data set.
        /*!<
         *   @param ecm (ElementContainerMatrix) The data to be imported
         *   @param index (UInt4) the index of the imported data set, maximum is PutNumOfAngles() - 1
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool ReplaceIntensityWithEcm(ElementContainerMatrix* ecm, UInt4 index);
        //!< Replace the intensity of the inside data set with the given ElementContainerMatrix with its index.
        /*!<
         *   @param ecm (ElementContainerMatrix) The data to be imported
         *   @param index (UInt4) the index of a data set to be replaced, maximum is PutNumOfAngles() - 1
         *   @retval true succeeded.
         *   @retval false failed.
         */
    void AllocateD4MatPseudoOnLine( UInt4 num_of_cases );
        //!< Allocate D4Mat data for on-line mode
        /*!<
         *   @param num_of_cases (UInt4) The number of CaseIds
         *   @retval None
         */
    Int4 RemoveEcm( UInt4 runNo );
        //!< Removes ElementContainer
        /*!< This removes one ElementContainer by given runNo
         *   RemoveEcm( UInt4 runNo );
         *   @param runNo (UInt4) the run number to be removed from D4Mat2 data
         *   @retval 0   no trouble
         */
    Int4 RemoveEcm( std::string label );
        //!< Removes ElementContainer
        /*!< This removes one ElementContainer by given label
         *   RemoveEcm( std::string label );
         *   @param label (std::string) The label of the data to be removed.
         *   @retval 0   no trouble
         */
    void ClearAll();
        //!< Clears D4Mat
        /*!< This resets D4Mat
         *   @param None
         *   @return None
         */
    void _putQvectorsFromData(D4MatOne* ec, std::vector<float> *Vx, std::vector<float> *Vy, std::vector<float> *Vz, std::vector<float> *Vw);
    bool _Slice2D( ElementContainerArray* eca, std::vector<Double> ax1range, std::vector<Double> ax2range, std::vector<Double> ax3range, std::vector<Double> ax4range, std::vector<std::string> type, std::vector<Double> folding, std::vector<std::string> axunits );
    bool Slice2d( ElementContainerArray* eca, PyObject* Ax1, PyObject* Ax2, PyObject* Ax3, PyObject* Ax4, PyObject* DiagFolding, PyObject* AxUnits );
        //!< Slices D4Mat by given parameters
        /*!< This slices D4Mat by given parametes to make ElementContainerArray as result
         *
         *   @param eca (ElementContainerArray) The sliced data to be returned (The given data must be empty.)
         *   @param Ax1 (PyObject list) slice info of axis 1  [ "type", min, max, width[, folding] ] where "type" is "x","y","z" or "t",
         *   @param Ax2 (PyObject list) slice info of axis 2
         *   @param Ax3 (PyObject list) slice info of axis 3
         *   @param Ax4 (PyObject list) slice info of axis 4
         *   @param DiagFolding (PyObject list) list of diag folding value for each axis
         *   @param AxUnits  (PyObject list) the list of units for axes
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool Slice2d( ElementContainerArray* eca, std::vector<Double> ax1range, std::vector<Double> ax2range, std::vector<Double> ax3range, std::vector<Double> ax4range, std::vector<std::string> axType, std::vector<Double> folding, std::vector<std::string> axunits );
        //!< Slices D4Mat by given parameters
        /*!< This slices D4Mat by given parametes to make ElementContainerArray as result
         *
         *   @param eca (ElementContainerArray) The sliced data to be returned (The given data must be empty.)
         *   @param ax1range (std::vector<Double>) range for axis 1
         *   @param ax2range (std::vector<Double>) range for axis 2
         *   @param ax3range (std::vector<Double>) range for axis 3
         *   @param ax4range (std::vector<Double>) range for axis 4
         *   @param axType   (std::vector<std::string>) types for each axis "X","Y","T"
         *   @param folding  (std::vector<Double>) folding information
         *   @param axunits  (std::vector<std::string>) the list of units for axes
         *   @retval true succeeded.
         *   @retval false failed.
         */
    ElementContainerArray Slice2d( std::vector<Double> ax1range, std::vector<Double> ax2range, std::vector<Double> ax3range, std::vector<Double> ax4range, std::vector<std::string> type, std::vector<Double> folding, std::vector<std::string> axunits );
        //!< Slices D4Mat by given parameters (not use recommended)
        /*!< This slices D4Mat by given parametes and makes ElementContainerArray as result
         *
         *   @param ax1range (std::vector<Double>) range for axis 1
         *   @param ax2range (std::vector<Double>) range for axis 2
         *   @param ax3range (std::vector<Double>) range for axis 3
         *   @param ax4range (std::vector<Double>) range for axis 4
         *   @param type     (std::vector<std::string>) types for each axis "X","Y","T"
         *   @param folding  (std::vector<Double>) folding information
         *   @param axunits  (std::vector<std::string>) the list of units for axes
         *   @return ElementContainerArray    results of sliced data
         */
    ElementContainerArray Slice2d( PyObject* ax1range, PyObject* ax2range, PyObject* ax3range, PyObject* ax4range, PyObject* type, PyObject* folding, PyObject* AxUnits );
        //!< Slices D4Mat by given parameters (not use recommended)
        /*!< This slices D4Mat by given parametes and makes ElementContainerArray as result
         *
         *   @param ax1range (PyObject float list) range for axis 1
         *   @param ax2range (PyObject float list) range for axis 2
         *   @param ax3range (PyObject float list) range for axis 3
         *   @param ax4range (PyObject float list) range for axis 4
         *   @param type     (PyObject str list) types for each axis "X","Y","T"
         *   @param folding  (PyObject float list) folding information
         *   @param AxUnits  (PyObject str list) the list of units for axes
         *   @return ElementContainerArray    results of sliced data
         */
    bool _Slice3D( ElementContainerMatrix* ecm, std::vector<Double> ax1range, std::vector<Double> ax2range, std::vector<Double> ax3range, std::vector<Double> ax4range, std::vector<std::string> type, std::vector<Double> folding );
    bool Slice3d( ElementContainerMatrix* ecm, PyObject* Ax1, PyObject* Ax2, PyObject* Ax3, PyObject* Ax4, PyObject* DiagFolding );
        //!< Slices D4Mat by given parameters
        /*!< This slices D4Mat by given parametes and makes ElementContainerArray as result
         *
         *   @param ecm (ElementContainerMatrix) The sliced data to be returned (The given data must be empty.)
         *   @param Ax1 (PyObject list) slice info of axis 1  [ "type", min, max, width[, folding] ] where "type" is "x","y","z" or "t",
         *   @param Ax2 (PyObject list) slice info of axis 2
         *   @param Ax3 (PyObject list) slice info of axis 3
         *   @param Ax4 (PyObject list) slice info of axis 4
         *   @param DiagFolding (PyObject list) list of diag folding value for each axis
         *   @retval true succeeded.
         *   @retval false failed.
         */
    ElementContainerMatrix Slice3d( std::vector<Double> ax1range, std::vector<Double> ax2range, std::vector<Double> ax3range, std::vector<Double> ax4range, std::vector<std::string> type, std::vector<Double> folding );
        //!< Slices D4Mat by given parameters
        /*!< This slices D4Mat by given parametes and makes ElementContainerArray as result
         *
         *   @param ax1range (std::vector<Double>) range for axis 1
         *   @param ax2range (std::vector<Double>) range for axis 2
         *   @param ax3range (std::vector<Double>) range for axis 3
         *   @param ax4range (std::vector<Double>) range for axis 4
         *   @param type     (std::vector<std::string>) types for each axis "X","Y","Z","T"
         *   @param folding  (std::vector<Double>) folding information
         *   @return ElementContainerMatrix    results of sliced data
         */
    ElementContainerMatrix Slice3d( PyObject* ax1range, PyObject* ax2range, PyObject* ax3range, PyObject* ax4range, PyObject* axistype, PyObject* folding );
        //!< Slices D4Mat by given parameters
        /*!< This slices D4Mat by given parametes and makes ElementContainerArray as result
         *
         *   @param ax1range (PyObject float list) range for axis 1
         *   @param ax2range (PyObject float list) range for axis 2
         *   @param ax3range (PyObject float list) range for axis 3
         *   @param ax4range (PyObject float list) range for axis 4
         *   @param axistype (PyObject str list) types for each axis "X","Y","Z","T"
         *   @param folding  (PyObject float list) folding information
         *   @return ElementContainerMatrix    results of sliced data
         */
    Int4 WriteData( std::string filename );
        //!< Saves D4Mat data using Boost Serialization
        /*!<
         *   @param filename (std::string)
         *   @retval 0   no trouble
         *   @retval -1  trouble happened.
         */
    Int4 ReadData( std::string filename );
        //!< Loads D4Mat data using Boost Serialization
        /*!<
         *   @param filename (std::string)
         *   @retval 0   no trouble
         *   @retval -1  trouble happened.
         */
    //ElementContainerArray* PutD4matPointer(){ return _D4mat; }
    D4MatGroup* PutD4matPointer(){ return _D4mat; }
        //!< Puts D4Mat data pointer
        /*!<
         *   @param None
         *   @return ElementContainerArray*)
         */
    void ResetD4mat();
        //!< Clear D4Mat data
        /*!<
         *   @param None
         *   @return None
         */
    std::vector<Double> AxLimit;
    std::vector<Double> GetAxLimit();
    std::vector<Double> GetAxLimit2();
        //!< Puts axes ranges of D4Mat
        /*!<
         *   @param None
         *   @return std::vector<Double>
         */
    PyObject* PutQRange(){ return __gCppToPython.VectorDoubleToList( GetAxLimit() );}
        //!< Puts axes ranges of D4Mat
        /*!<
         *   @param None
         *   @return python list object [ax1_min, ax1_max, ax2_min, ... , ax4_max]
         */
    bool AllocateD4MatOnDisk(std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range,
                             std::vector<std::string> titles, std::vector<std::string> units, std::string data_dir, std::string paramfile );
    bool AllocateD4MatOnDisk(PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range,
                             PyObject* titles, PyObject* units, std::string data_dir, std::string paramfile );
        //!< Makes new D4Matrix files on disk
        /*!< Each range consists of three values, start, end and width.
         *   @param a1range         first axis range
         *   @param a2range         second axis range
         *   @param a3range         third axis range
         *   @param a4range         fourth axis range
         *   @param titles          titles for axes
         *   @param units           units for axes
         *   @param data_dir        path to data dir (including xml file)
         *   @param paramfile       file name of parameter xml file
         *   @return None
         */
    Int4 SaveParamXmlD4MatOnDisk( std::string d4mat_datadir, std::string d4mat_param_file,
                                  std::vector<std::string> name_of_blocks, std::vector<UInt4> index_of_blocks,
                                  std::vector< std::vector<Double> > ranges, std::vector<std::string> axtitles,
                                  std::vector<std::string> units, std::vector<std::string> pathbinfiles );
        //!< Saves D4Mat xml to output data as D4Mat
        /*!< This method is called in AllocateD4MatOnDisk.
         *   @param d4mat_datadir (std::string) The path to the folder to store D4Mat data files
         *   @param d4mat_param_file (std::string) The file name of xml file for D4Mat
         *   @param name_of_blocks (std::vector<std::string>) File names of bin files
         *   @param index_of_blocks (std::vector<UInt4>) The index list of blocks in D4Mat data
         *   @param ranges (std::vector< std::vector<Double> >) The range for the axes in D4Mat data
         *   @param axtitles (std::vector<std::string>) The list of axes titles
         *   @param units (std::vector<std::string>) The list of units for axes
         *   @param pathbinfiles (std::vector<std::string>) The file list of vbin files (basically not use)
         *   @retval -1 Failed xml creation.
         *   @retval 0 Succeeded.
         */
    Int4 SaveParamXmlD4MatOnDisk( std::string d4mat_datadir, std::string d4mat_param_file,
                                  std::vector<std::string> name_of_blocks, std::vector<UInt4> index_of_blocks,
                                  std::vector<Double> ax1range, std::vector<Double> ax2range,
                                  std::vector<Double> ax3range, std::vector<Double> ax4range,
                                  std::vector<std::string> axtitles, std::vector<std::string> axunits,
                                  std::vector<std::string> pathbinfiles );
        //!< Saves D4Mat xml to output data as D4Mat
        /*!< This method is called in AllocateD4MatOnDisk.
         *   @param d4mat_datadir (std::string) The path to the folder to store D4Mat data files
         *   @param d4mat_param_file (std::string) The file name of xml file for D4Mat
         *   @param name_of_blocks (std::vector<std::string>) File names of bin files
         *   @param index_of_blocks (std::vector<UInt4>) The index list of blocks in D4Mat data
         *   @param ax1range (std::vector<Double>) The range of the AX1 axis in D4Mat data
         *   @param ax2range (std::vector<Double>) The range of the AX2 axis in D4Mat data
         *   @param ax3range (std::vector<Double>) The range of the AX3 axis in D4Mat data
         *   @param ax4range (std::vector<Double>) The range of the AX4 axis in D4Mat data
         *   @param axtitles (std::vector<std::string>) The list of axes titles
         *   @param units (std::vector<std::string>) The list of units for axes
         *   @param pathbinfiles (std::vector<std::string>) The file list of vbin files (basically empty)
         *   @retval -1 Failed xml creation.
         *   @retval 0 Succeeded.
         */
    std::vector<std::string> _vbinFileComponents;

    Int4 ImportEcmStepByStep(ElementContainerMatrix* ecm, double ang, double norm, double normFactor);
        //!< Import ECM data into D4Mat2 (currently not use)
        /*!< where ECM is the histogram data after the data reductions at an angle.
         *   @param ecm (ElementContainerMatrix) The data to be imported.
         *   @param ang (Double) Angle (around Y axis).
         *   @param norm (Double) The normalizing factor, like the proton current or the number of kickers.
         *   @param normFactor (Double) The correction value for normalization.
         *   @retval 0 Succeeded.
         */
    Int4 ImportEcmStepByStep(ElementContainerMatrix* ecm, double ang, std::string label, bool isStepByStep=true );
        //!< Import ECM data into D4Mat2
        /*!< where ECM is the histogram data after the data reductions at an angle.
         *   @param ecm (ElementContainerMatrix) The data to be imported.
         *   @param ang (Double) Angle (around Y axis).
         *   @param label (std::string) The label for the data
         *   @param isStepByStep (bool) Whether the mesurement method of the data is Step-by-Step method or not (continuous rotation)
         *   @retval 0 Succeeded.
         */
    bool Projection();
        //!< Do the projection treatment of the data
        /*!< This function do the projection over all angles data using stored information (XtalParam and view axes)
         *
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool Projection( std::vector<Double> viewAxis );
        //!< Do the projection treatment of the data
        /*!< This function do the projection over all angles data.
         *   @param vewAxis (std::vector<Double>) The view axes list [ax1_a*, ax1_b*, ax1_c*, ax1_enrgy, ax2_a*, ... , ax4_enrgy ]
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool Projection( UInt4 ind, std::vector<Double> viewAxis );
        //!< Do the projection treatment of the data
        /*!< This function do the projection of the data at an angle given by argument of ind.
         *   @param ind (UInt4) The index of the inner D4Mat data set which stores data for each angle.
         *   @param vewAxis (std::vector<Double>) The view axes list [ax1_a*, ax1_b*, ax1_c*, ax1_enrgy, ax2_a*, ... , ax4_enrgy ]
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool ProjectionStepByStep(PyObject* viewAxis ){
        std::cout << "!!!!!!!!!!! WARNING : ProjectionStepByStep will disappear at next major update." << std::endl;
        std::cout << "Please use Projection instead. ( both classes are same absolutely )"<<std::endl;
        std::cout << "!!!!!!!!!!!" << std::endl;
        return Projection( viewAxis );
    }
        //!< Do the projection treatment of the data (obsolete)
        /*!< This function do the projection over all angles data.
         *   @param vewAxis (PyObject float list) The view axes list [ax1_a*, ax1_b*, ax1_c*, ax1_enrgy, ax2_a*, ... , ax4_enrgy ]
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool Projection( PyObject* viewAxis );
        //!< Do the projection treatment of the data
        /*!< This function do the projection over all angles data.
         *   @param vewAxis (PyObject float list) The view axes list [ax1_a*, ax1_b*, ax1_c*, ax1_enrgy, ax2_a*, ... , ax4_enrgy ]
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool ExportEcmFromStepByStep(ElementContainerMatrix* ecm, UInt4 index);
        //!< Exports an angle data given by the index to ecm
        /*!<
         *   @param ecm (ElementContainerMatrix) The empty data container to be filled with the data.
         *   @param index (UInt4) The index of the inner D4Mat data set which stores data for each angle.
         *   @retval true succeeded.
         *   @retval false failed.
         */

    std::vector<std::string> PutLabelsOfImportedEcm();
        //!< Put the labels for the imported data
        /*!<
         *   @param None
         *   @return std::vector<std::string> The list of labels for the imported data
         */
    bool isDirectGeometry;
    void SetAveragingOnSlice( bool useAve = true ){_useAveOnSlice=useAve;}
        //!< Set intensity caluculation mode (average or summation) in _Slice2D and _Slice3D
        /*!<
         *   @param useAve (bool)   true : Average,  false : summation
         *   @return None
         */
    void SetXtalParam(std::string xtalparam){ _D4mat->_XtalParam=xtalparam; }
       //!< Set the xml contents of XtalParam as the inner XtalParam information
        /*!<
         *   @param xtalparam (std::string) XtalParam text
         *   @return None
         */
    std::string PutXtalParam(){ return _D4mat->_XtalParam; }
        //!< Get the xml contents of the inner XtalParam
        /*!<
         *   @param None
         *   @return std::string XtalParam
         */
    bool SaveXtalParam(std::string filepath);
        //!< Save the xml contents as the filepath
        /*!< This make xml text from the innder header information (_HH)
         *   @param filepath (std::string) The path to the xml file.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SaveData(std::string filepath, bool withComp=false);
        //!< Save the binary D4Mat2 data
        /*!<
         *   @param filepath (std::string) The path to the saved data file
         *   @param withComp (bool) Whether doing compression on the binary data or not on file saving.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool LoadData(std::string filepath);
        //!< Load the binary D4Mat2 data
        /*!<
         *   @param filepath (std::string) The path of the file to be loaded.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool DumpAllDataPoints(std::string filepath);
        //!< Dump all data points into the text file
        /*!<
         *   @param filepath (std::string) The path of the file.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool PutSlicedD4MatrixToText(std::string filepath,
                                 std::vector<Double> ax1range, std::vector<Double> ax2range,
                                 std::vector<Double> ax3range, std::vector<Double> ax4range,
                                 std::vector<Double> folding, bool isAve=true);
        //!< Put sliced (matrix) data points into the text file
        /*!<
         *   @param filepath (std::string) The path of the file.
         *   @param ax1range (std::vector<Double>) Ax1 range [<min>, <max>, <bin>]
         *   @param ax2range (std::vector<Double>) Ax2 range
         *   @param ax3range (std::vector<Double>) Ax3 range
         *   @param ax4range (std::vector<Double>) Ax4(hw) range
         *   @param folding  (std::vector<Double>) Folding information [<ax1_fold>, <ax2_fold>,...]
         *   @param isAve (bool) true means that the calculated intensity is normalized by the number of data.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool PutSlicedD4MatrixToVectors(std::vector<Double> *ax1, std::vector<Double> *ax2, std::vector<Double> *ax3, std::vector<Double> *ax4, std::vector<Double> *intensity, std::vector<Double> *error, bool isAve=true);
        //!< Put inner arrays for sliced (matrix) data points as vectors
        /*!<
         *   @param ax1range (std::vector<Double>*) Ax1 bin std::vector
         *   @param ax2range (std::vector<Double>*) Ax2 bin std::vector
         *   @param ax3range (std::vector<Double>*) Ax3 bin std::vector
         *   @param ax4range (std::vector<Double>*) Ax4(hw) bin std::vector
         *   @param intansity (std::vector<Double>*) intensity std::vector
         *   @param error (std::vector<Double>*) error std::vector
         *   @param isAve (bool) true means that the calculated intensity is normalized by the number of data.
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool MakeSlicedD4MatrixInner(std::vector<Double> ax1range, std::vector<Double> ax2range,
                                 std::vector<Double> ax3range, std::vector<Double> ax4range,
                                 std::vector<Double> folding);
        //!< Make inner arrays for sliced (matrix) data points
        /*!<
         *   @param ax1range (std::vector<Double>) Ax1 range [<min>, <max>, <bin>]
         *   @param ax2range (std::vector<Double>) Ax2 range
         *   @param ax3range (std::vector<Double>) Ax3 range
         *   @param ax4range (std::vector<Double>) Ax4(hw) range
         *   @param folding  (std::vector<Double>) Folding information [<ax1_fold>, <ax2_fold>,...]
         *   @retval true succeeded.
         *   @retval false failed.
         */
    void ClearSlicedD4MatrixInner();
        //!< Clear inner arrays for  sliced (matrix) data points
        /*!<
         *   @retval None
         */
    bool Empty(){ return _D4mat->data->empty(); }
        //!< Check whether the D4Mat2 data is empty.
        /*!<
         *   @retval true The data is empty.
         *   @retval false The data is filled.
         */
    bool MakeVirtualD4Mat2(ElementContainerMatrix* ecm, std::vector<Double> angles, std::vector<std::string> labels);
        //!< Make dummy D4Mat2 data
        /*!< This makes the virtual measurement data to be used for the check the measurement area and so on.
         *   @apram ecm (ElementContainerMatrix) The dummy data (all intensities are "1.0")
         *   @param angles (std::vector<Double>) The angles list used as the dummy data
         *   @param labels (std::vector<std::string>) The labels list used ad the dummy data
         *   @retval true succeeded.
         *   @retval false failed.
         */
    UInt4 PutSize(){ return (UInt4)(_D4mat->data->size()); }
        //!< Put the size of D4Mat data (the number of measurements angles)
        /*!<
         *   @param None
         *   @retval UInt4 the size
         */
    std::string MakeXmlStringFromHeader(HeaderBase* hh);
        //!< Put Xtalparam.xml information converted from the given header information
        /*!<
         *   @param hh (HeaderBase) the given header information
         *   @retval std::string The xml text made from the header
         */
    TreatD4Matrix2XmlParams* PutTreatD4Mat2XmlParams(){ return  _TP; }
        //!< Put the instanse of TreatD4Matrix2XmlParams
        /*!<
         *   @param None
         *   @retval the instanse of TreatD4Matrix2XmlParams
         */
    bool isMemSaveMode;
    void SetMemorySaving(bool memSave=true);
    void DumpInnerHeader(){ _HH->Dump();}
};
#endif

