#ifndef UTSUSEMISQECALCXTALPARAMS
#define UTSUSEMISQECALCXTALPARAMS

#include "Header.hh"
#include "UtsusemiHeader.hh"
#include "BoostXmlParser.hh"
#include "StringTools.hh"
#include "CppToPython.hh"

////////////////////////////////////
// UtsusemiSqeCalc
///////////////////////////////////

//!
/*!
 *
 */

class UtsusemiSqeCalcXtalParams
{
private:
    void Initialize( std::string filepath="" );
    BoostXmlParser* _xml;
    StringTools* _st;
    bool _ConvPyListToDoubleVect( PyObject *ax, std::vector<double> *ret, UInt4 s );
    bool _isUBpriority;
    std::vector<Double> _latticeConsts;
    std::vector<Double> _uVec;
    std::vector<Double> _vVec;
    std::vector<Double> _ubMatrix;
    std::vector< std::pair<std::string,Double> > _rotateSteps;
    Map< std::pair< std::string, std::vector<Double> > > _plotAxis;
    Map< std::pair<std::vector<Double>,std::vector<std::string> > > _projectionAxes; // key=["0","1","2","3"]
    std::pair< std::string, std::vector<Int4> > _diagFolding;

public:
    UtsusemiSqeCalcXtalParams( std::string filepath="" );
        //!< Constructor
        /*!<
         *   @return None
         */
    ~UtsusemiSqeCalcXtalParams();
        //!< Destructor
        /*!<
         *   @return None
         */

    std::string filePath;
    std::string version;
    std::string name;

    bool SetLatticeConstants( Double a, Double b, Double c, Double alpha, Double beta, Double gamma );
        //!< Sets crystal lattice parameters
        /*!< This sets crystal lattice consts with individual
         *   @param a     (double) Lattice constants a
         *   @param b     (double) Lattice constants a
         *   @param c     (double) Lattice constants a
         *   @param alpha (double) Lattice constants alpha
         *   @param beta  (double) Lattice constants beta
         *   @param gamma (double) Lattice constants gamma
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetLatticeConstants( PyObject* LC );
        //!< Sets crystal lattice parameters
        /*!< This sets crystal lattice consts by python list object
         *   @param LC    (list of float) Lattice constants [<a>,<b>,<c>,<alpha>,<beta>,<gamma>]
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */

    bool SetUVvector( Double ux, Double uy, Double uz, Double vx, Double vy, Double vz, bool isPriority=true );
        //!< Sets crystal orientation
        /*!<
         *   @param ux    (double) U-vector Uh
         *   @param uy    (double) U-vector Uk
         *   @param uz    (double) U-vector Ul
         *   @param wx    (double) V-vector Vh
         *   @param wy    (double) V-vector Vk
         *   @param wz    (double) V-vector Vl
         *   @param isPriority (bool) true: UV-vector is used to calculate projection instead of UBmatrix
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetUVvector( PyObject* UV, PyObject* VV, bool isPriority=true );
        //!< Sets crystal orientation
        /*!<
         *   @param UV    (list of float) U-vector [<Uh>,<Uk>,<Ul>]
         *   @param VV    (list of float) V-vector [<Vh>,<Vk>,<Vl>]
         *   @param isPriority (bool) true: UV-vector is used to calculate projection instead of UBmatrix
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetUBMatrix( PyObject* UB, bool isPriority=true );
        //!< Sets UB matrix
        /*!<
         *   @param UB    (list of float) U-vector [<UB11>,<UB12>,<UB13>,<UB21>,<UB22>,<UB23>,<UB31>,<UB32>,<UB33>,]
         *   @param isPriority (bool) true: UBmatrix is used to calculate projection instead of UV-vectors
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool AddRotationStep( std::string axis, double degree );
        //!< Sets Rotation angle
        /*!<
         *   @param axis    (std::string) "Y" or "X" or "Z"
         *   @param degree  (double) angle [degree]
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetRotationSteps( std::string steps );
        //!< Sets Rotation angle
        /*!<
         *   @param steps    (std::string) format "<Axis>:<degree>[,<Axis>:<degree>,...]"
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetSampleInfoToData( ElementContainerMatrix* ecm );
        //!< Sets Sample information to header in ElementContainerMatrix
        /*!<
         *   @param ecm  (ElementContainerMatrix)
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool ClearRotationStep();
        //!< Clears Rotation steps
        /*!<
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetProjectionAxis( std::string _id, double va, double vb, double vc, double ve, std::string title, std::string unit );
        //!< Sets Projection information for a axis
        /*!<
         *   @param _id   (std::string) id of Ax
         *   @param va    (double) a* value of corrdinate axis for projection
         *   @param vb    (double) b* value of corrdinate axis for projection
         *   @param vc    (double) c* value of corrdinate axis for projection
         *   @param ve    (double) Energy value of corrdinate axis for projection
         *   @param title (std::string) label of corrdinate axis
         *   @param unit  (std::string) unit of corrdinate axis
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetProjectionAxes(  PyObject* arg_ax1, PyObject* arg_ax2, PyObject* arg_ax3, PyObject* arg_ax4 );
        //!< Sets Projection information for a axis
        /*!< Given list is like [1.0,0.0,0.0,0.0,"Qh","rlu"]
         *   @param arg_ax1 (list) [<a* value>,<b* value>,<c* value>,<energy value>,"<label>","<unit>"]
         *   @param arg_ax2 (list) [<a* value>,<b* value>,<c* value>,<energy value>,"<label>","<unit>"]
         *   @param arg_ax3 (list) [<a* value>,<b* value>,<c* value>,<energy value>,"<label>","<unit>"]
         *   @param arg_ax4 (list) [<a* value>,<b* value>,<c* value>,<energy value>,"<label>","<unit>"]
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetSliceAxis( std::string _id, std::string _type, double _min, double _max, double _width, double _folding );
        //!< Sets slicing information for a axis
        /*!<
         *   @param _id   (std::string) id of Ax
         *   @param _type (std::string) type of Ax : "X","Y" or "T"
         *   @param _min  (double) minimum value of Ax
         *   @param _max  (double) maximum value of Ax
         *   @param _width (double) width value of Ax
         *   @param _folding (double) folding info of Ax
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetSliceAxes( PyObject* Ax1, PyObject* Ax2, PyObject* Ax3, PyObject* Ax4, bool isForced=false );
        //!< Sets slicing information
        /*!< "X" and "Y" axis : ["X",<min>,<max>,<width>]
         *   "T" axis : ["T",<min>,<max>]
         *
         *   @param Ax1   (list) List for Ax1
         *   @param Ax2   (list) List for Ax2
         *   @param Ax3   (list) List for Ax3
         *   @param Ax4   (list) List for Ax4
         *   @param isForced (bool) true: ignore the number of axis types ("X","Y" and "T")
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetDiagFolding( std::string _type, UInt4 ax1, UInt4 ax2 );
        //!< Sets folding information for a axix
        /*!<
         *   @param type  (std::string)
         *   @param ax1   (UInt4)
         *   @param ax2   (UInt4)
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SetDiagFolding( PyObject* Dfold );

    static const UInt4 TOXML_LATTICECONST;
    static const UInt4 TOXML_ORIENTATION;
    static const UInt4 TOXML_PROJECTION;
    static const UInt4 TOXML_SLICINGINFO;
    static const UInt4 TOXML_DIAGONALFOLD;
    static const UInt4 TOXML_UBMATRIX;
    static const UInt4 TOXML_ALL;
    bool LoadFile( std::string filepath, UInt4 flags=TOXML_ALL );
        //!< Loads XtalParams
        /*!<
         *   @param filepath (std::string) full path to XtalParam.xml
         *   @param flags    (UInt4) information to read parameters pertially
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool SaveFile( std::string filepath, UInt4 flags=TOXML_ALL );
        //!< Save XtalParams
        /*!<
         *   @param filepath (std::string) full path to XtalParam.xml
         *   @param flags    (UInt4) information to save parameters pertially
         *   @retval true   no trouble
         *   @retval false  trouble happened.
         */
    bool DecodeFromXml( std::string conts, UInt4 flags);
    bool EncodeToXml(UInt4 flags);
    std::string PutXmlString(UInt4 flags=TOXML_ALL);
        //!< Put XtalParams info as std::string
        /*!<
         *   @param flags    (UInt4) information to save parameters pertially
         *   @retval std::string XtalParam std::string
         */


    void Dump();

    void SetExampleParams();

    std::vector<Double> PutLatticeConsts(){ return _latticeConsts; }
    std::vector<Double> PutUVector(){ return _uVec; }
    std::vector<Double> PutVVector(){ return _vVec; }
    std::vector<Double> PutUBMatrix(){ return _ubMatrix; }
    bool PutPriorigy(){ return _isUBpriority; }
    std::vector<Double> PutRotateSteps();
    std::vector<Double> PutViewAxes();
    std::vector<std::string> PutViewAxesLabels();
    std::vector<std::string> PutViewAxesUnits();
    std::vector<Double> PutAxRange( UInt4 ind, bool useAxTypeInfo=false );
    std::vector<std::string> PutAxType();
    std::vector<std::string> PutAxLabels();
        //!< Returns axes labels for slicing.
        /*!< std::vector of 4 labels, [0]:Label for "X" axis, [1]:Label for "Y" axis, [2],[3]:labels for "T"
         *
         *   @retval std::vector<std::string>
         */
    std::vector<std::string> PutAxUnits();
        //!< Returns axes units for slicing.
        /*!< std::vector of 4 units, [0]:unit for "X" axis, [1]:unit for "Y" axis, [2],[3]:units for "T"
         *
         *   @retval std::vector<std::string>
         */
    std::vector<Double> PutFolding();
    std::vector<UInt4> PutDiagFolding();
};

#endif
