#ifndef UTSUSEMIEVENTDATACONVERTERTEMPLATE_HH
#define UTSUSEMIEVENTDATACONVERTERTEMPLATE_HH

#include "Header.hh"
#include "HeaderBase.hh"
#include "ElementContainer.hh"
#include "ElementContainerMatrix.hh"
#include "GslHistogram.hh"
#include "Map.hh"
#include <algorithm>
#include <boost/filesystem.hpp>
#include "StringTools.hh"
#include "UtsusemiHeader.hh"

////////////////////////////////////////
// UtsusemiEventDataConverterTemplate
////////////////////////////////////////

//! Template class for Convesion
/*! from EventData to Histogram on offline.
 *  - read EvnetDataFile
 *  - Decode Event data using Decode module
 *  - Increment to gls histogram
 *  This template requires the instanse successing UtsusemiNeutronEventDecorder.
 */

template <typename T1, typename T2>
class UtsusemiEventDataConverterTemplate
{
private:
    void Initialize();
    void Clear( UInt4 type = 0);
    StringTools* _stools;
    std::vector<Double*> _tofRangePointers;   /**< Vector of pointer(s) of _tofRange */

protected:
    std::string _MessageTag;
    UInt4 _NumOfMulTh;
    std::vector< GslHistogram* >* _gslHist;
    UInt4 _numOfInnerPixels;
    UInt4 _numOfAdditionalClocks; /**< number of additional clocks for FrameBoundary */
    UInt4 _numOfCases;
    UInt4 _eventSize;
    std::vector< Int4>* _convOuterPixelIdToInnerId;

    T1* _EventDecoder;
    T2* _CaseDecoder;

    Map< std::vector<std::string> > _dataFileList;
    Map< std::vector<std::string> > _t0dataFileList;
    std::pair<std::string,std::string> _dataPathes;
    std::vector<bool> _isUnReadDetId;

    std::vector< std::vector<Double>* >* _timeDependBackGroundList; /**< [multh][pixelId]  */
    bool _isLoadedTimeDependBackGroundList;
    Double _timeDependBackGroundNormalizeFactor;
    std::vector<UInt4> _numOfT0List;

public:
    UtsusemiEventDataConverterTemplate();
        //!< Constructor
        /*!<
         */
    ~UtsusemiEventDataConverterTemplate();
        //!< Destructor
        /*!<
         */
    T1* PutEventDecoder(){ return _EventDecoder; }
        //!< Puts instanse of event decoder class
        /*!<
         *   @return instanse of event decoder class
         */
    T2* PutCaseDecoder(){ return _CaseDecoder; }
        //!< Puts instanse of case decoder class
        /*!<
         *   @return instanse of case decoder class
         */
    bool SetEventParams( std::string wiring_file, std::string detector_file );
        //!< Sets Wiring Info and Detector Info files
        /*!<
         *   @param wiring_file (std::string) path to Wiring Info file
         *   @param detector_file (std::string) path to Detector Info file
         *   @return None
         */
    void SetCaseInfoParams( std::string pathToCaseInfo );
        //!< Sets CaseInfo file
        /*!<
         *   @param pathToCaseInfo (std::string) path to caseInfo file
         *   @return None
         */
    void AllocateGslHist( UInt4 numOfPixel=0, UInt4 numOfCases=0 );
        //!< Allocate memory for GSL Histogram
        /*!< This makes gslhistogram with the number of numOfPixel * numOfCases
         *
         *   @param numOfPixel (UInt4) the number of pixels
         *   @param numOfPixel (UInt4) the number of cases
         *   @retval None
         */
    void SetHistBin( UInt4 innerPixelId, Double *tof, UInt4 Size );
        //!< Set binning of histogram with array
        /*!<
         *   @param innerPixelId (UInt4) inner pixel id
         *   @param tof (Double*) array of tof
         *   @param Size (UInt4) the number of array
         *   @retval None
         */
    void SetHistBin( UInt4 innerPixelId, std::vector<Double> xaxis );
        //!< Set binning of histogram with std::vector
        /*!< This calls SetHistBin.
         *
         *   @param innerPixelId (UInt4) inner pixel id
         *   @param xaxis (std::vector<Double>) std::vector of tof
         *   @retval None
         */
    virtual void SetHistBin();
        //!< Set binning of histogram
        /*!< This calls SetHistBin using information loaded from wiring info and detector info
         *
         *   return None
         */
    void SetHistBin(ElementContainerMatrix *ecm, std::string _key="");
    virtual void SetHistAllocation( UInt4 num_of_multh=0 );
        //!< Allocation of GSL-Histogram and SetHistBin
        /*!< This executes simple allocation as AllocateGslHist(); SethistBin();
         *   @param num_of_multh (UInt4) set _NumOfMulTh if num_of_multh!=0
         *   @return None
         */

    virtual void Increment(UInt4 daqId, UInt4 moduleNo, const UChar* data, UInt4 size, UInt4 ThNum, std::vector<Double>* Offset, std::vector<UInt4>* Case );
        //!< Increment intensity
        /*!< Increment intensity of histogram by using information from decoded event
         *
         *   @param daqId (UInt4) DAQ id
         *   @param moduleNo (UInt4) Module No
         *   @param data (UChar*) event data
         *   @param size (UInt4) size of event data
         *   @param ThNum (UInt4) thread number
         *   @param Offset (Double) offset value
         *   @retval None
         */
    virtual void PreIncrement( UInt4 daqId, UInt4 moduleNo, const UChar* data, std::vector<UInt8> T0Table, std::vector<Double> ClockTable, std::vector< std::vector<UInt4>* > *CaseTable );
    virtual void PreIncrement( UInt4 daqId, UInt4 moduleNo, const UChar* data, std::vector<UInt8> T0Table);
        //!< Pre-process to convert event data to histogam
        /*!< Pre-process to convert event data to histogam with multh-threading.
         *
         *   @param daqId (UInt4) DAQ id
         *   @param moduleNo (UInt4) module No
         *   @param data (UChar*) event data
         *   @param T0Table (vecrot<UInt4>) T0 index
         *   @param ClockTable (std::vector<Double>) Differences between instrument clocks
         *   @param CaseTable (std::vector<std::vector<UInt4>>) Table of cases pattern
         *   @retval None
         */
    void SetDataPathOld(std::string dataPath, std::string t0Path, std::vector<UInt4> runNumbers, bool isReset=false );
    void SetDataPath(std::string dataPath, std::string t0Path, UInt4 runNo, bool isReset=false,
                     std::vector< std::vector< std::vector< std::vector<Int4>* >* >* >* _PixelInfoStore=NULL,
                     std::vector< std::pair<UInt4,UInt4> >* maskModules=NULL, bool makeT0b=true );
    void SetDataPath( std::string dataPath, std::string t0Path, std::vector<UInt4> runNumbers, bool isReset=false,
                      std::vector< std::vector< std::vector< std::vector<Int4>* >* >* >* _PixelInfoStore=NULL,
                      std::vector< std::pair<UInt4,UInt4> >* maskModules=NULL, bool makeT0b=true );
        //!< Sets path to Event data files
        /*!< This makes list of Event data files and T0 event data files to be read.
         *   This finds data directories like /data/XXX, /data/XXX01, /data/XXX02, ... /data/XXX99,
         *   then search run_folder and data files in found data directoris from beggning as XXX -> XXX01 -> XXX02 -> ...
         *   If data files (edb) are founds, searching in directories stops.
         *
         *   @param dataPath  (std::string)  Path to Event data folder ( "/data" )
         *   @param t0Path    (std::string)  Path to T0Event data folder
         *   @param runNo     (UInt4)   RunNo
         *   @param runNumbers (std::vector<UInt4> list of RunNo to be combined
         *   @param isReset    (bool)  Resets previous file list or not
         *   @param _PixelInfoStore
         *   @param maskModules
         *   @param makeT0b   (bool) true: try to create t0b
         *   @retval None
         */
    std::vector<std::string> PutDataFiles( UInt4 daqId, UInt4 modNo, bool isEdb=true );
        //!< Puts data file list
        /*!< This puts data files with given daqId, modNo from made list of data files
         *
         *   @param daqId (UInt4) DAQ id
         *   @param modNo (UInt4) module No
         *   @param isEdb (bool)  event data file (true) or t0b file (false)
         *   @retval file list (std::vector<stirng>)
         */
    std::vector<UInt8> PutFilesSize( std::vector<std::string> files );
        //!< Puts file sizes of given pathes
        /*!<
         *
         *   @param files (std::vector<std::string>) path list
         *   @retval None
         */
    virtual void ReadEventData( UInt4 daqId, UInt4 modNo );
        //!< Read Event data file to make histograms
        /*!<
         *
         *   @param daqId (UInt4) DAQ id
         *   @param modNo (UInt4) module No
         *   @retval None
         */

    virtual UInt4 PutHistId( UInt4 PixelId, UInt4 CaseId=1 );
        //!< Puts Histogram ID from outer PixelId and CaseId
        /*!< Histogram ID is used for allocated GSL-Histograms.
         *   @param PixelId (UInt4) outer pixel ID
         *   @param CaseId  (UInt4) case id
         *   @return None
         */
    std::vector<Double> PutHist( UInt4 PixelId, UInt4 CaseId=1 );
        //!< Puts intensity of histogram by outer PixelId and CaseId
        /*!<
         *   @param PixelId (UInt4) outer pixel ID
         *   @param CaseId  (UInt4) case id
         *   @return None
         */
    std::vector<Double> PutErr( UInt4 PixelId, UInt4 CaseId=1 );
        //!< Puts error of histogram by outer PixelId and CaseId
        /*!<
         *   @param PixelId (UInt4) outer pixel ID
         *   @param CaseId  (UInt4) case id
         *   @return None
         */
    Double TimeDependBackGroundCorrection( bool isIntensity, std::vector<Double>* tof_vec, std::vector<Double>* hist_vec, std::vector<Double>* bg_info, std::vector<Double>* ret );
        //!< Executes time-depend background correction
        /*!<
         *   @param isIntensity  (bool) hist_vec is the intensity (true) or errors (false).
         *   @param tof_vec      (std::vector<Double>) TOF std::vector including backgrond region.
         *   @param hist_vec     (std::vector<Double>) The intensity or error values
         *   @param bg_info      (std::vector<Double>) Background Info [0]:patern, [1]:first tof val, [2]:last tof val
         *   @param ret          (std::vector<Double>) corrected hist_vec.
         *   @return background intensity per unit (Double)
         */
    void InitTimeDependBackGroundList();
    bool TimeDependBackGroundCorrectionByList(bool isIntensity, std::vector<Double>* tof_vec, std::vector<Double>* hist_vec, UInt4 pixelId, UInt4 multh, std::vector<Double>* ret, UInt4 caseId=1 );
    bool SaveTimeDependBackGroundListToFile( std::string filePath, UInt4 caseId=1 );
    bool ReadTimeDependBackGroundListFromFile( std::string filePath );
    void ClearTimeDependBackGroundList();
    //void ReadCaseEventFiles( std::vector<std::string> files );
    void ReadCaseEvent( UInt4 index, std::vector<std::string> evt_files, std::vector<std::string> t0b_files );
    void ReadCaseEventFiles( UInt4 index, std::vector<std::string> evt_files, std::vector<std::string> t0b_files );
        //!< Reads event data files for cases
        /*!<
         *   @param index (UInt4) index for files ( XXX001000_00_000_000.edb, _001.edb ...  has same index )
         *   @param evt_files (std::vector<std::string>) pathes to neutron event data file
         *   @param t0b_files (std::vector<std::string>) pathes to t0b event data file
         *   @return None
         */
    void SetFlagOfPulseIdCheck( bool flag = true );
        //!< Sets flag of Pulse iD check
        /*!< This flag is used to compare pulse id between neutrons event data and case (trignet) event data
         *
         *   @param flag (bool) true : do check on reading case event data
         *   @return None
         */

    void SetElementContainer( UInt4 PixelId, ElementContainer *ec, UInt4 caseId=0 );
        //!< Put histogram data into ElementContainer with Case
        /*!< Before using this method, target ElementContainer must be created.
         *
         *   @param PixelId (UInt4) pixel Id
         *   @param ec (ElementContainer) target ElementContainer
         *   @param caseId (UInt4) case Id
         *   @retval None
         */

    void ResetHistogram();
        //!< Reset Histogram
        /*!< Clear all values in bins of GslHistogram ( binning is kept )
         *
         *   @retval None
         */

    UInt4 PutNumOfCases(){ return _numOfCases; }
        //!< Return number of cases
        /*!<
         *
         *   @return UInt4
         */

    UInt4 _runNumber; /**< run number */
    std::vector<UInt4> _runNumbers;
    std::vector<Double> _MeasTimeList; //[inamura 160623]
    std::vector<Double> PutMeasTimeList(){ return _MeasTimeList;} //[inamura 160623]
    std::string _instCode; /**< instrument code */
    bool _isReady;    /**< for check whether method(s) executed well or not */


    std::vector<UInt4> PutListOfCases(){ return _CaseDecoder->PutListOfCases(); }
        //!< Puts list of cases
        /*!<
         *  @param None
         *  @return list of cases
         */
    std::vector<UInt4> PutNumOfT0ListInCases(){ return _CaseDecoder->PutNumOfT0ListInCases(); }
    std::vector<Double> PutMeasTime(){ return _CaseDecoder->PutMeasPeriodFromT0(); }
        //!< put measuring period from instrument clock event
        /*!< This returns std::vector with 12 params. If conversion is failed,
         *   size of returned vector is one.
         *   @param None
         *   @return std::vector<Double> std::vector with 12 params for begin time and end time
         *                         (year,month,day,hour,minute,second,sub-second) x 2
         */
    bool AddRunInfoToHeader( HeaderBase* _hh, UInt4 caseId=1 );
    bool SetRangeOfSingleTimeSlicing( double startSec, double endSec ){
        return _CaseDecoder->SetRangeOfSingleTimeSlicing( startSec, endSec ); }
       //!< Sets time range for time slice of event data
       /*!< Values for time are indicated the passed time [sec] from head of event data
         *   @param  startSec     start time [sec]
         *   @param  endSec       end time [sec]
         *   @retval true         succeeded
         *   @retval false        failed
         */
    bool SetRangeOfSingleTimeSlicing( std::string startDate, std::string endDate ){
        return _CaseDecoder->SetRangeOfSingleTimeSlicing( startDate, endDate ); }
        //!< Sets time range for time slice of event data
        /*!< Values for time are indicated the passed time [sec] from head of event data
         *   std::string format : "YYYY,MM,DD,hh,mm,ss,s.ss", "2011,1,22,13,54,22,0.54"
         *   @param  startDate     start date std::string
         *   @param  endDate       end date std::string
         *   @retval true         succeeded
         *   @retval false        failed
         */
    void SetTimeSlicing( std::vector<Double> tmp ){ _CaseDecoder->SetTimeSlicing( tmp ); }
    void SetFramePeriod( Double _time ) { _EventDecoder->_MicroSec_Par_Frame=_time; }
};
#include "UtsusemiEventDataConverterTemplate.cc"

#endif
