#ifndef UTSUSEMID4MATRIX
#define UTSUSEMID4MATRIX

#include "Header.hh"
#include "ElementContainer.hh"
#include "ElementContainerArray.hh"
#include "CppToPython.hh"
#include "StringTools.hh"
#include "BoostXmlParser.hh"
#include <iomanip>
#include "UtsusemiHeader.hh"
#include "UtsusemiSqeCalc2.hh"
#include "UtsusemiUnitConverter.hh"
#include "UtsusemiNeunetEventDecoderBase.hh"
#include "UtsusemiGetNeunetHistogram.hh"

//////////////////////
//  UtsusemiD4Matrix
/////////////////////

//! Class for treating 4-dimensional data
/*!
 * This can import and conbine several data of single crystal sample
 * with dirrent conditions produced from VisualCont2.
 *
 */

class UtsusemiD4Matrix

{
private:
    std::string MessageTag;
    Double MAX_SIZE_OF_ONE_BLOCK;
    bool isDebugMode;
    std::string d4mat_param_file;
    std::string d4mat_data_dir;
    StringTools *stools;
    bool isFilesOpened;
    bool _isGoodResult;
    bool _isDirectGeometry;
    Double _Ef_fixed;

    void _Initialize();
        //!< Initializes for this class
        /*!< Sets initial value about MAX_SIZE_OF_ONE_BLOCK and some flags.
         *   @return None
         */
    Int4 _OpenFiles();
        //!< Opens allocated binary files
        /*!< Make file pointers for files described in parameter file
         *   @retval 0              No Error
         *   @retval -1             Error
         */
    Int4 _CalcIndex( Double a1, Double a2, Double a3, Double a4, UInt4 *target, UInt8 *ind );
        //!< Calculates index(pointer) in binary files.
        /*!<
         *   @param a1      range of a1-axis
         *   @param a2      range of a2-axis
         *   @param a3      range of a3-axis
         *   @param a4      range of a4-axis
         *   @param target  index of list for FILE I/O pointer including given a4 value
         *   @param ind     index of pointer on binary file calculated by a1, a2, a3 and a4.
         *   @return None
         */

    std::vector< std::vector<Double> > datArray, errArray; /**< Vectors of sliced data*/
    std::vector<Double> XArray, YArray;               /**< Vectors of XY axes for sliced data*/
    Int4 _AddToMatFromText( std::string filename, bool isAdd );
        //!< Adds or subtract TEXT data to D4Matrix files
        /*!< Reads TEXT data produced by VisualCont2 and add/subtract these values to/from D4Matrix files
         *   @param paramfilepath   full path to parameter
         *   @param isAdd           true: Add to, false: Sbutract from
         *   @retval 0              No Error
         *   @retval -1             Error
         */
    Int4 _AddToMatFromBin( std::string filename, bool isAdd );
        //!< Adds or subtract BINARY data to D4Matrix files
        /*!< Reads binary data converted from TEXT data of VisualCont2
         *   and add/subtract these values to/from D4Matrix files
         *   @param paramfilepath   full path to parameter
         *   @param isAdd           true: Add to, false: Sbutract from
         *   @retval 0              No Error
         *   @retval -1             Error
         */
    Int4 _ReadParamXml( std::string datapath, std::string paramfilepath );
        //!< Reads parameters from XML file
        /*!<
         *   @param paramfilepath The path to XML file of parameters
         *   @retval 0              No Error
         *   @retval -1             Error
         */
    void _ClearAllParams();
    bool _CalcRangeInfo( UInt4 dim, std::vector<Double> &a1r, std::vector<Double> &a2r, std::vector<Double> &a3r, std::vector<Double> &a4,
                         std::vector<std::string> &def_axes, std::vector<UInt4> &def_ind, std::vector< std::vector<Double> > &arlist, std::vector<UInt4> &numlist );
    bool _SliceMat( ElementContainerMatrix* _ecm, UInt4 dim, std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::vector<std::string> key_axes );
    std::vector<UInt4> _AxisDefIndex; // Axis info of sliced data index of Xaxis:[0], index of Yaxis:[1], ...

    // For VirtualD4Matrix
    bool _isVirtual;
    std::vector< std::vector<float>* >* _VirtualD4Mat;
    std::vector< std::pair<double,double>* > _VirtualAngleInfo;
    void _ClearVirtualMat();
    Int4 _CalcIndexVirtual( Double a1, Double a2, Double a3, UInt8 *ind );

public:
    UtsusemiD4Matrix();
        //!< Constructor
        /*!<
         */
    UtsusemiD4Matrix( bool isDebugMode );
        //!< Constructor
        /*!<
         *   @param isDebugMode  shows some comments and parameters on executing.
         */
    ~UtsusemiD4Matrix();
        //!< Destructor
        /*!<
         */
    bool SetEf( double _ef );
        //!< Sets Ef which is used to caculate the energy transfer for the inverted geometry instruments.
        /*!<
         *   @param _ef (Double) Ef [meV]
         *   @retval true succeeded.
         *   @retval false failed.
         */
    Double PutEf(){ return _Ef_fixed; }
        //!< Puts Ef which is used to caculate the energy transfer for the inverted geometry instruments.
        /*!<
         *   @param None
         *   @return Ef
         */
    void SetMaxSizeOfBlock( Double _size );
        //!< Sets maximum file size for one block of allocated D4Matrix binary file
        /*!< All file size can not be exceeded this size
         *   @param _size (Double) maximum file size
         *   @return None
         */
    void AllocateNewMat( 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 );
        //!< Makes new D4Matrix files on disk
        /*!< Each range consists of three values, start, end and width.
         *   @param a1range (std::vector<Double>) first axis range
         *   @param a2range (std::vector<Double>) second axis range
         *   @param a3range (std::vector<Double>) third axis range
         *   @param a4range (std::vector<Double>) fourth axis range
         *   @param titles  (std::vector<std::string>) titles for axes
         *   @param units   (std::vector<std::string>) units for axes
         *   @param data_dir (std::string) path to data dir (including xml file)
         *   @param paramfile (std::string) file name of parameter xml file
         *   @retval None
         */
    bool AllocateNewMat( 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 (PyObject float list) first axis range
         *   @param a2range (PyObject float list) second axis range
         *   @param a3range (PyObject float list) third axis range
         *   @param a4range (PyObject float list) fourth axis range
         *   @param titles  (PyObject str list) titles for axes
         *   @param units   (PyObject str list) units for axes
         *   @param data_dir (std::string) path to data dir (including xml file)
         *   @param paramfile (std::string) file name of parameter xml file
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    bool OpenMat( std::string datapath, std::string paramfile );
        //!< Open D4Matrix files existing on disk
        /*!< Read parameter file and open file pointers given by parameters.
         *   @param datapath (std::string) The path to data dir
         *   @param paramfile (std::string) The file name of parameter xml file
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    void CloseMat();
        //!< Closes opened D4Matrix files
        /*!< Close all file pointers opened by _OpenDat method.
         *   @param None
         *   @return None
         */
    bool isMatOpened(){ return isFilesOpened; }
        //!< Returns whether D4Matrix files are opened or not
        /*!<
         *   @param None
         *   @retval true   D4Matrix files are opened.
         *   @retval false  Not opened.
         */
    bool isStatusOK(){ return _isGoodResult; }
        //!< Returns status of results to be executed
        /*!<
         *   @param None
         *   @retval true   OK.
         *   @retval false  Bad.
         */
    void AddToMatFromText( std::string filename );
        //!< Adds TEXT data to D4Matrix files
        /*!< Read TEXT data produced by VisualCont2 and add these values to D4Matrix files
         *   @param  filename (std::string) The full path to the text data file
         *   @return None
         */
    Int4 AddToMatFromPyList( std::string title, PyObject *ax1, PyObject *ax2, PyObject *ax3, PyObject *ax4, PyObject *ii, PyObject *ee );
        //!< Adds python List object data to D4Matrix files
        /*!< Adds Sliced data produced by VisualCont2 to D4Matrix files
         *   @param title (std::string) Title for this data
         *   @param ax1 (PyObject float list) AX1
         *   @param ax2 (PyObject float list) AX2
         *   @param ax3 (PyObject float list) AX3
         *   @param ax4 (PyObject float list) AX4
         *   @param ii (PyObject float list) Intensity
         *   @param ee (PyObject float list) Error
         *   @retval 0  No Error
         *   @retval -1 Error
         */
    void SubtractFromMatByText( std::string filename );
        //!< Subtracts TEXT data from D4Matrix files
        /*!< Read TEXT data produced by VisualCont2 and subtract these values from D4Matrix files
         *   @param filename (std::string)  The full path to the text data file
         *   @return None
         */
    bool AddToMatFromBin( std::string filename );
        //!< Adds BINARY data to D4Matrix files
        /*!< Read binary data converted by VisualCont2 funcion to add these data into D4Matrix files
         *   @param filename (std::string) The full path to the binary data file
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    bool AddToMatFromBinFolder( std::string folderpath, std::string _ext=".vbin" );
        //!< Adds D4Mat vbin files in the given "folderpath" folder.
        /*!< Read binary data converted by VisualCont2 funcion to add these data into D4Matrix files
         *   @param folderpath (std::string) the full path to the folder
         *   @param _ext (std::string) the extention code for the binary files
         *   @retval true Succeeded.
         *   @retval false Failed.
         */
    void SubtractFromMatByBin( std::string filename );
        //!< Subtracts BINARY data from D4Matrix files
        /*!< Read binary data converted from TEXT data of VisualCont2 and subtract these values from D4Matrix files
         *   @param filename (std::string) The full path to the binary data
         *   @return None
         */
    void SliceMat( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings );
        //!< Slices D4Matrix by the given ranges and types of axes as 2D data
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X", "Y" and "T".
         *   "X" and "Y" mean X and Y axis on the visualization. Other two axes, must be indicated by "T", are summarized.
         *   Each range must consits of two values, begin and end;
         *   @param a1range (std::vector<Double>)  first axis range  [min, max]
         *   @param a2range (std::vector<Double>)  second axis range [min, max]
         *   @param a3range (std::vector<Double>)  third axis range  [min, max]
         *   @param a4range (std::vector<Double>)  fourth axis range [min, max]
         *   @param def_axes (std::vector<std::string>)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (std::vector<Double>) folding values, [] means [ -1, -1, -1, -1]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    bool SliceMat( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings ){ return Slice2d( NULL, a1range, a2range, a3range, a4range, def_axes, foldings ); }
        //!< Slices D4Matrix by the given ranges and types of axes as 2D data
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X", "Y" and "T".
         *   "X" and "Y" mean X and Y axis on visualization. Other two axes, must be indicated by "T", are summarized.
         *   Each range must consits of two values, begin and end;
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    void SliceMat1d( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings );
        //!< Slices D4Matrix by the given ranges and types of axes as 1D data (along an axis)
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X" and "T".
         *
         *   Each range must consits of two values, begin and end;
         *   @param a1range (std::vector<Double>)  first axis range  [min, max]
         *   @param a2range (std::vector<Double>)  second axis range [min, max]
         *   @param a3range (std::vector<Double>)  third axis range  [min, max]
         *   @param a4range (std::vector<Double>)  fourth axis range [min, max]
         *   @param def_axes (std::vector<Double>)   role of each axis, for example [ "X", "T", "T", "T" ]
         *   @param foldings (std::vector<Double>) folding values, [] means [ -1, -1, -1, -1]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */

    bool Slice2d( ElementContainerArray* _eca, PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings );
        //!< Slices D4Matrix by parameters from Python
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X", "Y" and "T".
         *   "X" and "Y" mean X and Y axis on visualization. Two axes indicated by "T" are summarized.
         *   Each range must consits of two values, begin and end;
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)  role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    ElementContainerArray Slice2d( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings );
        //!< Slices D4Matrix by parameters from Python as 2D and returns the result as ElementContainerArray
        /*!<  (Not recomended) Slice2d (ElementContainerArray, ...) shoud be used instead of this method.
         *   Each range must consits of two values, begin and end;
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)  role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    std::vector<Double> PutSliceResults( UInt4 type, UInt4 Xindex );
        //!< Put Sliced data as std::vector.
        /*!< Put std::vector made by SliceMat. This method puts a vector with X index.'type' indicates the type of data.
         *   @param type (UInt4) This indicates data type 0:Intensity, 1:Error, 2:X array, 3:Y array
         *   @param Xindex (UInt4) This indicates index of vectors of Intensity and Error.
         *   @return std::string std::vector
         */
    std::vector<Double> PickUpInten( Double a1, Double a2, Double a3, Double a4 );
        //!< Picks up data at a point on D4Matrix.
        /*!< Picks up data at a point indicated by given parameters and show its intensity and error.
         *   @param a1 (Double) A1 axis
         *   @param a2 (Double) A2 axis
         *   @param a3 (Double) A3 axis
         *   @param a4 (Double) A4 axis
         *   @return std::vector of two values for intensity and error.
         */
    void ReplaceInten( Double a1, Double a2, Double a3, Double a4, Double Inten, Double Error, Double Counts );
        //!< Replaces data at a point on D4Matrix.
        /*!< Replaces data at a point indicated by given parameters with given Intensity, Error and Counts.
         *   @param a1 (Double) A1 axis
         *   @param a2 (Double) A2 axis
         *   @param a3 (Double) A3 axis
         *   @param a4 (Double) A4 axis
         *   @param Inten (Double) Value for Intensity to be replaced
         *   @param Error (Double) Value for Error to be replaced
         *   @param Counts (Double) Value for the number of summarized data
         *   @return None
         */
    ElementContainerArray PutSlicedECA();
        //!< Puts Sliced data as ElementContainerArray
        /*!< Sliced data are stored in list of vectors.
         *   This method constructs ElementContainerArray from these vectors.
         *   ElementContainerArray can be sent to M2Plot directly.
         *   @param None
         *   @return ElementContainerArray
         */
    std::vector<std::string> PutFileComponents(){ return file_components; }
        //!< Puts list for file component of D4Matrix
        /*!<
         *   @param None
         *   @return file_components
         */
    std::vector<Double> PutAxRange( UInt4 i_ax );
        //!< Puts axis range
        /*!< Puts axis range in range_list by given index i_ax as std::vector
         *   @param i_ax (UInt4) The index of axis
         *   @return range_list[ i_ax ]
         */
    std::string PutAxTitle( UInt4 i_ax );
        //!< Puts axis title
        /*!<
         *   @param i_ax (UInt4) The index of axis title
         *   @return  ax_titles[ i_ax ]
         */
    void SetAxTitle( UInt4 i_ax, std::string title );
        //!< Sets axis title
        /*!<
         *   @param i_ax (UInt4) The index of axis title
         *   @param title (std::string) The axis title
         *   @return None
         */
    void SetAxTitles( std::vector<std::string> titles, bool isSaved );
        //!< Sets axis titles and save parames xml file
        /*!<
         *   @param titles (std::vector<std::string>) The list for axis titles
         *   @param isSaved (bool) The flag for save file after set of titles
         *   @return None
         */
    void SetAxTitles( PyObject* titles, bool isSaved );
        //!< Sets axis titles and save parames xml file
        /*!<
         *   @param titles (PyObject str list) The list for axis titles
         *   @param isSaved (bool) The flag for save file after set of titles
         *   @return None
         */
    std::string PutAxUnit( UInt4 i_ax );
        //!< Puts axis unit
        /*!<
         *   @param i_ax (UInt4) The index of axis title
         *   @return  ax_units[ i_ax ]
         */
    void SetAxUnit( UInt4 i_ax, std::string title );
        //!< Sets axis unit
        /*!<
         *   @param i_ax (UInt4) The index of axis unit
         *   @param title  axis unit
         *   @return None
         */
    void SetAxUnits( std::vector<std::string> units, bool isSaved );
        //!< Sets axis units and save parames xml file
        /*!<
         *   @param units (std::vector<std::string>) The list for axis units
         *   @param isSaved (bool) The flag for save file after set of units
         *   @return None
         */
    void SetAxUnits( PyObject* units, bool isSaved );
        //!< Sets axis units and save parames xml file
        /*!<
         *   @param units (PyObject std::string list) The list for axis units
         *   @param isSaved (bool) The flag for save file after set of units
         *   @return None
         */
    void SavePyListToBin( std::string filepath, PyObject *ax1, PyObject *ax2, PyObject *ax3, PyObject *ax4, PyObject *ii, PyObject *ee );
        //!< Saves List object on python to binary file
        /*!< Saves given list object on python to binary file as the format to be loaded by AddToMatFromBin.
         *   @param filepath (std::string) The file path of save binary file
         *   @param ax1 (PyObject float list) AX1
         *   @param ax2 (PyObject float list) AX2
         *   @param ax3 (PyObject float list) AX3
         *   @param ax4 (PyObject float list) AX4
         *   @param ii (PyObject float list) Intensity
         *   @param ee (PyObject float list) Error
         *   @return None
         */
    void AddMatToMat( std::string dir_from, std::string file_from, std::string dir_to, std::string file_to );
        //!< Adds data of saved Matrix files to other Matrix data files
        /*!< This is mainly used for rebinning of matrix
         *   @param dir_from (std::string) The directory path to original data
         *   @param file_from (std::string) The file name to original data
         *   @param dir_to (std::string) The directory path to new data
         *   @param file_to (std::string) The file name to new data
         *   @return None
         */
    std::vector<std::string> PutOpenedDataPath();
        //!< Puts opened data path
        /*!< This pushes d4mat_data_dir and d4mat_param_file
         *   @param None
         *   @return std::string std::vector including d4mat_data_dir and d4mat_param_file
         */

    Int4 GetPartOfD4Mat( UInt4 fs_index, float data[], UInt4 top_posi, UInt4 get_size);
        //!< Picks up the part of the binary data file
        /*!<
         *   @param fs_index (UInt4) The index of the opened d4mat bin files
         *   @retval -1 Error that fs_index is too large
         *   @retval -2 Error that top_posi is over the size of data
         *   @retval -3 Error that the file is not opened.
         *   @retval Int4 the result value of the fread function
         */
    Int4 SaveParamXml( std::string datapath, std::string paramfilepath );
        //!< Saves parameters to XML file
        /*!<
         *   @param paramfilepath (std::string) The path to XML file of parameters
         *   @retval 0  No Error
         *   @retval -1 Error
         */
    Int4 SliceMat3D( ElementContainerMatrix* _ecm, std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::vector<std::string> key_axes );
        //!< Slices D4Matrix for 3D
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X", "Y", "Z" and "T".
         *   "X","Y" and "Z" mean X, Y and Z axis on visualization. The other axis indicated by "T" are summarized.
         *   Each range must consits of two values, begin and end;
         *   SliceMat3D( dat, a1range, a2range, a3range, a4range, def_axes, foldings, key_axes );
         *   @param data (ElementContainerMatrix) The result data
         *   @param a1range (std::vector<Double>)  first axis range  [min, max]
         *   @param a2range (std::vector<Double>)  second axis range [min, max]
         *   @param a3range (std::vector<Double>)  third axis range  [min, max]
         *   @param a4range (std::vector<Double>)  fourth axis range [min, max]
         *   @param def_axes (std::vector<std::string>)   role of each axis, for example [ "X", "Y", "Z", "T" ]
         *   @param foldings (std::vector<Double>)  folding values, empty means [ -1, -1, -1, -1]
         *   @param key_axes (std::vector<std::string>)   Key name for each range [ <KeyX>,<KeyY>,<KeyZ> ]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    bool SliceMat3D( ElementContainerMatrix* _ecm, PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, PyObject* key_axes ){ return Slice3d( _ecm, a1range, a2range, a3range, a4range, def_axes, foldings, key_axes ); }
        //!< Slices D4Matrix for 3D
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X", "Y", "Z" and "T".
         *   "X","Y" and "Z" mean X, Y and Z axis on visualization. The other axis indicated by "T" are summarized.
         *   Each range must consits of two values, begin and end;
         *   SliceMat3D( dat, a1range, a2range, a3range, a4range, def_axes, foldings, key_axes );
         *   @param data (ElementContainerMatrix) The result data
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @param key_axes (PyObject str list)   Key name for each range [ <KeyX>,<KeyY>,<KeyZ> ]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    bool Slice3d( ElementContainerMatrix* _ecm, PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, PyObject* key_axes );
        //!< Slices D4Matrix for 3D
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X", "Y", "Z" and "T".
         *   "X","Y" and "Z" mean X, Y and Z axis on visualization. The other axis indicated by "T" are summarized.
         *   Each range must consits of two values, begin and end;
         *   Slice3D( dat, a1range, a2range, a3range, a4range, def_axes, foldings, key_axes );
         *   @param data (ElementContainerMatrix) The result data
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @param key_axes (PyObject str list)   Key name for each range [ <KeyX>,<KeyY>,<KeyZ> ]
         *   @retval False Failed.
         *   @retval True  Succeeded.
         */
    ElementContainerMatrix Slice3d( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, PyObject* key_axes );
        //!< Slices D4Matrix for 3D (Not recommended using this. Use SliceMat3D instead.)
        /*!< Picks up the region given by parameters from D4Matrix and make std::vector data for visualization.
         *   Users can set 4 axes ranges and the role of each axis by using std::string "X", "Y", "Z" and "T".
         *   "X","Y" and "Z" mean X, Y and Z axis on visualization. The other axis indicated by "T" are summarized.
         *   Each range must consits of two values, begin and end;
         *   Slice3D(a1range, a2range, a3range, a4range, def_axes, foldings, key_axes);
         *   @param a1range (PyObject float list) first axis range  [min, max]
         *   @param a2range (PyObject float list) second axis range [min, max]
         *   @param a3range (PyObject float list) third axis range  [min, max]
         *   @param a4range (PyObject float list) fourth axis range [min, max]
         *   @param def_axes (PyObject str list) role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @param key_axes (PyObject str list) Key name for each range [ <KeyX>,<KeyY>,<KeyZ> ]
         *   @retval ElementContainerMatrix The sliced data
         */
    Int4 OutputText3D( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::string filename, bool isIgnoreMaskVal=false, std::string maskValStr=""  );
        //!< Slices as 3D axes data of D4Matrix to save as text file
        /*!<
         *   OutputText3D( a1range, a2range, a3range, a4range, def_axes, foldings, filename, isIgnoreMaskVal, maskValStr );
         *   @param a1range (std::vector<Double>) first axis range  [min, max]
         *   @param a2range (std::vector<Double>) second axis range [min, max]
         *   @param a3range (std::vector<Double>) third axis range  [min, max]
         *   @param a4range (std::vector<Double>) fourth axis range [min, max]
         *   @param def_axes (std::vector<std::string>) role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (std::vector<Double>) folding values, [] means [ -1, -1, -1, -1]
         *   @param isIgnoreMaskVal (bool) ignore mask values ( does not save mask value ) or not
         *   @param maskValStr (std::string) if isIgnoreMaskVal==False, this std::string is used as the mask value in text file.
         *   @retval 0 No trouble.
         *   @retval -1 Failed to slice data.
         *   @retval -2 Failed to calculate the reanges for the axes.
         *   @retval -3 Failed to open the file to output.
         */
    bool OutputText3D( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, std::string filename, bool isIgnoreMaskVal=false, std::string maskValStr=""  );
        //!< Slices as 3D axes data of D4Matrix to save as text file
        /*!<
         *   OutputText3D( a1range, a2range, a3range, a4range, def_axes, foldings, filename, isIgnoreMaskVal, maskValStr );
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @param isIgnoreMaskVal (bool)   ignore mask values ( does not save mask value ) or not
         *   @param maskValStr (str)         if isIgnoreMaskVal==False, this std::string is used as the mask value in text file.
         *   @retval True  Succeeded.
         *   @retval False Failed.
         */
    Int4 DumpD4MatToFile( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::string filename, bool isText=true, bool isAve=true );
       //!< Saves D4Matrix to text or binary file
        /*!<
         *   DumpD4MatToFile( a1range, a2range, a3range, a4range, def_axes, foldings, filename, isText );
         *   @param a1range (std::vector<Double>)  first axis range  [min, max]
         *   @param a2range (std::vector<Double>)  second axis range [min, max]
         *   @param a3range (std::vector<Double>)  third axis range  [min, max]
         *   @param a4range (std::vector<Double>)  fourth axis range [min, max]
         *   @param def_axes (std::vector<std::string>)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (std::vector<Double>) folding values, [] means [ -1, -1, -1, -1]
         *   @param isText (bool) If True, save data as text file.
         *   @param isAve  (bool) If False, the intensity of a bin is the summation of the counts.
         *   @retval 0 No trouble.
         *   @retval -1 Failes to calculate the ranges for the axes.
         */
    bool DumpD4MatToFile( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, std::string filename, bool isText=true, bool isAve=true );
        //!< Saves D4Matrix to text or binary file
        /*!<
         *   DumpD4MatToFile( a1range, a2range, a3range, a4range, def_axes, foldings, filename, isText );
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @param isText (bool) If True, save data as text file.
         *   @param isAve  (bool) If False, the intensity of a bin is the summation of the counts.
         *   @retval True  Succeeded.
         *   @retval False Failed.
         */
    Int4 DumpD4MatIntoVect( std::vector<Double> a1r, std::vector<Double> a2r, std::vector<Double> a3r, std::vector<Double> a4r, std::vector<std::string> def_axes, std::vector<Double> foldings, bool isAve,
                            std::vector<Double> *ax1, std::vector<Double> *ax2, std::vector<Double> *ax3, std::vector<Double> *hws, std::vector<Double> *intensity, std::vector<Double> *error);
       //!< Put D4Matrix into given vectors on memory.
        /*!< The order of intensity ::
         *   for ihw in range(hws.size()):
         *       for i1 in range(ax1.size()):
         *           for i2 in range(ax2.size()):
         *               for i3 in range(ax3.size()):
         *                   ind = i3 + (ax3.size() * i2) + (ax3.size() * ax2.size() * i1) + (ax3.size() * ax2.size() * ax1.size() * ihw)
         *                   i1, i2, i3, ihw, intensity[ind], error[ind]
         *
         *   DumpD4MatToFile( a1r, a2r, a3r, a4r, def_axes, foldings, isAve,
         *                    ax1, ax2, ax3, hws, intensity, error );
         *   @param a1r (std::vector<Double>)  first axis range  [min, max]
         *   @param a2r (std::vector<Double>)  second axis range [min, max]
         *   @param a3r (std::vector<Double>)  third axis range  [min, max]
         *   @param a4r (std::vector<Double>)  fourth axis range [min, max]
         *   @param def_axes (std::vector<std::string>)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (std::vector<Double>) folding values, [] means [ -1, -1, -1, -1]
         *   @param isAve  (bool) If False, the intensity of a bin is the summation of the counts.
         *   @param ax1 (std::vector<Double>*) ax1 std::vector imported from D4Matrix data
         *   @param ax2 (std::vector<Double>*) ax2 std::vector imported from D4Matrix data
         *   @param ax3 (std::vector<Double>*) ax3 std::vector imported from D4Matrix data
         *   @param hws (std::vector<Double>*) hw std::vector imported from D4Matrix data
         *   @param intensity (std::vector<Double>*) intensity std::vector imported from D4Matrix data
         *   @param error (std::vector<Double>*) error std::vector imported from D4Matrix data
         *   @retval 0 No trouble.
         *   @retval -1 Failes to calculate the ranges for the axes.
         */
    bool  DumpD4MatIntoVect( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings,  bool isAve,
                            std::vector<Double> *ax1, std::vector<Double> *ax2, std::vector<Double> *ax3, std::vector<Double> *ax4, std::vector<Double> *intensity, std::vector<Double> *error);
       //!< Put D4Matrix into given vectors on memory.
        /*!< The order of intensity ::
         *   for ihw in range(hws.size()):
         *       for i1 in range(ax1.size()):
         *           for i2 in range(ax2.size()):
         *               for i3 in range(ax3.size()):
         *                   ind = i3 + (ax3.size() * i2) + (ax3.size() * ax2.size() * i1) + (ax3.size() * ax2.size() * ax1.size() * ihw)
         *                   i1, i2, i3, ihw, intensity[ind], error[ind]
         *
         *   DumpD4MatToFile( a1range, a2range, a3range, a4range, def_axes, foldings, isAve,
         *                    ax1, ax2, ax3, hws, intensity, error );
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param def_axes (PyObject str list)   role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (PyObject float list) folding values, [] means [ -1, -1, -1, -1]
         *   @param isAve  (bool) If False, the intensity of a bin is the summation of the counts.
         *   @param ax1 (std::vector<Double>*) ax1 std::vector imported from D4Matrix data
         *   @param ax2 (std::vector<Double>*) ax2 std::vector imported from D4Matrix data
         *   @param ax3 (std::vector<Double>*) ax3 std::vector imported from D4Matrix data
         *   @param hws (std::vector<Double>*) hw std::vector imported from D4Matrix data
         *   @param intensity (std::vector<Double>*) intensity std::vector imported from D4Matrix data
         *   @param error (std::vector<Double>*) error std::vector imported from D4Matrix data
         *   @retval 0 No trouble.
         *   @retval -1 Failes to calculate the ranges for the axes.
         */
    std::vector<FILE*> fs_list;
    std::vector< std::vector<Double> > range_list;
    std::vector<UInt4> NumBin;
    std::vector<std::string> name_of_blocks;
    std::vector<UInt4> index_of_blocks;
    std::vector<std::string> file_components;
    std::vector<UInt4> size_of_Ax;
    std::vector<std::string> ax_titles;
    std::vector<std::string> ax_units;
    std::vector<Double> _hwInfoForVirtualMatrix;
    virtual void _CalcVirtualAngleInfo( std::string wfile, std::string dfile );
    virtual void _CalcVirtualAngleInfo( ElementContainerMatrix* _ecm );
    virtual bool SetRunNoForVirtualMatrix( UInt4 runNo, PyObject* hwInfo );
        //!< Sets the run number for the virtual matrix
        /*!<
         *   @param runNo (UInt4) The run number
         *   @param hwInfo (PyObject float list) hw information [Ei, delta_hw, hw_min, hw_max]
         *   @retval true succeeded.
         *   @retval false failed.
         */
    void AllocateVirtualMat( std::vector<Double> latticeConst, std::vector<Double> Uvec, std::vector<Double> Vvec, std::vector<Double> rotateSteps,
                             std::vector<Double> viewAxes, std::vector<Double> hwInfo, std::vector<Double> phiSteps,
                             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 );
        //!< Makes Virtual Matrix in memory
        /*!<
         *   AllocateVirtualMat( latticeConst, Uvec, Vvec, rotateSteps, viewAxes, phiSteps , a1range, a2range, a3range, a4range, titles )
         *   @param latticeConst (std::vector<Double>) Lattice Constant [a,b,c,alpha,beta,gamma]
         *   @param Uvec         (std::vector<Double>) U-vector
         *   @param Vvec         (std::vector<Double>) V-vector
         *   @param rotateSteps  (std::vector<Double>) Steps for rotation [ 1, -5 ] means -5 degree rotation aroung Y axis
         *   @param viewAxes     (std::vector<Double>) List of matrix for axes projection
         *   @param hwInfo       (std::vector<Double>) hw info [Ei, delta_hw, hw_min, hw_max]
         *   @param phiStep      (std::vector<Double>) List of angles for sample orientations
         *   @param a1range (std::vector<Double>)  first axis range  [min, max]
         *   @param a2range (std::vector<Double>)  second axis range [min, max]
         *   @param a3range (std::vector<Double>)  third axis range  [min, max]
         *   @param a4range (std::vector<Double>)  fourth axis range [min, max]
         *   @param titles  (std::vector<std::string>)    Titles
         *   @param units   (std::vector<std::string>)    Units
         *   @retval None
         */
    bool AllocateVirtualMat( PyObject* latticeConst, PyObject* Uvec, PyObject* Vvec, PyObject* rotateSteps,
                             PyObject* viewAxes, PyObject* phiSteps,
                             PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* titles, PyObject* units );
        //!< Makes Virtual Matrix in memory
        /*!<
         *   AllocateVirtualMat( latticeConst, Uvec, Vvec, rotateSteps, viewAxes, phiSteps , a1range, a2range, a3range, a4range, titles )
         *   @param latticeConst (PyObject float list) Lattice Constant [a,b,c,alpha,beta,gamma]
         *   @param Uvec         (PyObject float list) U-vector
         *   @param Vvec         (PyObject float list) V-vector
         *   @param rotateSteps  (PyObject float list) Steps for rotation [ 1, -5 ] means -5 degree rotation aroung Y axis
         *   @param viewAxes     (PyObject float list) List of matrix for axes projection
         *   @param hwInfo       (PyObject float list) hw info [Ei, delta_hw, hw_min, hw_max]
         *   @param phiStep      (PyObject float list) List of angles for sample orientations
         *   @param a1range (PyObject float list)  first axis range  [min, max]
         *   @param a2range (PyObject float list)  second axis range [min, max]
         *   @param a3range (PyObject float list)  third axis range  [min, max]
         *   @param a4range (PyObject float list)  fourth axis range [min, max]
         *   @param titles  (PyObject str list)    Titles
         *   @param units   (PyObject str list)    Units
         *   @retval True succeeded.
         *   @retval False failed.
         */
    std::vector<Double> EstimateRangeOfVirtualMat( std::vector<Double> latticeConst, std::vector<Double> Uvec, std::vector<Double> Vvec, std::vector<Double> rotateSteps,
                                             std::vector<Double> viewAxes, std::vector<Double> hwInfo, std::vector<Double> phiSteps );
        //!< Estimates range of Virtual Matrix
        /*!<
         *   EstimateRangeOfVirtualMat( latticeConst, Uvec, Vvec, rotateSteps, viewAxes, phiSteps )
         *   @param latticeConst (std::vector<Double>) Lattice Constant [a,b,c,alpha,beta,gamma]
         *   @param Uvec         (std::vector<Double>) U-vector
         *   @param Vvec         (std::vector<Double>) V-vector
         *   @param rotateSteps  (std::vector<Double>) Steps for rotation [ 1, -5 ] means -5 degree rotation aroung Y axis
         *   @param viewAxes     (std::vector<Double>) List of matrix for axes projection
         *   @param phiStep      (std::vector<Double>) List of angles for sample orientations
         *   @return ranges for all axes (std::vector<Double>)
         */
    PyObject* EstimateRangeOfVirtualMat( PyObject* latticeConst, PyObject* Uvec, PyObject* Vvec, PyObject* rotateSteps,
                                             PyObject* viewAxes, PyObject* phiSteps );
        //!< Estimates range of Virtual Matrix
        /*!<
         *   EstimateRangeOfVirtualMat( latticeConst, Uvec, Vvec, rotateSteps, viewAxes, phiSteps )
         *   @param latticeConst (PyObject float list) Lattice Constant [a,b,c,alpha,beta,gamma]
         *   @param Uvec         (PyObject float list) U-vector
         *   @param Vvec         (PyObject float list) V-vector
         *   @param rotateSteps  (PyObject float list) Steps for rotation [ 1, -5 ] means -5 degree rotation aroung Y axis
         *   @param viewAxes     (PyObject float list) List of matrix for axes projection
         *   @param phiStep      (PyObject float list) List of angles for sample orientations
         *   @return ranges for all axes (PyObject float list)
         */
    void SliceVirtualMat( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings );
        //!< Slices the virtual matrix
        /*!<
         *   SliceVirtualMat(a1range, a2range, a3range, a4range, def_axes, foldings);
         *   @param a1range (std::vector<Double>) first axis range  [min, max]
         *   @param a2range (std::vector<Double>) second axis range [min, max]
         *   @param a3range (std::vector<Double>) third axis range  [min, max]
         *   @param a4range (std::vector<Double>) fourth axis range [min, max]
         *   @param def_axes (std::vector<std::string>) role of each axis, for example [ "X", "Y", "T", "T" ]
         *   @param foldings (std::vector<std::string>) folding values, [] means [ -1, -1, -1, -1]
         *   @retval None
         */
    bool isVirtualMode(){ return _isVirtual; }
        //!< Checks whether the data is the virtual mode or not
        /*!<
         *   @param None
         *   @retval true the data is the virtual mode.
         *   @retval false the data is not virtual mode.
         */
    bool isDirectGeometry(){ return _isDirectGeometry; }
        //!< Checks whether the type of the instrument for the data is the direct geometry or not
        /*!<
         *   @param None
         *   @retval true the direct geometry
         *   @retval false the inverted geometry
         */
    static const Int4 ROTATE_AXIS_X;
    static const Int4 ROTATE_AXIS_Y;
    static const Int4 ROTATE_AXIS_Z;
};

#endif
