#ifndef T0TREATTOOLSBASE
#define T0TREATTOOLSBASE

//#include <time.h>
#include "Header.hh"
#include <boost/filesystem.hpp>
#include "StringTools.hh"
#include "MlfHeader.hh"
#include <algorithm>

//////////////////////////////////
// T0TreatToolsBase
/////////////////////////////////
//! Tools for treating T0 event in eventdata
/*!
 *
 *
 *  updated
 *  130501: define NumOfClocksBeforeFirstT0
 *  130227: define BytesOfOrgEvent for readOrgEvent
 *  100910: delete returnBytesOfEvent and define const BytesOfT0Event
 */

class T0TreatToolsBase
{

private:
    std::vector<UInt8> pulseId_n;
    std::vector<Double> t0Time_n;  // MLF time [sec]
    std::vector<Double> t0Sec_n;   // Period time from begin [sec]
    std::vector<UInt8> t0Index_n;  // unit is [events]
    std::vector<UInt8> pulseId_m;
    std::vector<Double> t0Time_m;  // unit is [sec]
    std::vector<UInt8> t0Index_m;  // unit is [events]
    std::vector<Double> t0Sec_m;   // time from top
    std::vector<Double> t0Time_diff;

    std::vector<Double> t0Time_diff_tmp;
    std::vector<Double> t0Time_tmp;
    std::vector<UInt8> t0Index_tmp;
    std::vector<UInt8> pulseId_tmp;

    std::vector<Double> t0Time_ext;
    std::vector<Double> t0Sec_ext;
    std::vector<Double> t0Time_diff_ext;

    bool hasReadEvents;

    std::vector<Double> MeasPeriodClock;
    std::vector< std::pair<Double,Double> > _MeasPeriodClock;
    bool is_ReliableClock;
    UInt4 NumOfClocksBeforeFirstT0;
    bool ignoredT0PIDCheck;

    std::string _MessageTag;

    static const UInt4 BytesOfT0Event = 8;

    UInt4 BytesOfOrgEvent; //This is used on reading orginal Event [inamura 130227]

    virtual UInt4 checkHeaderT0(UChar buf[]){ return 0; }
        //!< check whether a given event is T0 event or not
        /*!< This checks whether a given event is T0 event or not and then reply the result.
         *   @param aByte(char) given event
         *   @retval 0  if given event is not T0 event.
         *   @retval 1  if given event is T0 event.
         */
    virtual UInt4 checkHeaderClock(UChar buf[]){ return 0; }
        //!< check whether a given event is Instrument Clock event or not
        /*!< This checks whether a given event is Instrument Clock event or not and then reply the result.
         *   @param aByte(char) given event
         *   @retval 0  if given event is not Instrument Clock event.
         *   @retval 1  if given event is Instrument Clock event.
         */
    virtual UInt8 decodePulseIdEvent(UChar buf[]){ return 0;}
        //!< give pulseID from T0 event
        /*!< This must give the pulse ID from T0 event.
         *   @param buf(UChar)  given T0 event
         *   @retval pulseId(UInt8)
         */
    virtual Double decodeInstClockEvent(UChar buf[]){ return 0.;}
        //!< give clock from T0 event
        /*!< This must give the clock from Instrument Clock event.
         *   @param buf(UChar)  given instrument clock event
         *   @retval clock(double)
         */

    void encodePidClockEvent(UChar eventPid[], UChar eventClock[], UInt8 pid, Double clock );
    void decodePidClockEvent(UChar eventPid[], UChar eventClock[], UInt8 *pid, Double *clock );
    void decodePidEvent(UChar eventPid[], UInt8 *pid );
    void encodeT0InfoEvent(UChar event[], UInt8 num, Double clock);
    void encodeT0InfoEvent(UChar event[], UInt8 num );
    void decodeT0InfoEvent(UChar event[], UInt8 *num, Double *clock);
    void decodeT0InfoEvent(UChar event[], UInt8 *num );

    void encodeClockIncEvent(UChar event[], Double ClockInc );
    void decodeClockIncEvent(UChar event[], Double *ClockInc );

    UInt4 putIndexByPid(UInt8 start_pid, UInt8 end_pid, UInt4 *start_ret_id, UInt4 *end_ret_id );
    UInt4 putIndexByClock(Double start_clock, Double end_clock, UInt4 *start_ret_id, UInt4 *end_ret_id );


public:
    T0TreatToolsBase(UInt4 bytes_of_org_event=8);
        //!< Constructor
        /*!<
         *    @param bytes_of_org_event  size of event to be read [bytes]
         */
    virtual ~T0TreatToolsBase();
        //!< Destructor
        /*!<
         */


    UInt4 readOrgEvent(std::string filename);
    UInt4 readOrgEvent(std::vector<std::string> filenames);
        //!< Load original event data
        /*!< This reads original event data from DAQ system
         *   to count events from head of file to T0 event
         *   and store counts, Pulse ID and its Instrument clock.
         *   readOrgEvent( std::string filename )
         *   readOrgEvent( std::vector<std::string> filenames )
         *
         *   @param filename  the file name of event data from DAQ
         *   @param filenames the file name list of event data
         *   @retval 0  succeeded in reading file
         *   @retval 1  failed in reading file
         */
    UInt4 saveT0IndexEvent(std::string filename);
        //!< Make T0 index file
        /*!< This reads Event Data (RAW), make T0 index and save as file.
         *   @param filename  the file name of event data for T0 index.
         *   @retval 0  succeeded in saving file
         *   @retval 1  failed in saving file
         */
    UInt4 readT0IndexEventold(std::string filename);
    UInt4 readT0IndexEventold(std::vector<std::string> filenames);
    UInt4 readT0IndexEvent(std::string filename);
    UInt4 readT0IndexEvent(std::vector<std::string> filenames);
        //!< Read T0 index file
        /*!< Read T0 index file produced by makeT0Index
         *   readT0IndexEvent( std::string filename )
         *   readT0IndexEvent( std::vector<std::string> filenames );
         *
         *   @param filename  the file name of event data for T0 index.
         *   @param filenames
         *   @retval 0  succeeded in reading file
         *   @retval 1  failed in readinf file
         */
    std::vector<UInt8> putVectorT0Index();
        //!< Put T0 index
        /*!< Put all T0 index as std::vector
         *
         *   @retval std::vector<UInt4>
         */
    std::vector<UInt8> putVectorT0IndexBySec(Double start_sec, Double end_sec);
        //!< Put T0 index std::vector between start ana end.
        /*!< Put T0 index
         *   @param start_sec (Double)
         *   @param end_sec (Double)
         *   @retval std::vector<UInt4>
         */
    std::vector<UInt8> putVectorPulseId();
        //!< Put PulseId
        /*!< Put all PulseIDs as std::vector
         *
         *   @retval std::vector<UInt8>
         */
    std::vector<UInt8> putVectorPulseIdBySec(Double start_sec, Double end_sec);
        //!< Put PulseId std::vector between start ana end.
        /*!< Put PulseId index in the range of given parameters
         *   @param start_sec (Double)
         *   @param end_sec (Double)
         *   @retval std::vector<UInt8>
         */
    std::vector<Double> putVectorT0Clock();
        //!< Put T0 clock
        /*!< Put all T0 clocks as std::vector
         *
         *   @retval std::vector<double>
         */
    void makeVectorBySec( Double start_sec, Double end_sec, bool getT0Index=true );
    std::vector<UInt8> putT0IndexByPid(UInt8 start_pid, UInt8 end_pid);
        //!< Put required region of T0 index
        /*!< Put start and end index of T0 by given Pulse-IDs.
         *   @param start_pid  pulse id at beggining in required region
         *   @param end_pid    pulse id at last in reaquired region
         *   @retval std::vector<UInt4> std::vector size is 2.
         */
    std::vector<UInt8> putT0IndexByClock(Double start_clock, Double end_clock);
        //!< Put required region of T0 index
        /*!< Put start and end index of T0 by given Clocks.
         *   @param start_clock  clock at beggining in required region
         *   @param end_clock    clock at last in reaquired region
         *   @retval std::vector<UInt4>  std::vector size is 2.
         */
    std::vector<Double> putT0ClockRegion();
        //!< Put the region of clock number of T0
        /*!< Put two clock numbers for top and last index of T0
         *   @retval std::vector<double> std::vector size is 2.
         */
    std::vector<UInt8> putPidRegion();
        //!< Put region of of PID
        /*!< Put first PID and last PID of T0
         *
         *   @retval std::vector<UInt4> std::vector size is 2.
         */
    std::vector<Double> putT0ClockDiffAll();
    std::vector<Double> putT0ClockDiff();
        //!< Put differences of clocks
        /*!< putT0ClockDiffAll : all differences
         *   putT0ClockDiff    : sliced list of differences
         *
         *   @retval std::vector<Double>
         */
    void decodeT0ClockEvent(UChar eventClock[], Double *clock);
        //!< decode Inst clock event
        /*!<
         *   @param eventClock (UChar)  given Inst Clock event
         *   @param clock      (Double*)
         *   @return None
         */
    bool CheckReliable(){ return is_ReliableClock; }
    std::vector<Double> convertInstClockToDateTime( Double inst_clock );
        //!< convert Instrument Clock (UTC) to Date Time (JST)
        /*!<
         *   @param inst_clock (Double) instrument clock decoded from Instrument clock event [sec]
         *   @retval std::vector<Double> std::vector of year,month,day,hour,minute,second,sub-second
         */
    Double convertDateTimeToInstClock( std::vector<Double> date_time );
        //!< convert Date Time (JST) to Instrument Clock which its origin is 2008/1/1 00:00:00 (MLF origin Date Time)
        /*!<
         *   @param std::vector<Double> std::vector of year,month,day,hour,minute,second,sub-second
         *   @retval (Double) instrument clock decoded from Instrument clock event
         */
    std::vector<Double> 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
         */
    void clearMeasPeriod();
        //!< clear stored measuring period
        /*!<
         *   @param None
         *   @return None
         */
    void SetBytesOfOrgEvent( UInt4 bytes_of_org_event ); //[inamura 130227]
    void setNumOfClocksBeforeFirstT0( UInt4 num_of_clocks ); //[inamura 130501]
    std::vector<UInt8> putSlicedT0IndexEvent( UInt8 start_posi, std::string path_to_file, UInt8 *count_to_last );
    std::vector<UInt8> putSlicedT0IndexEventPy( UInt8 start_posi, std::string path_to_file );
        //!< Put required region of T0 index from T0Index Event file
        /*!< T0Index will be picked up from start_posi to count_to_last.
         *   @param start_posi   T0Index events before start_posi are skipped.
         *   @param path_to_file path to event data file
         *   @param count_to_last  the number of events from start_poti to last. Set 0 when read all events after start_posi.
         *   @retval std::vector<UInt4>
         */
    bool putSlicedT0EventInfo( UInt8 start_posi, std::vector<std::string> filenames, std::vector<UInt8>& retCountToLast, std::vector<UInt8>& retT0Index, std::vector<UInt8>& retPulseId, std::vector<Double>& retDiffClock, UInt8 lastPulseId=0 );
    std::vector<UInt8> putSlicedT0EventInfoPy1( UInt8 start_posi, std::vector<std::string> filenames );
    std::vector<UInt8> putSlicedT0EventInfoPy2( UInt8 start_posi, std::vector<std::string> filenames, UInt8 start_pid=0 );
    std::pair<Double,Double> MeasClockSliced;    // .first:smallest clock in sliced region, .second:last clock [sec]
    std::pair<Double,Double> CurrentClockSliced; // .first:absolute clock  .second:sum of diff clock from InstClock [sec]

    std::vector<Double> putT0SecVector();
    void dumpMeasPeriodClock();

    std::vector<UInt8> PutT0Index();
        //!< Put T0 Index
        /*!< Put T0 Index std::vector.
         *   If time slicing is set using by SetRangeOfSingleTimeSlicing
         *   return sliced T0 Index std::vector
         *
         *   @retval std::vector<UInt4>
         */
    std::vector<UInt8> PutPulseId();
        //!< Put Pulse ID list
        /*!< Put Pulse ID std::vector.
         *   If time slicing is set using by SetRangeOfSingleTimeSlicing
         *   return sliced Pulse ID std::vector
         *
         *   @retval std::vector<UInt8>
         */
    std::vector<Double> PutT0ClockDiff();
        //!< Put differences of instrument clocks
        /*!< If time slicing is set using by SetRangeOfSingleTimeSlicing
         *   return sliced clock std::vector
         *
         *   @retval std::vector<Double>
         */
    std::vector<Double> PutT0Clock();
        //!< Put instrument clocks
        /*!< If time slicing is set using by SetRangeOfSingleTimeSlicing
         *   return sliced clock std::vector
         *
         *   @retval std::vector<Double>
         */
    std::vector<Double> _RangeSingleTimeSlice;
    bool SetRangeOfSingleTimeSlicing( double startSec, double 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]
         *   @return None
         */
    bool SetRangeOfSingleTimeSlicing( std::string startDate, std::string 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
         *   @return None
         */
    void SetExternalClockInfo( std::vector<Double> _t0Time, bool _isReliable=true );
    void ClearExternalClockInfo();
    bool PutSlicedOrgEventBySec( std::vector<std::string> orgfiles, double start_sec, double end_sec, std::string outfile, std::vector<double> extTime );
    bool PutSlicedOrgEventByKicker( std::vector<std::string> orgfiles, UInt4 start_kick, UInt4 end_kick, std::string outfile );
    void DecodePidClockEvent(UChar eventPid[], UChar eventClock[], UInt8 *pid, Double *clock ){
        decodePidClockEvent(eventPid, eventClock, pid, clock );
    }
    void EncodePidClockEvent(UChar eventPid[], UChar eventClock[], UInt8 pid, Double clock ){
        encodePidClockEvent(eventPid, eventClock, pid, clock);
    }

    void DumpInfo(std::string filepath="");
    void DumpInfo(std::vector<std::string> filepaths);
        //!< Shows the information included in MLF event data file.
        /*!< Information about :
         *   - Measurement period
         *   - The result of check the lack of t0 events (by the increment of T0 ID)
         *
         *   @param  filepath target event data file, if empty, use the loaded event data.
         *   @return None
         */

    bool CheckSequencePulseId(std::string filepath="");
        //!< Check the sequence of pulse id in given edb/t0b file.
        /*!<
         *
         *   @param  filepath target event data file or t0b file, if empty, use the loaded event/t0b data.
         *   @return bool
         */
    bool CheckSequencePulseId2(std::string filepath, std::vector<UInt4>* ret_pid, std::vector<double>* ret_clock);
        //!< Check the sequence of pulse id in given edb/t0b file and return sequence of pid and clock
        /*!<
         *
         *   @param  filepath target event data file or t0b file, if empty, use the loaded event/t0b data.
         *   @param  ret_pid sequence of pids
         *   @param  ret_clock sequence of clocks
         *   @return bool
         */
};

#endif
