#ifndef WIRINGINFOCONVERSIONDICTIONARY
#define WIRINGINFOCONVERSIONDICTIONARY

#include <algorithm>
#include "Map.hh"
#include "UtsusemiHeader.hh"
#include "UtsusemiUnitConverter.hh"
#include "UtsusemiTofOriginCorrection.hh"
#include "WiringInfoDataBase.hh"

////////////////////////////////////////
// WiringInfoConversionTemplate
////////////////////////////////////////

//! Template for methods to convert from TOF
/*!
 *
 *
 */
class WiringInfoConversionTemplate
{
private:
    UtsusemiUnitConverter* _UUC;

public:
    WiringInfoConversionTemplate();
        //!< Constructor
        /*!<
         */
    WiringInfoConversionTemplate( const WiringInfoConversionTemplate& obj);
        //!< Copy Constructor
        /*!<
         */
    ~WiringInfoConversionTemplate();
        //!< Destructor
        /*!<
         */
    Int4 ConvType;
    std::string KeyCode;
    std::vector<UInt4> NumOfParams;
    std::string Memo;
    bool isReversed;
    bool isRequiredPixelPosi;
    bool (*CheckParamsFunc)(std::vector<Double>, UtsusemiUnitConverter* );
    std::vector<Double> (*PutTofFunc)(std::vector<Double>*, std::vector<Double>*, std::vector<Double>*, std::vector<Double>*, UtsusemiUnitConverter* );
    std::vector<Double> (*PutXaxisFunc)(std::vector<Double>,  Double );
    std::vector<Double> (*PutLambdaFunc)(std::vector<Double>*, std::vector<Double>*, std::vector<Double>*, std::vector<Double>*, UtsusemiUnitConverter* );
    bool CheckParams( std::vector<Double> params );
    std::vector<Double> PutTofBin(std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams );
    std::vector<Double> PutXaxisVect(std::vector<Double> params, Double tof_offset=0.0);
    std::vector<Double> PutLambdaVec(std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams );
    std::vector< std::pair< std::string,std::string > > LabelsOfEC;

};

////////////////////////////////////////
// WiringInfoConversionDictionary
////////////////////////////////////////

//! Methods for unit conversion on histogram creation
/*!
 *  - puts X-axis bin for direct conversion from event to histogram
 *  - puts TOF bin for histogram according to given conversion
 *  - puts lambda values for each X axis
 *  tt = WiringInfoConversionDictionary()
 *  tt.SetParams( conv_type, params )
 *  x=tt.PutXaxis()
 *  tof_bin = tt.PutTofBin( pixel_id )
 */

class WiringInfoConversionDictionary
{

private:
    UtsusemiTofOriginCorrection* _UTO;

protected:
    std::string _KeyCode;
    std::vector<Double> _Xaxis;
    std::vector<Double> _ConvParams;
    std::string _MessageTag;
    Double _L1;
    std::vector<Double> _SamplePosition;
    std::vector< std::vector<Double>* > _pixelPositionVect;
    std::vector< std::vector<Double> > _timeFocParam;
    std::vector< WiringInfoConversionTemplate* > Dict;
    void Initialize();
    void SetDict();
    void _Clear();
    WiringInfoConversionTemplate* _Search( std::string keycode );
    WiringInfoConversionTemplate* _Search( Int4 convtype );
    std::vector<Double> _PutTofBinOrLambda( UInt4 _pixel_id, bool isTof );

    bool isSetTimeDependBackGroundRegion; //[inamura 160709]

public:
    WiringInfoConversionDictionary();
        //!< Constructor
        /*!<
         */
    ~WiringInfoConversionDictionary();
        //!< Destructor
        /*!<
         */
    bool isValidConvType( Int4 convtype );
    Int4 PutConvType( std::string keycode );
        //!< Puts ConvType Number from key code
        /*!<
         *   @param keycode (std::string) key code for a type of direct conversion
         *   @return ConvType (Int4)
         */
    std::string PutKeyCode( Int4 convtype );
        //!< Puts Key code from ConvType Number
        /*!<
         *   @param convtype (Int4) conversion type number
         *   @return KeyCode (std::string)
         */
    bool CheckParams( Int4 convtype, std::vector<Double> params );
    std::vector<UInt4> PutNumOfParams( std::string keycode );
    std::vector<UInt4> PutNumOfParams( Int4 convtype );
        //!< Puts the number of parameters for given conv type.
        /*!<     PutNumOfParams( std::string keycode );
         *       PutNumOfParams( Int4 convtype );
         *   @param keycode  (std::string)
         *   @param convtyep (Int4)
         *   @return the number of parameters (std::vector<UInt4>)
         */
    std::string PutMemo( std::string keycode );
        //!< Puts Memo for given ConvType
        /*!<
         *   @param keycode (std::string) key code for a type of direct conversion
         *   @return Memo (std::string)
         */
    bool isReverseXaxis( std::string keycode );
    bool isReverseXaxis( Int4 convtype );
        //!< Returns whether converted tof is required to reverse
        /*!<     isReverseXaxis( std::string keycode );
         *       isReverseXaxis( Int4 convtype );
         *   @param keycode  (std::string)
         *   @param convtyep (Int4)
         *   @return  (bool)
         */
    bool SetParams( std::string keycode, std::vector<Double> *params );
    bool SetParams( Int4 convtype, std::vector<Double> *params );
        //!< Sets conv type and its parameters
        /*!<     SetParams( std::string keycode );
         *       SetParams( Int4 convtype );
         *   @param keycode  (std::string)
         *   @param convtyep (Int4)
         *   @param params   (std::vector<Double>*)
         *   @retval true  : succeed setting
         *   @retval false : fail setting
         */
    std::vector<Double> PutParams( Int4 convtype );
        //!< Puts parametes for given conv type
        /*!<     PutParams( Int4 convtype );
         *   @param convtyep (Int4)
         *   @return  params (std::vector<Double>*)
         */
    std::vector<Double> PutXaxis( Double tof_offset=0.0 );
        //!< Puts X axis for given conv type
        /*!<     PutXaxis();
         *   @param tof_offset (Double)
         *   @return  X axis (std::vector<Double>)
         */
    std::vector<Double> PutTofBin( UInt4 pixelId );
    std::vector<Double> PutTofBin( UInt4 pixelId, Int4 convtype, std::vector<Double> *params );
        //!< Puts Tof Binning for given conv type
        /*!<  (1)   PutTofBin( UInt4 pixelId )
         *    (2)   PutTofBin( UInt4 pixelId, Int4 convtype, std::vector<Double> *params )
         *   Both return TOF binning of given pixel ID.
         *   (1) requires SetParams(...) before.
         *   (2) includes SetParams(...), so you must give convtype and params.
         *   @param pixelId   (UInt4)
         *   @param convtype  (Int4)
         *   @param params    (std::vector<Double>*)
         *   @return  TOF binning (std::vector<Double>)
         */
    std::vector<Double> PutLambda( UInt4 pixelId );
        //!< Puts Lambda values for given pixel ID and its X axis values
        /*!<     PutLambda( UInt4 pixelId );
         *   @param pixelId (UInt4)
         *   @return  Lambda values (std::vector<Double>)
         */
    void SetPixelPosition( std::vector< std::vector<Double>* > pixelPositionVect );
    void SetTimeFocusingParam( std::vector< std::vector<Double> >* timeFocusParam );
    void SetL1( Double L1 );
    void SetSamplePosition( Double px, Double py, Double pz );
    std::pair<std::string,std::string> PutXLabel( Int4 convtype=-1 );
    std::pair<std::string,std::string> PutYLabel( Int4 convtype=-1 );
    std::pair<std::string,std::string> PutELabel( Int4 convtype=-1 );

    bool SetTofShift( UInt4 cType );
    bool SetTofShift( UInt4 cType, std::vector<Double> params );

    void SetTimeDependBackGroundRegion( Double tof0=0., Double tof1=0. ); //[inamura 160809]
    std::vector< std::vector<Double>* >* TimeDependBackGroundRegion;           //[inamura 160809]
    bool SetFrameBoundaryInfoList( UInt4 frameNo, Double boundary, std::string unit );
    std::vector< std::pair<UInt4,Double>* > FrameBoundaryInfoList; /** first: calculated frameNo, second: calculated boundary tof [inamura 170410]  */

    // ConvType = 1 : List of histogram
    static bool CheckParamsType001( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType001( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType001( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType001( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 2 : delta T const
    static bool CheckParamsType002( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType002( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType002( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 3 : (delta T)/T const
    static bool CheckParamsType003( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType003( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType003( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 12 : delta T const with time focusing, ConvType = 13 : (delta T)/T const with time focusing
    static std::vector<Double> PutTofBinConvType012Type013( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType012Type013( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 20 : Energy Transfer
    static bool CheckParamsType020( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType020( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType020( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType020( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 21 : Energy
    static bool CheckParamsType021( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType021( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType021( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType021( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 22 : Q
    static bool CheckParamsType022( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType022( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType022( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType022( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 23 : delta Lambda const
    static bool CheckParamsType023( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType023( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType023( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType023( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 24 : (delta Lambda)/Lambda const
    static bool CheckParamsType024( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType024( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType024( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType024( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 25 : d value
    static bool CheckParamsType025( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType025( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType025( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType025( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 26 : (delta d) / d const
    static bool CheckParamsType026(std::vector<Double> params, UtsusemiUnitConverter* uuc);
    static std::vector<Double> PutXaxisConvType026(std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType026(std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc);
    static std::vector<Double> PutLambdaConvType026(std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc);

    // ConvType = 27 : inverted geometry (for DNA)
    static bool CheckParamsType027( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType027( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType027( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType027( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );

    // ConvType = 28 : inverted geometry (for DNA)
    static bool CheckParamsType028( std::vector<Double> params, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutXaxisConvType028( std::vector<Double> params, Double tof_offset);
    static std::vector<Double> PutTofBinConvType028( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
    static std::vector<Double> PutLambdaConvType028( std::vector<Double>* xaxis, std::vector<Double>* params, std::vector<Double>* pv, std::vector<Double>* oparams, UtsusemiUnitConverter* uuc );
};
#endif
