#ifndef UTSUSEMIEVENTDATAMONITORTEMPLATE_HH
#define UTSUSEMIEVENTDATAMONITORTEMPLATE_HH

/* Header.hh should be included on the top to avoid environments
 * specific issues (see Header.hh for the detail).
 */
#include "Header.hh"

#include "EventDataMonitorBase.hh"
#include "WriteSerializationFile.hh"
#include "StringTools.hh"
#include "UtsusemiHeader.hh"
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

///////////////////////////////////////////
//  UtsusemiEventDataMonitorTemplate
///////////////////////////////////////////

//! Event Data Monitor ( Differential Data Reduction )
/*!
 *  tt = UtsusemiEventDataMonitorXXXX()
 *  tt.SetDataFolder( "/data" )
 *  tt.ParameterSet( wfile, dfile, cfile )
 *  tt.AddAllDataModules()
 *  // repeat below
 *  tt.Update()
 *  dat = ElementContainerMatrix()
 *  tt.Output( dat )
 *  tt.Clear() // if needed
 *
 *  or
 *  tt.UpdataDataModules()
 *  tt.IncrementCases()
 *  tt.Increment(1,1) // give the only daqId and modNo required
 *  dat = ElementContainerMatrix()
 *  tt.Output( dat )
 *  tt.Clear() // if needed
 *
 *
 */
class UtsusemiEventDataMonitorContainer
{
public:
    std::vector< std::pair<std::string,UInt4> > Edbfiles;  /**<  <filename, file size> */
    std::vector< std::pair<std::string,UInt4> > T0bfiles;  /**<  <filename, file size> */
    std::vector<UInt8> LeftPulseIdTable;
    std::vector<UInt8> LeftT0IndexTable;
    std::vector<Double> LeftDiffClockTable;
    UInt4 CurrentPosi_edb;                  /**< the number of events (x Byte = binary file size) */
    UInt8 CurrentPosi_t0b;                  /**< the number of events (x Byte = binary file size) */
    std::pair<Double,Double> MeasClockSliced;
    std::pair<Double,Double> CurrentClockSliced;
    UInt8 LastPulseId;

    UtsusemiEventDataMonitorContainer(){
        Edbfiles.clear();  /**<  <filename, file size> */
        T0bfiles.clear();  /**<  <filename, file size> */
        LeftPulseIdTable.clear();
        LeftT0IndexTable.clear();
        LeftDiffClockTable.clear();
        CurrentPosi_edb = 0;
        CurrentPosi_t0b = 0;
        MeasClockSliced.first = -1.0;
        MeasClockSliced.second = -1.0;
        CurrentClockSliced.first = 0.0;
        CurrentClockSliced.second = 0.0;
        LastPulseId = 0;
    }
    UtsusemiEventDataMonitorContainer( const UtsusemiEventDataMonitorContainer& obj ){
        Edbfiles.resize( obj.Edbfiles.size() );
        Edbfiles.assign( obj.Edbfiles.begin(), obj.Edbfiles.end() );
        T0bfiles.resize( obj.T0bfiles.size() );
        T0bfiles.assign( obj.T0bfiles.begin(), obj.Edbfiles.end() );
        LeftPulseIdTable.resize( obj.LeftPulseIdTable.size() );
        LeftPulseIdTable.assign( obj.LeftPulseIdTable.begin(), obj.LeftPulseIdTable.end() );
        LeftT0IndexTable.resize( obj.LeftT0IndexTable.size() );
        LeftT0IndexTable.assign( obj.LeftT0IndexTable.begin(), obj.LeftT0IndexTable.end() );
        LeftDiffClockTable.resize( obj.LeftDiffClockTable.size() );
        LeftDiffClockTable.assign( obj.LeftDiffClockTable.begin(), obj.LeftDiffClockTable.end() );
        CurrentPosi_edb = obj.CurrentPosi_edb;
        CurrentPosi_t0b = obj.CurrentPosi_t0b;
        MeasClockSliced.first = obj.MeasClockSliced.first;
        MeasClockSliced.second = obj.MeasClockSliced.second;
        CurrentClockSliced.first = obj.CurrentClockSliced.first;
        CurrentClockSliced.second = obj.CurrentClockSliced.second;
        LastPulseId = obj.LastPulseId;
    }
    ~UtsusemiEventDataMonitorContainer(){}
};

template <typename T1>
class UtsusemiEventDataMonitorTemplate:
    public EventDataMonitorBase
{
private:
    std::string _MessageTag;


    std::vector< std::vector<Int4>* >* TrigInfoStore;
    std::vector<UInt8> PulseIdOfCases;
    std::vector< std::vector<UInt4>* > CaseList;
    std::vector< std::vector<UInt4> > IndexOfCaseFile; /**< [num of files]< index, ver, daqId, modNo > */

    std::string _PathToDataRoot;  /**<  /data/SIK/SIK000373_20090105  */
    std::vector< std::pair<UInt4,UInt4> > _ModuleInfo;
    std::vector< std::vector< UtsusemiEventDataMonitorContainer* > > _ModuleContainer; /**<  [daqId][modNo][num]<filename>   */
    //UInt4 _RunNo;
    UInt4 _BytesOfT0Event;
    std::vector<Int4> _KickersForCases;
    std::vector<UInt4> _UpdatedCases;
    std::string TargetFolder;

public:
    T1* _EDC;  //EventDataConverterXXX

    std::vector< std::vector<UInt8> > _leftT0IndexTable;

    bool isReadout;     //[inamura 170220]
    UInt8 firstPulseId; //[inamura 170220]
    UInt4 _RunNo;
    //////////////////////////////////////////////////////////////////////////
    //!< Constructor
    /*!<
     */
    UtsusemiEventDataMonitorTemplate(UInt4 ByteOfNeutronEvent=8):EventDataMonitorBase(ByteOfNeutronEvent){
        _EDC = NULL;
        _leftT0IndexTable.clear();

        _PathToDataRoot= UtsusemiEnvGetDataDir();
        _ModuleInfo.clear();
        _ModuleContainer.clear();
        _RunNo = 0;
        _BytesOfT0Event = 8;
        _MessageTag = "UtsusemiEventDataMonitorTemplate >> ";
        _KickersForCases.clear();
        _UpdatedCases.clear();
        isReadout = false;//[inamura 170220]
        firstPulseId = 0; //[inamura 170220]
        TargetFolder = "";
    }
    //////////////////////////////////////////////////////////////////////////
    //!< Destructor
    /*!<
     */
    ~UtsusemiEventDataMonitorTemplate(){
        if (_EDC!=NULL) delete _EDC;
        ClearDataModules();
        for (UInt4 i=0; i<CaseList.size(); i++)
            if (CaseList[i]!=NULL) delete CaseList[i];
    }

    T1* PutEventDataConverter(){ return _EDC; }
    //////////////////////////////////////////////////////////////////////////
    //!< ParameterSet sets Event parameters
    /*!<
     *    @param _WireingFile  (std::string) Wiring Info file path
     *    @param _DetectorInfoFile (std::string) Detector Info file path
     *    @param _CaseInfoFile (std::string)
     *    @param tofShiftPtnId (Int4) : this will be included in WiringInfo or DetectorInfo
     *    @return None
     */
    void ParameterSet( std::string _WireingFile, std::string _DetectorInfoFile, std::string _CaseInfoFile, UInt4 _MulTh=0, Int4 tofShiftPtnId=-1 ){
        isGoodStatus = false;
        if (_EDC!=NULL) delete _EDC;
        _EDC = new T1();
        if (!(_EDC->LoadParamFiles( _WireingFile, _DetectorInfoFile, _CaseInfoFile ))){
            delete _EDC;
            _EDC=NULL;
            return;
        }
        if (tofShiftPtnId>-1)
            _EDC->SetTofOriginShift( (UInt4)tofShiftPtnId );
        if (_MulTh!=0)
            _EDC->SetHistAllocation(_MulTh);
        else
            _EDC->SetHistAllocation();
        if (_RunNo!=0) _EDC->_runNumbers.push_back( _RunNo );

        TrigInfoStore = _EDC->PutEventDecoder()->_wirInfo->TrigInfoStore;
        IndexOfCaseFile.clear();
        if (TrigInfoStore!=NULL){
            for (UInt4 i=0; i<TrigInfoStore->size(); i++){
                if (TrigInfoStore->at(i)!=NULL){
                    if (TrigInfoStore->at(i)->empty()){
                    }else{
                        if (TrigInfoStore->at(i)->at(0)!=-1){
                            std::vector<UInt4> tmp;
                            tmp.push_back( i );
                            tmp.push_back( (UInt4)(TrigInfoStore->at(i)->at(0)) );  // TrigNet version
                            tmp.push_back( (UInt4)(TrigInfoStore->at(i)->at(1)) );  // daqId
                            tmp.push_back( (UInt4)(TrigInfoStore->at(i)->at(2)) );  // modNo
                            IndexOfCaseFile.push_back( tmp );
                        }
                    }
                }
            }
        }
        _KickersForCases.resize( PutNumOfCases()+1, 0 ); //[inamura 161210]
        isGoodStatus = true;
    }

    //////////////////////////////////////////////////////////////////////////
    //!< AddDataFiles adds Event data file(s) and T0Index event data file(s) pathes
    /*!<
     *    @param TargetT0EventFilePath (std::string or std::vector<std::string>) T0Index event data file path
     *    @param TargetEventDataFilePath (std::string or std::vector<std::string>) Event Data file path
     *    @param DaqID (UInt4 or std::vector<UInt4>)
     *    @return None
     */
    void AddDataFiles( std::string TargetT0EventFilePath,
                       std::string TargetEventDataFilePath,
                       UInt4 DaqID ){
        EventDataMonitorBase::AddDataFiles( TargetT0EventFilePath, TargetEventDataFilePath, DaqID );
        std::vector<UInt8> tmp;
        tmp.clear();
        _leftT0IndexTable.push_back( tmp );
    }
    void AddDataFiles( std::vector<std::string> TargetT0EventFilePath,
                       std::vector<std::string> TargetEventDataFilePath,
                       std::vector<UInt4> DaqID ){
        EventDataMonitorBase::AddDataFiles( TargetT0EventFilePath, TargetEventDataFilePath, DaqID );
        for (UInt4 i=0;i<TargetEventDataFilePath.size();i++){
            std::vector<UInt8> tmp;
            tmp.clear();
            _leftT0IndexTable.push_back( tmp );
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //!<  Increment increments data
    /*!<  This reads difference of data by index and add to histograms
     *    note : This is OBSOLETED! first version of differential data reduction
     *
     *    @param index (UInt4) Index of data
     *    @return None
     */
    void Increment( UInt4 index ){
        isGoodStatus = false;

        if (index>=CurrentPosition.size()){
            UtsusemiError( _MessageTag+" Increment >> index is too large." );
            return;
        }

        if (_EDC==NULL){
            UtsusemiError( _MessageTag+" Did not set parameters (ParameterSet)" );
            return;
        }

        // pick up differential between previous T0 Index Event file and current one.
        UInt8 last_cnt_T0event = 0;
        std::vector<UInt8> sv = _EDC->PutCaseDecoder()->PutT0TreatTools()->putSlicedT0IndexEvent(
            CurrentPosition[index], TargetT0EvnetFileSet[index], &last_cnt_T0event );

        if (last_cnt_T0event==0){
            UtsusemiError( _MessageTag+" could not read correctly T0Index Event file" );
            return;
        }

        CurrentPosition[index] += last_cnt_T0event;

        // add T0IndexTable which is not used in previous Increment()
        UInt4 sizeOfLeftT0IndexTable = (UInt4)(_leftT0IndexTable[index].size());
        std::vector<UInt8> table( (sizeOfLeftT0IndexTable+sv.size()), 0 );
        for (UInt4 i=0;i<sizeOfLeftT0IndexTable;i++) table[i]=_leftT0IndexTable[index][i];
        for (UInt4 i=0;i<sv.size();i++) table[i+sizeOfLeftT0IndexTable] = sv[i];

        // slice Event data by table of T0Index differentials
        UChar* data = new UChar[ (table[table.size()-1]-table[0])*ElementSize ];
        Int8 lastIndexOfTable = Read( TargetEventFileSet[index], table, data );
        UInt8 numOfReadEvents = table[lastIndexOfTable]-table[0];

        // unused T0index differentials are stored in _leftT0IndexTable.
        _leftT0IndexTable[index].clear();
        if (lastIndexOfTable!=(table.size()-1)){
            for (UInt8 i=(lastIndexOfTable+1);i<(table.size());i++) {
                _leftT0IndexTable[index].push_back( table[i] );
            }
        }

        // make T0 table for increments of sliced events
        std::vector<UInt8> t0table( (lastIndexOfTable+1), 0 );
        for (UInt4 i=0;i<(lastIndexOfTable+1);i++) {
            t0table[i] = table[i]-table[0];
        }

        // Increment of sliced event in histogram
        UChar* data2 = new UChar[ numOfReadEvents*ElementSize ];
        for (UInt4 i=0;i<(numOfReadEvents*ElementSize);i++) data2[i]=data[i];

        _EDC->PreIncrement( DaqIdSet[index], 0, data2, t0table );

        delete [] data;
        delete [] data2;
        isGoodStatus = true;
    }

    //////////////////////////////////////////////////////////////////////////
    //!<  SetDataFolder
    /*!<  This sets data folder
     *
     *    @param dfolder (std::string) path to data folder same as UTSUSEMI_DATA_DIR
     *    @return None
     */
    void SetDataFolder( std::string dfolder ){ _PathToDataRoot = dfolder; }
    //////////////////////////////////////////////////////////////////////////
    //!<  ClearDataModules
    /*!<  This cleans the list of all modules given by WiringInfo or users
     *
     *    @param None
     *    @return None
     */
    void ClearDataModules(){
        _ModuleInfo.clear();
        for (UInt4 daqId=0; daqId<_ModuleContainer.size(); daqId++){
            for (UInt4 modNo=0; modNo<_ModuleContainer[daqId].size(); modNo++){
                if (_ModuleContainer[daqId][modNo]!=NULL)
                    delete _ModuleContainer[daqId][modNo];
            }
            _ModuleContainer[daqId].clear();
        }
        _ModuleContainer.clear();
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  SetRunNumber
    /*!<  This sets run number of target for differential data reduction
     *
     *    @param runNo (UInt4) run number
     *    @return None
     */
    void SetRunNumber( UInt4 runNo ){
        _RunNo = runNo;
        if (_EDC!=NULL){
            _EDC->_runNumbers.clear();
            _EDC->_runNumbers.push_back( runNo );
        }
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  AddAllDataModules
    /*!<  This adds all modules described in WiringInfo to the list to be
     *    used for differential data reduction
     *
     *    @param None
     *    @return None
     */
    void AddAllDataModules(){
        ClearDataModules();
        std::vector< std::vector< std::vector< std::vector<Int4>* >* >* >* _PixelInfoStore = _EDC->PutEventDecoder()->_wirInfo->PixelInfoStore;
        if (_PixelInfoStore==NULL){
            UtsusemiError( _MessageTag+"AddAllDataModules >>> There is no information about pixels from WiringInfo.xml" );
            return;
        }
        for (UInt4 daq=0; daq<(_PixelInfoStore->size()); daq++)
            if (_PixelInfoStore->at(daq)!=NULL)
                for (UInt4 mod=0; mod<(_PixelInfoStore->at(daq)->size()); mod++)
                    if (_PixelInfoStore->at(daq)->at(mod)!=NULL){
                        //std::cout << "---AddAllDataModules daq,mod="<<daq<<","<<mod<<std::endl;
                        AddDataModule( daq, mod );
                    }

        std::vector< std::vector<Int4>* >* caseInfoStore = _EDC->PutEventDecoder()->_wirInfo->TrigInfoStore;
        if (caseInfoStore!=NULL){
            for (UInt4 i=0; i<caseInfoStore->size(); i++){
                if (caseInfoStore->at(i)!=NULL){
                    Int4 daq = caseInfoStore->at(i)->at(1);
                    Int4 mod = caseInfoStore->at(i)->at(2);
                    //std::cout << "---AddAllDataModules daq,mod="<<daq<<","<<mod<<std::endl;
                    AddDataModule( daq, mod );
                }
            }
        }else{
            UtsusemiError( _MessageTag+"AddAllDataModules >>> caseInfoStore is NULL " );
        }
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  AddDataModule
    /*!<  This adds given modules to the list to be used
     *    for differential data reduction
     *
     *    @param daqId (UInt4)
     *    @param modNo (UInt4)
     *    @return None
     */
    void AddDataModule( UInt4 daqId, UInt4 modNo ){
        for (std::vector< std::pair<UInt4,UInt4> >::iterator it = _ModuleInfo.begin(); it!=_ModuleInfo.end(); ++it){
            if ( ((*it).first==daqId)&&((*it).second==modNo) ){
                StringTools st;
                UtsusemiError( _MessageTag + "AddDataModules >> already added given daqId,modNo = "+st.UInt4ToString(daqId)+","+st.UInt4ToString(modNo) );
                return;
            }
        }

        std::pair<UInt4,UInt4> daq_mod;
        daq_mod.first = daqId;
        daq_mod.second = modNo;
        _ModuleInfo.push_back( daq_mod );

        if (daqId>=_ModuleContainer.size()) _ModuleContainer.resize( (daqId+1) );
        if (modNo>=_ModuleContainer[daqId].size()) _ModuleContainer[daqId].resize( (modNo+1), NULL );
        if (_ModuleContainer[daqId][modNo]==NULL)
            _ModuleContainer[daqId][modNo] = new UtsusemiEventDataMonitorContainer();

    }
    //////////////////////////////////////////////////////////////////////////
    //!<  UpdateDataModules
    /*!<  This updates all modules for the differential data reduction
     *
     *    @param None
     *    @return None
     */
    void UpdateDataModules(){
        if (_EDC==NULL){
            UtsusemiError( _MessageTag+"UpdateDataModules : _EDC=NULL" );
        }
        isGoodStatus = true;
        for (UInt4 i=0; i<_ModuleInfo.size(); i++){
            UInt4 daqId = _ModuleInfo[i].first;
            UInt4 modNo = _ModuleInfo[i].second;

            bool ret =  UpdateDataModule( daqId, modNo );
            if (ret){
            }else{
                StringTools st;
                UtsusemiError( _MessageTag+"UpdateDataModules() >>> failed update daqid="+st.UInt4ToString(daqId)+", modNo="+st.UInt4ToString(modNo) );
                isGoodStatus = false;
            }
        }
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  UpdateDataModule
    /*!<  This updates given modules for the differential data reduction
     *
     *    @param daqId (UInt4)
     *    @param modNo (UInt4)
     *    @return None
     */
    bool UpdateDataModule(UInt4 daqId, UInt4 modNo){
        if ((daqId+1)>_ModuleContainer.size()){
            StringTools st;
            UtsusemiError( _MessageTag+"UpdateDataModule : given daqId is too large ("+st.UInt4ToString(daqId)+")" );
            return false;
        }
        if ((modNo+1)>_ModuleContainer[daqId].size()){
            StringTools st;
            UtsusemiError( _MessageTag+"UpdateDataModule : given modNo is too large ("+st.UInt4ToString(modNo)+")" );
            return false;
        }
        if (_ModuleContainer[daqId][modNo]==NULL){
            StringTools st;
            UtsusemiError( _MessageTag+"UpdateDataModule : not set files for daqId,modNo="+st.UInt4ToString(daqId)+","+st.UInt4ToString(modNo) );
            return false;
        }

        bool isUpdateEdb = false;
        bool isContinue=true;
        UInt4 num = 0;
        while(isContinue){
            if (num<_ModuleContainer[daqId][modNo]->Edbfiles.size()){
                const boost::filesystem::path path( _ModuleContainer[daqId][modNo]->Edbfiles[num].first );
                const boost::uintmax_t size = boost::filesystem::file_size(path);
                if (_ModuleContainer[daqId][modNo]->Edbfiles[num].second != (UInt4)size){
                    _ModuleContainer[daqId][modNo]->Edbfiles[num].second = (UInt4)size;
                    isUpdateEdb = true;
                }
            }else{
                std::pair<std::string,UInt4> tmp = FindTargetFile( _RunNo, daqId, modNo, num, "edb" );
                if (tmp.first=="") {
                    //std::cout << "UpdateDataModule : cannot find target files. daqId, modNo, num="<< daqId << "," << modNo << "," << num << std::endl;
                    isContinue=false;
                }
                else {
                    _ModuleContainer[daqId][modNo]->Edbfiles.push_back( tmp );
                    isUpdateEdb = true;
                }
            }
            num++;
        }

        num = 0;
        isContinue=true;
        while(isContinue){
            if (num<_ModuleContainer[daqId][modNo]->T0bfiles.size()){
                const boost::filesystem::path path( _ModuleContainer[daqId][modNo]->T0bfiles[num].first );
                const boost::uintmax_t size = boost::filesystem::file_size(path);
                if (_ModuleContainer[daqId][modNo]->T0bfiles[num].second != (UInt4)size){
                    _ModuleContainer[daqId][modNo]->T0bfiles[num].second = (UInt4)size;
                }
            }else{
                std::pair<std::string,UInt4> tmp = FindTargetFile( _RunNo, daqId, modNo, num, "t0b" );
                if (tmp.first=="") isContinue=false;
                else _ModuleContainer[daqId][modNo]->T0bfiles.push_back( tmp );
            }
            num++;
        }

        return isUpdateEdb;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  FindTargetFile
    /*!<  This gets the full path and file size of the data file
     *    of the given modules for the differential data reduction
     *
     *    @param runNO (UInt4)
     *    @param daqId (UInt4)
     *    @param modNo (UInt4)
     *    @param num   (UInt4) the count number for same daqId and modNo
     *    @param ext_code (std::string) ".edb" or "t0b"
     *    @param useOnlyOneDir (bool) whether using only "XXX" data folder or using also "XXX01", "XXX02"...
     *    @return None
     */
    std::pair<std::string,UInt4> FindTargetFile( UInt4 runNo, UInt4 daqId, UInt4 modNo, UInt4 num, std::string ext_code, bool useOnlyOneDir=true ){
        bool isContinue=true;
        std::pair<std::string,UInt4> ret( "", 0 );
        char path1c[150], run_code_c[10], target_c[30];
        std::snprintf( path1c, sizeof(path1c), "%s", _PathToDataRoot.c_str());
        std::snprintf( run_code_c, sizeof(run_code_c), "%s%06d", _EDC->_instCode.c_str(), runNo );
        std::snprintf( target_c, sizeof(target_c), "%3s%06d_%02d_%03d_%03d.%3s", _EDC->_instCode.c_str(), runNo, daqId, modNo, num, ext_code.c_str() );
        std::string run_code( run_code_c );
        std::string target( target_c );
        const boost::filesystem::path path1( path1c );
        if (TargetFolder != ""){
            const boost::filesystem::path pathFolder(TargetFolder);
            if (!(boost::filesystem::is_directory(pathFolder))){
                return ret;
            }
            BOOST_FOREACH( const boost::filesystem::path& p_target,
                           std::make_pair( boost::filesystem::directory_iterator(pathFolder),
                           boost::filesystem::directory_iterator() ) ){
                               // search "SIK000001_00_000_000.edb"
                               if (!(boost::filesystem::is_directory(p_target))){
                                   std::string::size_type ind_tar = p_target.filename().string().find(target);
                                   if (ind_tar==0){
                                       const boost::uintmax_t size = boost::filesystem::file_size(p_target);
                                       ret.first = p_target.string();
                                       ret.second = (UInt4)size;
                                       isContinue=false;
                                       break;
                                   }
                               }
            }
            return ret;
        }
        BOOST_FOREACH( const boost::filesystem::path& p1,
                       std::make_pair( boost::filesystem::directory_iterator(path1),
                                       boost::filesystem::directory_iterator() ) ){
            // search "SIK"
            if (boost::filesystem::is_directory( p1 )){
                std::string::size_type ind_code = p1.filename().string().find( _EDC->_instCode );
                if ((useOnlyOneDir)&&(p1.filename().string().size()!=3)) continue;
                if (ind_code==0){
                    const boost::filesystem::path path2( p1 );
                    BOOST_FOREACH( const boost::filesystem::path& p2,
                                   std::make_pair( boost::filesystem::directory_iterator(path2),
                                                   boost::filesystem::directory_iterator() ) ){
                        // search "SIK000001_20140612"
                        if (boost::filesystem::is_directory( p2 )){ //SIK000001_20140612
                            std::string::size_type ind_fol = p2.filename().string().find( run_code );
                            if (ind_fol==0){
                                const boost::filesystem::path path3( p2 );
                                BOOST_FOREACH( const boost::filesystem::path& p3,
                                               std::make_pair( boost::filesystem::directory_iterator(path3),
                                                               boost::filesystem::directory_iterator() ) ){
                                    // search "SIK000001_00_000_000.edb"
                                    if (!(boost::filesystem::is_directory( p3 )) ){
                                        std::string::size_type ind_tar = p3.filename().string().find( target );
                                        if (ind_tar==0){
                                            const boost::uintmax_t size = boost::filesystem::file_size(p3);
                                            ret.first = p3.string();
                                            ret.second = (UInt4)size;
                                            isContinue=false;
                                            TargetFolder = p2.string() + "/";
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        if (!isContinue) break;
                    }
                }
            }
            if (!isContinue) break;
        }

        return ret;
    }

    UInt4 PutNumOfCases(){
        if (_EDC!=NULL)
            return _EDC->PutNumOfCases();
        else
            return 0;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  PutListOfCounterConditions()
    /*!<  This shows ListOfCounterConditions
     *
     *    @param None
     *    @return std::vector<Double>
     */
    std::vector<Double> PutListOfCounterConditions(){ return _EDC->PutListOfCounterConditions(); }
    //////////////////////////////////////////////////////////////////////////
    //!<  Dump
    /*!<  This shows modules information ( file name, file size )
     *
     *    @param ind (UInt4) unknown
     *    @return None
     */
    void Dump(UInt4 ind=0){
        if ((ind==0)||(ind==1)){
            for (UInt4 daqId=0; daqId<_ModuleContainer.size(); daqId++){
                for (UInt4 modNo=0; modNo<_ModuleContainer[daqId].size(); modNo++){
                    if (_ModuleContainer[daqId][modNo]!=NULL){
                        UtsusemiEventDataMonitorContainer* mc = _ModuleContainer[daqId][modNo];
                        for (UInt4 i=0; i<(mc->Edbfiles.size()); i++){
                            std::pair<std::string,UInt4> tmp = mc->Edbfiles[i];
                            std::cout << "daqId=" << daqId << ",modNo=" << modNo << ", EDB file="+tmp.first << ",size=" << tmp.second <<  std::endl;
                        }
                        for (UInt4 i=0; i<(mc->T0bfiles.size()); i++){
                            std::pair<std::string,UInt4> tmp = mc->T0bfiles[i];
                            std::cout << "daqId=" << daqId << ",modNo=" << modNo << ", T0B file="+tmp.first << ",size=" << tmp.second <<  std::endl;
                        }
                    }
                }
            }
        }
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  IncrementCases
    /*!<  This update TrigNET data to make caseID list
     *
     *    @param None
     *    @return None
     */
    bool IncrementCases(){
        isGoodStatus = false;
        if (_EDC==NULL){
            UtsusemiError( _MessageTag+" Did not set parameters (ParameterSet)" );
            return isGoodStatus;
        }
        // If num of cases is 1 ( not set CaseInfo )
        if (PutNumOfCases()==1){
            isGoodStatus = true;
            return true;
        }

        if (IndexOfCaseFile.empty()){
            UtsusemiMessage( _MessageTag+" IncrementCases >> No TRINGNET cases." );
            return isGoodStatus;
        }

        UInt4 num_of_case_files = (UInt4)(IndexOfCaseFile.size());
        std::vector< std::vector<UInt8> > retCountToLast( num_of_case_files );
        std::vector< std::vector<UInt8> > retT0Indexes( num_of_case_files );
        std::vector< std::vector<UInt8> > retPulseIds( num_of_case_files );
        std::vector< std::vector<Double> > retClockTables( num_of_case_files );
        std::vector< UInt8 > lastPulseIds( num_of_case_files );
        for (UInt4 icf=0;icf<num_of_case_files; icf++){
            UInt4 index = IndexOfCaseFile[icf][0];
            UInt4 ver   = IndexOfCaseFile[icf][1];
            UInt4 daqId = IndexOfCaseFile[icf][2];
            UInt4 modNo = IndexOfCaseFile[icf][3];

            UtsusemiEventDataMonitorContainer* mc = _ModuleContainer[daqId][modNo];

            UInt8 CurrentPosi_t0b = mc->CurrentPosi_t0b;
            UInt4 ind = 0;
            std::vector<std::string> target_t0files;
            if ((mc->T0bfiles.size())==1){
                target_t0files.push_back( mc->T0bfiles[0].first );
            }else{
                for (UInt4 j=0;j<((mc->T0bfiles.size())-1);j++){
                    if (((CurrentPosi_t0b)-((mc->T0bfiles[j].second)/(_BytesOfT0Event)))<0){
                        ind = j;
                        for (UInt4 k=j;k<(mc->T0bfiles.size());k++) target_t0files.push_back( mc->T0bfiles[k].first );
                        break;
                    }else{
                        CurrentPosi_t0b -= mc->T0bfiles[j].second/(_BytesOfT0Event);
                    }
                }
            }

            bool flag=_EDC->PutCaseDecoder()->PutT0TreatTools()->putSlicedT0EventInfo(
                CurrentPosi_t0b, target_t0files, retCountToLast[icf],
                retT0Indexes[icf], retPulseIds[icf], retClockTables[icf] );
            if (!flag){
                UtsusemiError( _MessageTag+"IncrementCases >>> putSlicedT0EventInfo is false. " );
            }
            std::vector< UInt8 >::iterator it=retPulseIds[icf].end();
            lastPulseIds[icf] = *(it-1);
        }

        std::vector<UInt8>::iterator it = min_element( lastPulseIds.begin(), lastPulseIds.end() );

        std::vector< std::vector<UInt8> > T0Indexes( num_of_case_files );
        std::vector< UInt8 > CountToLast( num_of_case_files,0 );
        for (UInt4 icf=0;icf<num_of_case_files; icf++){
            for (UInt4 j=0;j<retPulseIds[icf].size();j++){
                if (retPulseIds[icf][j]<=(*it)){
                    T0Indexes[icf].push_back( retT0Indexes[icf][j] );
                    CountToLast[icf]=retCountToLast[icf][j];
                }else{
                    break;
                }
            }
        }

        std::vector<bool> isReady( num_of_case_files, true );
        for (UInt4 icf=0;icf<num_of_case_files; icf++){
            UInt4 index = IndexOfCaseFile[icf][0];
            UInt4 ver   = IndexOfCaseFile[icf][1];
            UInt4 daqId = IndexOfCaseFile[icf][2];
            UInt4 modNo = IndexOfCaseFile[icf][3];

            UtsusemiEventDataMonitorContainer* mc = _ModuleContainer[daqId][modNo];
            mc->CurrentPosi_t0b += CountToLast[icf];

            // add T0IndexTable which is not used in previous Increment()
            UInt4 sizeOfLeftT0IndexTable = (UInt4)(mc->LeftT0IndexTable.size());
            if (( sizeOfLeftT0IndexTable==0 )&&(retT0Indexes[icf].size()==1)){
                isReady[icf]=false;
                continue;
            }
            std::vector<UInt8> table( (sizeOfLeftT0IndexTable+retT0Indexes[icf].size()), 0 );
            for (UInt4 i=0;i<sizeOfLeftT0IndexTable;i++) table[i]=mc->LeftT0IndexTable[i];
            for (UInt4 i=0;i<retT0Indexes[icf].size();i++) table[i+sizeOfLeftT0IndexTable] = retT0Indexes[icf][i];

            // slice Event data by table of T0Index differentials
            std::vector<std::string> edb_files( mc->Edbfiles.size(),"");
            for (UInt4 i=0;i<mc->Edbfiles.size();i++) edb_files[i] = mc->Edbfiles[i].first;

            UChar* data = new UChar[ (table[table.size()-1]-table[0])*ElementSize ];
            Int8 lastIndexOfTable = Read( edb_files, table, data );
            UInt8 numOfReadEvents = table[lastIndexOfTable]-table[0];

            // unused T0index differentials are stored in _leftT0IndexTable.
            mc->LeftT0IndexTable.clear();
            if (lastIndexOfTable!=(table.size()-1)){
                for (UInt8 i=lastIndexOfTable;i<table.size();i++) {
                    mc->LeftT0IndexTable.push_back( table[i] );
                }
            }

            // make T0 table for increments of sliced events
            std::vector<UInt8> t0table( (lastIndexOfTable+1), 0 );
            for (UInt4 i=0;i<(lastIndexOfTable+1);i++) {
                t0table[i] = table[i]-table[0];
            }

            // Increment of sliced event in histogram
            UChar* data2 = new UChar[ numOfReadEvents*ElementSize ];
            for (UInt4 i=0;i<(numOfReadEvents*ElementSize);i++) data2[i]=data[i];


            _EDC->PutCaseDecoder()->PutFilter()->ClearAllTables(index, true);
            _EDC->PutCaseDecoder()->PutFilter()->PreCaseSorting( data2, t0table, index );
            _EDC->PutCaseDecoder()->PutFilter()->isTrigTableReady=true;
            _EDC->PutCaseDecoder()->PutFilter()->MakeCaseTable();

            _EDC->PutCaseDecoder()->PutFilter()->CheckAmbiguousFrame();
            mc->LastPulseId = retPulseIds[icf].back();

            delete [] data;
            delete [] data2;

        }

        for (UInt4 i=0; i<num_of_case_files; i++)
            if (isReady[i]){
            }else{
                return isGoodStatus;
            }
        std::vector<UInt8> tmp_Pulse = _EDC->PutCaseDecoder()->PutFilter()->filterPulseIdList;
        std::vector< std::vector<UInt4>* >* tmp_cases = _EDC->PutCaseDecoder()->PutFilter()->filterCaseTable;

        // Increment Kickers for each case
        for (UInt4 i=0; i<(tmp_cases->size()); i++){
            if (tmp_cases->at(i)!=NULL){
                UInt4 a_case = tmp_cases->at(i)->at(0);
                if (a_case>=(_KickersForCases.size())) _KickersForCases.resize( (a_case+1),0 );
                _KickersForCases[a_case]++;
            }
        }

        // CaseList is kept forever...
        UInt4 org_size = (UInt4)(PulseIdOfCases.size());
        if ((isReadout)&&(org_size==0)&&(!(tmp_Pulse.empty()))) firstPulseId = tmp_Pulse[0]; //[inamura 170220]
        PulseIdOfCases.resize( (org_size+tmp_Pulse.size()),0 );
        CaseList.resize( (org_size+(tmp_cases->size())), NULL );

        if ((tmp_cases->size())!=tmp_Pulse.size()) UtsusemiWarning( _MessageTag+"UtsusemiIncrementCases (tmp_cases->size())!=tmp_Pulse.size())" );
        for (UInt4 i=0; i<tmp_Pulse.size(); i++){
            PulseIdOfCases[ org_size + i ] = tmp_Pulse[i] - firstPulseId; //[inamura 170220]
            if (tmp_cases->at(i)!=NULL){
                CaseList[org_size+i] = new std::vector<UInt4> ( tmp_cases->at(i)->size(), 0 );
                for (UInt4 j=0; j< tmp_cases->at(i)->size(); j++)
                    CaseList[org_size+i]->at(j) = tmp_cases->at(i)->at(j);
            }else{
                StringTools st;
                UtsusemiError( _MessageTag+"UtsusemiIncrementCases (tmp_cases i="+st.UInt4ToString(i)+" is NULL" );
            }
        }

        isGoodStatus = true;
        return isGoodStatus;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  Increment
    /*!<  This update all data for the differential data reduction
     *
     *    @param daqId (UInt4)
     *    @param modNo (UInt4)
     *    @return None
     */
    void Increment( bool doRead=true ){
        ClearUpdatedCases();
        for (UInt4 i=0; i<_ModuleInfo.size(); i++)
            Increment( _ModuleInfo[i].first, _ModuleInfo[i].second, doRead );
    }
    void Increment( UInt4 daqId, UInt4 modNo, bool doRead=true ){
        UInt4 num_of_case_files = (UInt4)(IndexOfCaseFile.size());
        for (UInt4 icf=0;icf<num_of_case_files; icf++){
            UInt4 daqId_case = IndexOfCaseFile[icf][2];
            UInt4 modNo_case = IndexOfCaseFile[icf][3];
            if ((daqId==daqId_case)&&(modNo==modNo_case)) return;
        }
        StringTools st;
        UtsusemiMessage( _MessageTag+" --- Increment daq,mod="+st.UInt4ToString(daqId)+","+st.UInt4ToString(modNo) );

        isGoodStatus = false;
        bool isSet = false;
        for (UInt4 i=0; i<_ModuleInfo.size(); i++){
            if ( (daqId==_ModuleInfo[i].first)&&(modNo==_ModuleInfo[i].second) ){
                isSet = true;
                break;
            }
        }
        if (!isSet){
            std::string msg = _MessageTag+"Increment >> such daqId and modNo is not set (daqId="+st.UInt4ToString(daqId);
            UtsusemiError( msg+", modNo="+st.UInt4ToString(modNo) );
            return;
        }

        UtsusemiEventDataMonitorContainer* mc = _ModuleContainer[daqId][modNo];

        // pick up differential between previous T0 Index Event file and current one.
        std::vector<UInt8> retCountToLast;
        std::vector<UInt8> retT0Index;
        std::vector<UInt8> retPulseId;
        std::vector<Double> retClockTable;

        UInt8 CurrentPosi_t0b = mc->CurrentPosi_t0b;
        UInt4 ind = 0;
        std::vector<std::string> target_t0bfiles;

        if ((mc->T0bfiles.size())==0){
            std::string msg = _MessageTag+"Increment >> cannot find t0b files (daqId,modNo)="+st.UInt4ToString(daqId);
            UtsusemiError( msg+","+st.UInt4ToString(modNo) );
            return;
        }else if ((mc->T0bfiles.size())==1){
            target_t0bfiles.push_back( mc->T0bfiles[0].first );
        }else{
            for (UInt4 j=0;j<((mc->T0bfiles.size())-1);j++){
                if (((CurrentPosi_t0b)-((mc->T0bfiles[j].second)/(_BytesOfT0Event)))<0){
                    ind = j;
                    for (UInt4 k=j;k<(mc->T0bfiles.size());k++) target_t0bfiles.push_back( mc->T0bfiles[k].first );
                    break;
                }else{
                    CurrentPosi_t0b -= mc->T0bfiles[j].second/(_BytesOfT0Event);
                }
            }
        }

        if (mc->LeftPulseIdTable.empty()){
            _EDC->PutCaseDecoder()->PutT0TreatTools()->CurrentClockSliced.first = mc->CurrentClockSliced.first;
            _EDC->PutCaseDecoder()->PutT0TreatTools()->CurrentClockSliced.second= mc->CurrentClockSliced.second;
        }
        bool flag=_EDC->PutCaseDecoder()->PutT0TreatTools()->putSlicedT0EventInfo(
            CurrentPosi_t0b, target_t0bfiles, retCountToLast,
            retT0Index, retPulseId, retClockTable, mc->LastPulseId );
        if (flag){
            if ((retPulseId.empty())||(retT0Index.empty())||(retClockTable.empty())){
                UtsusemiError( _MessageTag+"::Increment >> T0Index data may be empty." );
                return;
            }
        }else{
            return;
        }

        // add T0IndexTable and DiffClockTable which are not used in previous Increment
        UInt4 num_of_ret_vec = (UInt4)(retPulseId.size());
        UInt4 num_of_left_vec = (UInt4)(mc->LeftPulseIdTable.size());
        std::vector<UInt8> PulseId( mc->LeftPulseIdTable.begin(), mc->LeftPulseIdTable.end() );
        std::vector<UInt8> T0Table( mc->LeftT0IndexTable.begin(), mc->LeftT0IndexTable.end() );
        std::vector<Double> ClockTable( mc->LeftDiffClockTable.begin(), mc->LeftDiffClockTable.end() );
        PulseId.reserve( num_of_left_vec+num_of_ret_vec );
        T0Table.reserve( num_of_left_vec+num_of_ret_vec );
        ClockTable.reserve( num_of_left_vec+num_of_ret_vec );

        // Check Measurement period
        mc->CurrentClockSliced.first = _EDC->PutCaseDecoder()->PutT0TreatTools()->CurrentClockSliced.first;
        mc->CurrentClockSliced.second = _EDC->PutCaseDecoder()->PutT0TreatTools()->CurrentClockSliced.second;
        if (((mc->MeasClockSliced.first)<0.0)||
            ((_EDC->PutCaseDecoder()->PutT0TreatTools()->MeasClockSliced.first)<(mc->MeasClockSliced.first)))
            mc->MeasClockSliced.first = _EDC->PutCaseDecoder()->PutT0TreatTools()->MeasClockSliced.first;
        if ((_EDC->PutCaseDecoder()->PutT0TreatTools()->MeasClockSliced.second)>(mc->MeasClockSliced.second))
            mc->MeasClockSliced.second = _EDC->PutCaseDecoder()->PutT0TreatTools()->MeasClockSliced.second;

        // comparing PulseId between TrigNET and Neutron
        std::vector< std::vector<UInt4>* > *CaseTable = new std::vector< std::vector<UInt4>* >;
        UInt8 firstPulseId_Neutron( PulseId.front() );
        UInt8 lastPulseId_Neutron( retPulseId.back() );
        bool isIncrementReady = false;
        UInt8 CountToLast = 0;
        if (PulseIdOfCases.empty()){
            PulseId.insert( PulseId.end(), retPulseId.begin(), retPulseId.end() );
            T0Table.insert( T0Table.end(), retT0Index.begin(), retT0Index.end() );

            ClockTable.insert( ClockTable.end(), retClockTable.begin(), retClockTable.end() );
            //CountToLast = retCountToLast[ retCountToLast.size()-1 ];
            CountToLast = retCountToLast.back();
            mc->CurrentPosi_t0b += CountToLast;
            isIncrementReady = true;
        }else{
            UInt8 lastPulseId_TRIGNET( PulseIdOfCases.back() );
            UInt4 num_cases_pid( (UInt4)(PulseIdOfCases.size()) );
            isIncrementReady = false;
            if (lastPulseId_TRIGNET>lastPulseId_Neutron){
                UInt4 first_cases_index = 0;
                UInt4 last_cases_index = 0;
                bool isFoundFirst = false;
                bool isFoundLast = false;
                for (UInt4 i=0;i<num_cases_pid;i++){
                    if (PulseIdOfCases[num_cases_pid-1-i]==lastPulseId_Neutron){
                        last_cases_index = num_cases_pid-1-i;
                        isFoundLast = true;
                    }
                    if (PulseIdOfCases[num_cases_pid-1-i]==firstPulseId_Neutron){
                        first_cases_index = num_cases_pid-1-i;
                        isFoundFirst = true;
                    }
                    if (isFoundLast && isFoundFirst) break;
                }
                if (isFoundLast && isFoundFirst){
                    CaseTable->resize( last_cases_index-first_cases_index+1, NULL );
                    CaseTable->assign( (CaseList.begin()+first_cases_index), (CaseList.begin()+last_cases_index+1) );
                    PulseId.insert( PulseId.end(), retPulseId.begin(), retPulseId.end() );
                    T0Table.insert( T0Table.end(), retT0Index.begin(), retT0Index.end() );
                    ClockTable.insert( ClockTable.end(), retClockTable.begin(), retClockTable.end() );
                    //CountToLast = retCountToLast[ retCountToLast.size()-1 ];
                    CountToLast = retCountToLast.back();
                    isIncrementReady = true;
                    /*
                      std::cout << "### CaseTable.size(), T0Table.size()="<<CaseTable->size()<<","<< T0Table.size()<<std::endl;
                      for (UInt4 k=0; k<(PulseId.size()); k++) std::cout << PulseId[k] << ",";
                      std::cout << std::endl;
                    */
                }else{
                    UtsusemiError( _MessageTag+"#### Not Found PulseId of Cases equal that of Neunet" );
                }
            }else{ // lastPulseId_TRIGNET <= lastPulseId_Neutron
                UInt4 num_pid = (UInt4)(retPulseId.size());
                UInt4 last_index = 0;
                bool isFound = false;
                for (UInt4 i=0; i<num_pid; i++){
                    if (retPulseId[num_pid-1-i]==lastPulseId_TRIGNET){
                        last_index = num_pid-1-i;
                        isFound = true;
                        break;
                    }
                }
                if (isFound){
                    UInt4 first_case_index = 0;
                    if (PulseId.empty()){
                        CaseTable->resize( last_index,NULL );
                        CaseTable->assign( CaseList.begin()+(num_cases_pid-1)-last_index, CaseList.end() );
                    }else{
                        for (UInt4 i=0;i<num_cases_pid;i++){
                            if (PulseIdOfCases[num_cases_pid-1-i]==firstPulseId_Neutron){
                                first_case_index = num_cases_pid-1-i;
                                break;
                            }
                        }
                        CaseTable->resize( CaseList.size()-first_case_index,NULL );
                        CaseTable->assign( CaseList.begin()+first_case_index, CaseList.end() );
                    }

                    PulseId.insert( PulseId.end(), retPulseId.begin(), retPulseId.begin()+last_index );
                    T0Table.insert( T0Table.end(), retT0Index.begin(), retT0Index.begin()+last_index );
                    ClockTable.insert( ClockTable.end(), retClockTable.begin(), retClockTable.begin()+last_index );
                    CountToLast = retCountToLast[ last_index-1 ]; //[inamura 161118]
                    isIncrementReady = true;
                }else{
                }
            }
            mc->CurrentPosi_t0b += CountToLast;
        }

        if (!doRead){
            mc->LeftPulseIdTable.clear();
            mc->LeftT0IndexTable.clear();
            mc->LeftDiffClockTable.clear();
            mc->LastPulseId = PulseId.back();
        }else if ((isIncrementReady)&&(T0Table.size()>1)){
            // slice Event data
            UChar* data = new UChar[ ( T0Table.back() - T0Table[0] )*ElementSize ];

            UInt4 offset = 0;
            std::vector<std::string> targetFiles;
            for (UInt4 i=0; i<(mc->Edbfiles.size()); i++){
                if ( T0Table[0]>=((mc->Edbfiles[i].second)/ElementSize+offset) ){
                    offset += (UInt4)((mc->Edbfiles[i].second)/ElementSize);
                }else{
                    targetFiles.push_back( mc->Edbfiles[i].first );
                }
            }
            std::vector<UInt8> T0Table_offseted( T0Table.begin(),T0Table.end() );
            for (std::vector<UInt8>::iterator it=T0Table_offseted.begin();it!=T0Table_offseted.end();++it)
                (*it) -= offset;

            Int8 lastIndexOfTable = Read( targetFiles, T0Table_offseted, data );
            UInt8 numOfReadEvents = T0Table[lastIndexOfTable]-T0Table[0];

            // store unused T0Index differential
            mc->LeftPulseIdTable.clear();
            mc->LeftT0IndexTable.clear();
            mc->LeftDiffClockTable.clear();
            if (lastIndexOfTable!=(T0Table.size()-1)){
                for (UInt8 i=(lastIndexOfTable+1);i<(T0Table.size()-1);i++){
                    mc->LeftPulseIdTable.push_back( PulseId[i] );
                    mc->LeftT0IndexTable.push_back( T0Table[i] );
                    mc->LeftDiffClockTable.push_back( ClockTable[i] );
                }
            }

            // make T0 table for increment
            std::vector<UInt8> t0_table( (lastIndexOfTable+1), 0 );
            std::vector<Double> cl_table( (lastIndexOfTable+1), 0 );
            for (UInt4 i=0;i<(lastIndexOfTable+1);i++)
                t0_table[i] = T0Table[i]-T0Table[0];
            cl_table.assign( ClockTable.begin(), ClockTable.end() );

            // Increment
            UChar* data2 = new UChar[ numOfReadEvents*ElementSize ];
            for (UInt4 i=0;i<(numOfReadEvents*ElementSize);i++) data2[i]=data[i];

            _EDC->PreIncrement( daqId, modNo, data2, t0_table, cl_table, CaseTable );
            mc->LastPulseId = PulseId.back();

            delete [] data2;
            delete [] data;
        }
        std::vector<UInt4> updated_cases( CaseTable->size() );
        for (UInt4 i=0;i<(updated_cases.size());i++)
            updated_cases[i] = CaseTable->at(i)->at(0);
        sort( updated_cases.begin(), updated_cases.end() );
        updated_cases.erase( unique(updated_cases.begin(),updated_cases.end()), updated_cases.end() );
        for (std::vector<UInt4>::iterator it=updated_cases.begin(); it!=updated_cases.end(); ++it)
            _UpdatedCases.push_back( (*it) );
        delete CaseTable;
        isGoodStatus = true;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  Updated data
    /*!<  This function executes commands below :
     *      UpdataDataModules()
     *      IncrementCases()
     *      Increment()
     *
     *    bool Update()
     *
     *    @return None
     */
    bool Update(bool doRead=true){
        UpdateDataModules();
        if (isGoodStatus){
            IncrementCases();
            if (isGoodStatus){
                Increment(doRead);
                if (isGoodStatus)
                    return true;
                else
                    UtsusemiError( _MessageTag+"Update() >>> Increment Fails" );
            }else
                UtsusemiError(  _MessageTag+"Update() >>> IncrementCases Fails" );
        }else
            UtsusemiError( _MessageTag+"Update() >>> UpdateDataModules Fails" );
        return false;
    }

    //////////////////////////////////////////////////////////////////////////
    //!<  Output stored data
    /*!<
     *    Output( std::string OutputFileName );
     *    Output( ElementContainerMatrix* ecm );
     *    Output( ElementContainer* ec, UInt4 pixelId );
     *
     *    @param OutputFileName (std::string) saves ElementContainer as files
     *    @param ecm (ElementContainerMatrix) gives ElementContainerMatrix
     *    @param pixelId (UInt4) pixel Id of ElementContainer to get
     *    @return None
     */
    void Output( std::string OutputFileName ){
        isGoodStatus = false;
        ElementContainerMatrix* resultECM = new ElementContainerMatrix();
        _EDC->SetElementContainerMatrix( resultECM );
        SetMeasTimeSliced( resultECM->PutHeaderPointer() );
        WriteSerializationFile<boost::archive::binary_oarchive>  wsf(OutputFileName.c_str());
        wsf.Save( (*resultECM) );
        delete resultECM;
        isGoodStatus = true;
    }
    void Output( ElementContainerMatrix* ecm, UInt4 caseId=1 ){
        _EDC->SetElementContainerMatrixForPseudOnLineMon(ecm,caseId);
        SetMeasTimeSliced( ecm->PutHeaderPointer() );
        SetKickers( ecm->PutHeaderPointer(), caseId );
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  Clear makes stored data empty
    /*!<  This makes intensities for each pixels to zero.
     *
     *    @return None
     */
    void Clear(){
        _EDC->ResetHistogram();
        for (UInt4 i=0;i<_ModuleContainer.size();i++){
            for (UInt4 j=0;j<_ModuleContainer[i].size();j++){
                if (_ModuleContainer[i][j]!=NULL){
                    _ModuleContainer[i][j]->MeasClockSliced.first= -1.0;
                    _ModuleContainer[i][j]->MeasClockSliced.second= -1.0;
                    _ModuleContainer[i][j]->CurrentClockSliced.first = 0.0;
                    _ModuleContainer[i][j]->CurrentClockSliced.second = 0.0;
                }
            }
        }
        for (UInt4 i=0;i<IndexOfCaseFile.size(); i++){
            UInt4 ind = IndexOfCaseFile[i][0];
            _EDC->PutCaseDecoder()->PutFilter()->ClearAllTables( ind );
        }
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  SetMeasTimeSliced
    /*!<  This adds the information of the  measurement period for sliced data
     *
     *    @param hh  (HeaderBase*)
     *    @return None
     */

    void SetMeasTimeSliced( HeaderBase* hh ){
        Double min_clock = 0.0;
        Double max_clock = 0.0;
        for (UInt4 i=0;i<_ModuleContainer.size();i++){
            for (UInt4 j=0;j<_ModuleContainer[i].size();j++){
                if (_ModuleContainer[i][j]!=NULL){
                    if ((_ModuleContainer[i][j]->MeasClockSliced.second)>-1.0){
                        if ((min_clock==0.0)||(min_clock>(_ModuleContainer[i][j]->MeasClockSliced.first)))
                            min_clock = _ModuleContainer[i][j]->MeasClockSliced.first;
                        if ((max_clock==0.0)||(max_clock<(_ModuleContainer[i][j]->MeasClockSliced.second)))
                            max_clock = _ModuleContainer[i][j]->MeasClockSliced.second;
                    }
                }
            }
        }

        std::vector<Double> start_p = _EDC->PutCaseDecoder()->PutT0TreatTools()->convertInstClockToDateTime( min_clock );
        std::vector<Double> end_p = _EDC->PutCaseDecoder()->PutT0TreatTools()->convertInstClockToDateTime( max_clock );
        std::vector<Double> tmp(14);
        for (UInt4 i=0;i<7;i++){
            tmp[i] = start_p[i];
            tmp[i+7] = end_p[i];
        }
        if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MEASPERIOD)==1) hh->OverWrite( UTSUSEMI_KEY_HEAD_MEASPERIOD, tmp );
        else hh->Add( UTSUSEMI_KEY_HEAD_MEASPERIOD, tmp );
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  SetKickers
    /*!<  This adds the number of kickers into HeaderBase
     *
     *    @param hh     (HeaderBase*)
     *    @param caseId (UInt4)
     *    @return None
     */
    void SetKickers( HeaderBase* hh, UInt4 caseId=0 ){
        if (caseId>=(_KickersForCases.size())) return;
        if (hh->CheckKey(UTSUSEMI_KEY_HEAD_KICKERCOUNT)==1) hh->OverWrite(UTSUSEMI_KEY_HEAD_KICKERCOUNT, _KickersForCases[caseId]);
        else hh->Add(UTSUSEMI_KEY_HEAD_KICKERCOUNT, _KickersForCases[caseId]);
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  ClearDataFileSets clears data files
    /*!<
     *
     *    @return None
     */
    void ClearDataFileSets(){
        EventDataMonitorBase::ClearDataFileSets();
        for (UInt4 i=0;i<_leftT0IndexTable.size();i++){
            _leftT0IndexTable[i].clear();
        }
        _leftT0IndexTable.clear();
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  PutUpdatedCases
    /*!<  This returns the list of cases that update happened on updating modules
     *
     *    @param None
     *    @return None
     */
    std::vector<UInt4> PutUpdatedCases(){
        sort( _UpdatedCases.begin(), _UpdatedCases.end() );
        _UpdatedCases.erase( unique(_UpdatedCases.begin(),_UpdatedCases.end()), _UpdatedCases.end() );
        return _UpdatedCases;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  ClearUpdatedCases
    /*!<  This clears the list of cases that update happened on updating modules
     *
     *    @param None
     *    @return None
     */
    void ClearUpdatedCases(){ _UpdatedCases.clear(); }
    //////////////////////////////////////////////////////////////////////////
    bool isGoodStatus;

    bool AddRunInfoToHeader( HeaderBase* _hh, UInt4 caseId=1 ){
        return _EDC->AddRunInfoToHeader( _hh, caseId );
    }

};

#endif
