#ifndef UTSUSEMIECSCLIPPER
#define UTSUSEMIECSCLIPPER

#include <math.h>

#include "UtsusemiHeader.hh"
#include "HistogramBinToPoint.hh"
#include "DoubleBinArrange.hh"
#include "StringTools.hh"

//////////////////////////////////
// UtsusemiEcClipper
//////////////////////////////////

//! Clip and integrate data
/*! 
 *  Clip specified region from ElementContainerArray
 *  and integrate them to a ElementContainer,
 *  while exclude masked point. 
 *  
 *  cd = Manyo.UtsusemiEcsClipper( tea ) <- ElementContainerArray
 *  ecm = TPC.Execute(0.05) <-- give Q step
 *  
 */
class UtsusemiEcsClipper:
    public OperatorBase< ElementContainerArray, ElementContainerArray >
{
private:
    bool _debugMode;
    bool _invalid;           // Given data is invalid flag
    Double _ei;              // Incident Energy. in case og TOF, this value is 0.0.
    int _numMask;            // Number of Masked regions 
    string _runNo;           // Run No. in Header
    vector<string> _keys;    // preserve original keys
    vector<string> _units;   // preserve original units
    vector< pair<string,UInt4> > _givenAxesKeys;// keys given by SetAxes and index of type
                                                // 0: vector<Double> in EC,
                                                // 1: Int4 in EC Header, 2: Double in EC Header
                                                // 3: vector<Int4> (size of 2) in EC Header
                                                // 4: vecotr<Double>(size of 2) in EC Header
                                                // 5: vector<Int> (size same as ECs)in ECA Header
                                                // 6: vector<Double> (size same as ECs)in ECA Header
                                                // 7: vector<Int> (size same as ECs+1)in ECA Header
                                                // 8: vector<Double> (size same as ECs+1)in ECA Header
    
    
    vector< vector<Double> > _regions;    // Assembly of clip region, each region will create an ElementContainer
    
    // 2D Map data
    vector< vector<Double> > _anisoBin2d;    // X-axis points (TOF or Q values for Energy Data)
    vector< vector<Double> > _ints2d;        // Intencity of Neutron
    vector< vector<Double> > _errs2d;        // Errors
    vector<Double> _isoBin;                  // Y-axis points (Indices for TOF, or Energy), same for all Histogram
                                             // 
    vector<Double> _Angles;                  // Polar Angles(deg) in header

    ElementContainerArray* _eca_res;

    void _makeHeader(Double ,Double, bool, ElementContainer& , bool);    // 
    void _initData(Double ei);     // 
    void _MakeRectMap();            // Make 2D Map data for TOF
    void _MakePowderMap(Double ei);     // Make 2D Map data for Q data
    void _MakeRectYbinCutData(vector<Double> , bool , ElementContainer&);
    void _MakeRectXbinCutData(vector<Double> , bool , ElementContainer&);
    void _MakeRectDiagCutData(vector<Double>, Double, Double, bool, ElementContainer& );
                                                                        // Make a histogram of free cut on RectMap
    void _MakeQbinCutData(vector<Double>, bool, ElementContainer&);        // Make a histogram which xbin is Q
    void _MakeEbinCutData(vector<Double>, bool, ElementContainer&);        // Make a histogram which xbin is Energy
    void _Rebin(UInt4, vector<Double>&, vector<Double>&,vector<Double>&);    // Rebinning of aniso Axis
    void _AddAngle(HeaderBase* hh, Int4 index0, Int4 index1);           // Set Polar Angle to Header

    void _initialize();
    string _MessageTag;
    StringTools* _st;
public:
    UtsusemiEcsClipper();
        //!< Constructor
        /*!<
         */
    ~UtsusemiEcsClipper();
        //!< Destructor
        /*!<
         */
    UtsusemiEcsClipper( ElementContainerMatrix* ecm, string keyOfX="", string keyOfY="" );
        //!< Constructor
        /*!<
         *   @param eca   Target ElementContainerMatrix (TOF or Energy/Q data)
         *   @param keyOfX   key used as X axis (same as SetAxes) 
         *   @param keyOfY   key used as Y axis (same as SetAxes) 
         */
    UtsusemiEcsClipper( ElementContainerArray* eca, string keyOfX="", string keyOfY="" );
        //!< Constructor
        /*!<
         *   @param eca   Target ElementContainerArray (TOF or Energy/Q data)
         *   @param keyOfX   key used as X axis (same as SetAxes) 
         *   @param keyOfY   key used as Y axis (same as SetAxes) 
         */
    void SetAxes(string keyOfX="", string keyOfY="", bool doInitData=true);
        //!< Set Axes keys
        /*!< This sets keys to be used as X-axis values or Y-axis vector.
         *   keyX must be included in the Header of ECA or the Header of EC as Int4, Double, 
         *   vector<Int4> or vectro<Double> which size is same as the number of ECs or plus 1.
         *   keyY must be one of the vectors in EC.
         *   If not set or invalid keys, X axis is made from  "XRANGE" vector in the Header of EC 
         *   and Y axis from EC.PutX()
         *  
         *   @param keyOfX      key used as X axis 
         *   @param keyOfY      key used as Y axis
         *   @param doInitData  whether executing initData or not
         *   @retval None
         */
    void SetMask(Double x0, Double y0, Double x1, Double y1);
        //!< Add mask region
        /*!<
         *   @param x0   minimam Tof or Energy value
         *   @param y0   minimam pixel ID or Q value
         *   @param x1   maximam Tof or Energy value
         *   @param y1   maximam pixel ID or Q value
         */
    bool IsInvalid(){return _invalid;};
        //!< Return if valid data
        /*!<
         *   @param None
         *   @returnValue   true or false
         */
    void ClearMask(void);
        //!< Clear vector of Mask region 
        /*!<
         *   Clear Mask region vector
         *   @param None
         */
    void SetClipRegion(Double x0, Double y0, Double x1, Double y1);
        //!< Add mask region
        /*!<
         *   @param x0   minimam Tof or Energy value
         *   @param y0   minimam pixel ID or Q value
         *   @param x1   maximam Tof or Energy value
         *   @param y1   maximam pixel ID or Q value
         */
    void ClearClipRegion(void);
        //!< Clear vector of clip region
        /*!<
         *   Clear Mask region vector
         *   @param None
         */
    ElementContainerArray ExecInteg(bool average, int axis, Double width=0.0, Double bin=0.0);
        //!< Integrate (or calcurate average) each region
        /*!<
         *   X axis will be TOF or Energy
         *   @param mode  Set if true: average or false:integration
         *   @param axis  Set axis 0: TOF or Energy 1:index  or Q 2:Free cutting
         *   @param width Set integ width on free cutting
         *   @param bin   Set bin of free cutting line
         */
    ElementContainerArray CutAlongX( bool average=true ){ return ExecInteg( average, 1 ); }
    ElementContainerArray CutAlongY( bool average=true ){ return ExecInteg( average, 0 ); }
    ElementContainerArray CutDiagonal( Double width, Double bin, bool average=true ){ return ExecInteg( average, 2, width, bin ); }
};
#endif
