#ifndef SASTREATQHKLWITHUB
#define SASTREATQHKLWITHUB

#include "Header.hh"
#include "CppToPython.hh"
#include "ManipulatorBase.hh"
#include "ElementContainerMatrix.hh"
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_blas.h>
#include "UtsusemiHeader.hh"
//////////////////////////////////
// Treatment of Q(h,k,l) with UB matrix for Analysis on SAS
/////////////////////////////////

//! Function to calculate QxQyQz to Q(hkl)
/*!
 *
 *
 *
 *
 */

class TreatQhklWithUB :
    public ManipulatorBase< ElementContainerMatrix >
{
private:
    /** Axes Conversion */
    std::vector<Double> _UBmat;
    std::vector<Double> _ViewAxes;
    std::vector<std::string> _Labels;
    std::vector<std::string> _Keys;
    std::vector<std::string> _Units;
    /** Slicing */
    UInt4 _indSliceX;
    UInt4 _indSliceY;
    UInt4 _indSliceT;
    std::vector<Double> _Qxbin;
    std::vector<Double> _Qybin;
    std::vector< std::vector<double> > _IQ;
    std::vector< std::vector<double> > _Error;
    std::vector< std::vector<double> > _Count;
    std::pair<double,double> MakeBinsZeroCenter( double s_val, double e_val, double step );

    void Initialize();
    std::string _MessageTag;
    bool _SetVectToMatrix( std::vector<double>, gsl_matrix* );
    bool _SetViewVectToMatrix( std::vector<double>, gsl_matrix* );
    bool _CalcInverseMatrix( gsl_matrix* , gsl_matrix* );

    CppToPython* _CTP;

public:
    TreatQhklWithUB();
        //!< Constructor
        /*!<
         *
         */
    TreatQhklWithUB( ElementContainerMatrix* ecm );
        //!< Constructor
        /*!<
         *  @param ecm ElementContainerMatrix for the target
         */
    ~TreatQhklWithUB();
        //!< Destructor
        /*!<
         *
         */
    bool SetUBmatrix( std::vector<Double> ubmat );
        //!< Set UBmatrix
        /*!< Give UB matrix to be used for Qhkl calculation
         *  given UB matrix:
         *  |Qx|   | ubmat[0], ubmat[1], ubmat[2] | |H|
         *  |Qy| = | ubmat[3], ubmat[4], ubmat[5] | |K|
         *  |Qz|   | ubmat[6], ubmat[7], ubmat[8] | |L|
         *
         *  @param ubmat (std::vector<Double>) UB matrix
         *  @retval true   succeeded.
         *  @retval false  failed.
         */
    bool SetUBmatrix( PyObject* );
    bool SetViewAxes( std::vector<Double> vaxes);
    bool SetViewAxes( PyObject* Q1, PyObject* Q2, PyObject* Q3);
        //!< Set View Axes
        /*!<
         *   @param Q1 (list) [H,K,L]
         *   @param Q2 (list) [H,K,L]
         *   @param Q3 (list) [H,K,L]
         *   @retval true   succeeded.
         *   @retval false  failed.
         */
    bool SetViewAxesLabels( std::string Q1Label, std::string  Q2Label, std::string Q3Label,
                    std::string Q1Unit="1/Ang", std::string Q2Unit="1/Ang", std::string Q3Unit="1/Ang" );
        //!< Set View Axes labels
        /*!<
         *   @param Q1Label (std::string)
         *   @param Q2Label (std::string)
         *   @param Q3Label (std::string)
         *   @param Q1Unit  (std::string)
         *   @param Q2Unit  (std::string)
         *   @param Q3Unit  (std::string)
         *   @retval true   succeeded.
         *   @retval false  failed.
         */
    bool Projection();
    bool SetSliceAxes( std::string Q1, std::string Q2, std::string Q3);
        //!< Set Axes for slicing
        /*!<
         *   @param Q1 (std::string) type of Q1 : "X","Y","T"
         *   @param Q2 (std::string) type of Q2 : "X","Y","T"
         *   @param Q3 (std::string) type of Q3 : "X","Y","T"
         *   @retval true   succeeded.
         *   @retval false  failed.
         */
    std::vector<Double> PutSliceMaxRange();
    PyObject* PutSliceMaxRangeList(){ return _CTP->VectorToList( PutSliceMaxRange() ); }
    bool Slice( ElementContainerArray* eca, std::vector<Double> Xrange, std::vector<Double> Yrange, std::vector<Double> Trange);
        //!< Slicing
        /*!<
         *   @param eca    (ElementContainerArray) give empty ElementContainerArray to store result
         *   @param Xrange (std::vector<Double>) Plot X range : <min>,<max>,<bin width>
         *   @param Yrange (std::vector<Double>) Plot Y range : <min>,<max>,<bin width>
         *   @param Thick  (std::vector<Double>) Thickness : <min>,<max>
         *   @retval true   succeeded.
         *   @retval false  failed.
         */
    bool Slice( ElementContainerArray* , PyObject* , PyObject* , PyObject* );


    std::vector<Double> InverseMatrix( std::vector<Double> a );
    PyObject* PutQKeysList(){ return _CTP->VectorStringToList( _Keys ); }

    static const std::string SAS_TREATQHK_KEYS;
    static const std::string SAS_TREATQHK_LABELS;

};
#endif
