#ifndef UTSUSEMIREDISPUBSUBEVENTMONITORTEMPLATE_HH
#define UTSUSEMIREDISPUBSUBEVENTMONITORTEMPLATE_HH

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

#include "UtsusemiRedisPubSubEventContainer.hh"
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

///////////////////////////////////////////
//  UtsusemiRedisPubSubEventMonitorTemplate
///////////////////////////////////////////

//! 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
 *
 *
 */
template <typename T1>
class UtsusemiRedisPubSubEventMonitorTemplate
{
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::string _redisHost;
    UInt4 _redisPort;
    std::vector< std::pair<UInt4,UInt4> > _ModuleInfo;
    std::vector< std::vector< UtsusemiRedisPubSubEventContainer* > > _ModuleContainer; /**<  [daqId][modNo]   */
    UInt4 _RunNo;
    //UInt4 _BytesOfT0Event;
    std::vector<Int4> _KickersForCases;
    std::vector<UInt4> _UpdatedCases;

    bool _isDebug;

public:
    T1* _EDC;  //EventDataConverterXXX

    //std::vector< std::vector<UInt4> > _leftT0IndexTable;

    bool isReadout;
    UInt8 firstPulseId;
    //////////////////////////////////////////////////////////////////////////
    //!< Constructor
    /*!<
     */
    UtsusemiRedisPubSubEventMonitorTemplate(std::string host="localhost", UInt4 port=6379){
        _EDC = NULL;
        //_leftT0IndexTable.clear();

        //_PathToDataRoot= "";
        _ModuleInfo.clear();
        _ModuleContainer.clear();
        _RunNo = 0;
        //_BytesOfT0Event = 8;
        _MessageTag = "UtsusemiRedisPubSubEventMonitorTemplate >> ";
        _KickersForCases.clear();
        _UpdatedCases.clear();
        isReadout = false;
        firstPulseId = 0;

        _redisHost = host;
        _redisPort = port;
        _isDebug = false;
    }
    //////////////////////////////////////////////////////////////////////////
    //!< Destructor
    /*!<
     */
    ~UtsusemiRedisPubSubEventMonitorTemplate(){
        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; }
    //////////////////////////////////////////////////////////////////////////
    //!<  SetRedisServer
    /*!<  This sets Queue host and port
     *
     *    @param host (std::string) host name of Queue server
     *    @param port (UInt4)  port number to access to Queue server
     *    @return None
     */
    void SetRedisServer(std::string host="localhost", UInt4 port=6379){
        _redisHost = host;
        _redisPort = port;
    }
    //////////////////////////////////////////////////////////////////////////
    //!< 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();
        _EDC->LoadParamFiles( _WireingFile, _DetectorInfoFile, _CaseInfoFile );
        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;
    }

    //////////////////////////////////////////////////////////////////////////
    //!<  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{
            UtsusemiWarning( _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) ){
                std::cout << _MessageTag + "AddDataModules >> already added given daqId,modNo = "<< daqId << "," << modNo << std::endl;
                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 UtsusemiRedisPubSubEventContainer();

    }
    //////////////////////////////////////////////////////////////////////////
    //!<  InitializeModules
    /*!<  This does initialization (Subscribe) for all modules
     *
     *    @param None
     *    @retval true  : succeeded.
     *    @retval false : failed.
     */
    std::vector<bool> InitializeDataModules(){
        std::vector<bool> ret_list(_ModuleInfo.size(),false);
        if (_EDC==NULL){
            UtsusemiError(_MessageTag+ "InitializeDataModules : _EDC=NULL");
            return ret_list;
        }
        if ((_EDC->_instCode=="")||(_RunNo==0)){
            UtsusemiError(_MessageTag+"RunNumber is not set yet");
            return ret_list;
        }
        isGoodStatus = true;

        for (UInt4 i=0; i<_ModuleInfo.size(); i++){
            UInt4 daqId = _ModuleInfo[i].first;
            UInt4 modNo = _ModuleInfo[i].second;
            bool ret =  InitializeDataModule( daqId, modNo );
            if (ret){
            }else{
                std::cout << _MessageTag+"InitializeDataModules() >>> failed update daqid="<<daqId<<", modNo="<<modNo<<std::endl;
                isGoodStatus = false;
            }
            ret_list[i] = ret;
        }
        return ret_list;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  UpdateDataModule
    /*!<  This updates given modules for the differential data reduction
     *
     *    @param daqId (UInt4)
     *    @param modNo (UInt4)
     *    @return None
     */
    bool InitializeDataModule(UInt4 daqId, UInt4 modNo){
        if ((daqId+1)>_ModuleContainer.size()){
            std::cout << "InitializeDataModule : given daqId is too large ("<<daqId<<")"<<std::endl;
            return false;
        }
        if ((modNo+1)>_ModuleContainer[daqId].size()){
            std::cout << "InitializeDataModule : given modNo is too large ("<<modNo<<")"<<std::endl;
            return false;
        }
        if (_ModuleContainer[daqId][modNo]==NULL){
            std::cout << "InitializeDataModule : not set files for daqId,modNo="<<daqId<<","<<modNo<<std::endl;
            return false;
        }

        UtsusemiRedisPubSubEventContainer* mc = _ModuleContainer[daqId][modNo];
        if ((mc->isInitialized()))
            return true;
        else{
            if (mc->Initialize( _EDC->_instCode, _RunNo, daqId, modNo, _redisHost, _redisPort )){
                return true;
            }else{
                return false;
            }
        }
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  UpdateDataModules
    /*!<  This updates all modules for the differential data reduction
     *
     *    @param None
     *    @return None
     */
    void UpdateDataModules(){
        if (_EDC==NULL){
            std::cout << "UpdateDataModules : _EDC=NULL" << std::endl;
            return;
        }
        if ((_EDC->_instCode=="")||(_RunNo==0)){
            UtsusemiError(_MessageTag+"RunNumber is not set yet");
            return;
        }
        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{
                std::cout << _MessageTag+"UpdateDataModules() >>> failed update daqid="<<daqId<<", modNo="<<modNo<<std::endl;
                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()){
            std::cout << "UpdateDataModule : given daqId is too large ("<<daqId<<")"<<std::endl;
            return false;
        }
        if ((modNo+1)>_ModuleContainer[daqId].size()){
            std::cout << "UpdateDataModule : given modNo is too large ("<<modNo<<")"<<std::endl;
            return false;
        }
        if (_ModuleContainer[daqId][modNo]==NULL){
            std::cout << "UpdateDataModule : not set files for daqId,modNo="<<daqId<<","<<modNo<<std::endl;
            return false;
        }

        UtsusemiRedisPubSubEventContainer* mc = _ModuleContainer[daqId][modNo];
        if (_isDebug) std::cout << "-- UpdateDataModule daqId:modNo = " << daqId << ":" << modNo << std::endl;
        mc->isDebug = _isDebug;
        if ((mc->isInitialized()))
            return mc->Update();
        else{
            if (mc->Initialize( _EDC->_instCode, _RunNo, daqId, modNo, _redisHost, _redisPort )){
                return mc->Update();
            }else{
                return false;
            }
        }

    }
    //////////////////////////////////////////////////////////////////////////
    //!<  PutListOfCounterConditions()
    /*!<  This shows ListOfCounterConditions
     *
     *    @param None
     *    @return std::vector<Double>
     */
    std::vector<Double> PutListOfCounterConditions(){ return _EDC->PutListOfCounterConditions(); }
    //////////////////////////////////////////////////////////////////////////
    UInt4 PutNumOfCases(){
        if (_EDC!=NULL)
            return _EDC->PutNumOfCases();
        else
            return 0;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  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){
                        UtsusemiRedisPubSubEventContainer* mc = _ModuleContainer[daqId][modNo];

                    }
                }
            }
        }
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  IncrementCases
    /*!<  This update TrigNET data to make caseID list
     *
     *    @param None
     *    @return None
     */
    bool IncrementCases(){
        isGoodStatus = false;
        if (_EDC==NULL){
            std::cout << _MessageTag << " Did not set parameters (ParameterSet)" << std::endl;
            return isGoodStatus;
        }
        // If num of cases is 1 ( not set CaseInfo )
        if (PutNumOfCases()==1){
            isGoodStatus = true;
            return true;
        }

        if (IndexOfCaseFile.empty()){
            std::cout << _MessageTag << " IncrementCases >> No TRINGNET cases." << std::endl;
            return isGoodStatus;
        }

        UInt4 num_of_case_files = IndexOfCaseFile.size();
        std::vector< std::vector<UInt8> > retPulseIds( num_of_case_files );
        std::vector< std::vector<UInt8> > retT0Indexes( 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];

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

            retPulseIds[icf] = mc->PutPulseIdTable();
            if (retPulseIds[icf].empty())
                lastPulseIds[icf] = 0;
            else
                lastPulseIds[icf] = retPulseIds[icf].back();
            retT0Indexes[icf] = mc->PutT0IndexTable();
        }

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

        std::vector< std::vector<UInt8> > T0Indexes( num_of_case_files );
        //std::vector< UInt4 > 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{
                    retPulseIds[icf].clear();
                    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];

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

            std::vector<Double> *dum_ClockTables = new std::vector<Double>();
            if (mc->SetReference( &(PulseIdOfCases) ) ){
                UInt4 num_of_buf=mc->PutEventSize();
                UChar *buf = new UChar[ num_of_buf ];
                if ( mc->Put( buf, &num_of_buf, &(retPulseIds[icf]), dum_ClockTables, &(retT0Indexes[icf]), NULL ) ){
                    _EDC->PutCaseDecoder()->PutFilter()->ClearAllTables(index, true);
                    //for (UInt4 k=0; k<retT0Indexes[icf].size(); k++) std::cout << retT0Indexes[icf][k] << ",";
                    //std::cout << std::endl;
                    _EDC->PutCaseDecoder()->PutFilter()->PreCaseSorting( buf, retT0Indexes[icf], index );
                    _EDC->PutCaseDecoder()->PutFilter()->isTrigTableReady=true;
                    _EDC->PutCaseDecoder()->PutFilter()->MakeCaseTable();
                    _EDC->PutCaseDecoder()->PutFilter()->CheckAmbiguousFrame();
                }else{
                    isReady[icf]=false;
                }
                delete [] buf;
                delete dum_ClockTables;
            }else{
                UtsusemiWarning( _MessageTag+"IncrementCases >> SetReference is false" );
            }
        }

        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 = PulseIdOfCases.size();
        if ((isReadout)&&(org_size==0)&&(!(tmp_Pulse.empty()))) firstPulseId = tmp_Pulse[0]; //[inamura 170220]
        PulseIdOfCases.resize( (org_size+tmp_Pulse.size()),0.0 );
        for (UInt4 i=0; i<CaseList.size(); i++)
            if (CaseList[i]!=NULL) delete CaseList[i];
        CaseList.resize( (org_size+(tmp_cases->size())), NULL );

        if ((tmp_cases->size())!=tmp_Pulse.size()) std::cout << "## (tmp_cases->size())!=tmp_Pulse.size())" << std::endl;
        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.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{
                std::cout << "## tmp_cases i="<<i<<" is NULL" << std::endl;
            }
        }

        //std::cout << "### PulseIdOfCases = ";
        //for (UInt4 i=0; i<(PulseIdOfCases.size());i++) std::cout << PulseIdOfCases[i] << ",";
        //std::cout << std::endl;

        isGoodStatus = true;
        return isGoodStatus;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  Increment
    /*!<  This update all data for the differential data reduction
     *
     *    @param daqId (UInt4)
     *    @param modNo (UInt4)
     *    @return None
     */
    void Increment(){
        ClearUpdatedCases();
        for (UInt4 i=0; i<_ModuleInfo.size(); i++)
            Increment( _ModuleInfo[i].first, _ModuleInfo[i].second );
    }
    void Increment( UInt4 daqId, UInt4 modNo ){
        //std::cout << "Template::Increment start" << std::endl;
        UInt4 num_of_case_files = 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;
        }

        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::cout << _MessageTag+"Increment >> such daqId and modNo is not set (daqId=" << daqId;
            std::cout << ", modNo=" << modNo << std::endl;
            return;
        }

        UtsusemiRedisPubSubEventContainer* mc = _ModuleContainer[daqId][modNo];
        std::vector< std::vector<UInt4>* >* CaseTable = new std::vector< std::vector<UInt4>* >;
        // If num of cases is 1 ( not set CaseInfo )
        if (PutNumOfCases()==1){
            UInt4 num_of_data = mc->PutEventSize();
            UChar *data = new UChar[ num_of_data ];
            std::vector<UInt8> retPulseId;
            std::vector<Double> retT0Clock;
            std::vector<UInt8> retIndex;
            if (mc->Put( data, &num_of_data, &retPulseId, &retT0Clock, &retIndex, CaseTable )){
                std::vector<Double> t0Clock( retT0Clock.size()+1, 0);
                copy( retT0Clock.begin(), retT0Clock.end(), t0Clock.begin()+1);
                std::vector<UInt8> t0Index( retIndex.size()+1,0 );
                copy( retIndex.begin(), retIndex.end(), t0Index.begin()+1 );
                if ((num_of_data/8)>t0Index.back()){
                    t0Index.push_back( num_of_data/8 );
                    t0Clock.push_back( t0Clock.back()+0.04 );
                    if (!(CaseTable->empty()))
                        CaseTable->push_back( NULL );
                }
                //std::cout << "Template::Increment Put data size="<< num_of_data/8 << std::endl;
                //std::cout << "Template::Increment last T0Index="<< t0Index.back() << std::endl;
                // Increment
                _EDC->PreIncrement( daqId, modNo, data, t0Index, t0Clock, CaseTable);
            }
            delete [] data;

        }else if (mc->SetReference( &PulseIdOfCases, &CaseList )){

            UInt4 num_of_data = mc->PutEventSize();
            UChar *data = new UChar[ num_of_data ];
            std::vector<UInt8> retPulseId;
            std::vector<Double> retT0Clock;
            std::vector<UInt8> retIndex;

            if (mc->Put( data, &num_of_data, &retPulseId, &retT0Clock, &retIndex, CaseTable )){
                /*
                std::cout << "## Increment after Put " << std::endl;
                std::cout << "num_of_data="<< num_of_data << std::endl;
                std::cout << "retPulseId size="<<retPulseId.size()<< std::endl;
                std::cout << "retT0Clock size="<<retT0Clock.size()<<std::endl;
                std::cout << "retIndex size  ="<<retIndex.size()<<std::endl;
                std::cout << "CaseTable size ="<<CaseTable->size()<<std::endl;
                std::cout << "-----------"<<std::endl;
                for (UInt4 z=0; z<retPulseId.size(); z++) std::cout << retPulseId[z] << ",";
                std::cout << std::endl;
                for (UInt4 z=0; z<retT0Clock.size(); z++) std::cout << retT0Clock[z] << ",";
                std::cout << std::endl;
                for (UInt4 z=0; z<retIndex.size(); z++) std::cout << retIndex[z] << ",";
                std::cout << std::endl;
                for (UInt4 z=0; z<CaseTable->size(); z++){
                    if (CaseTable->at(z)!=NULL){
                        for (UInt4 zz=0; zz<CaseTable->at(z)->size(); zz++)
                            std::cout << CaseTable->at(z)->at(zz) << ",";
                        std::cout<<std::endl;
                    }else{
                        std::cout << "CaseTable is empty : z="<<z<<std::endl;
                    }
                }
                std::cout << std::endl;
                */

                // Increment
                _EDC->PreIncrement( daqId, modNo, data, retIndex, retT0Clock, CaseTable );
            }
            delete [] data;

            std::vector<UInt4> updated_cases( CaseTable->size(),0 );
            for (UInt4 i=0;i<(updated_cases.size());i++)
                if (CaseTable->at(i)!=NULL)
                    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;
        }
        for (UInt4 i=0; i<(CaseTable->size()); i++){
            if (CaseTable->at(i)!=NULL) delete CaseTable->at(i);
        }
        delete CaseTable;

        isGoodStatus = true;
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  Updated data
    /*!<  This function executes commands below :
     *      UpdataDataModules()
     *      IncrementCases()
     *      Increment()
     *
     *    bool Update()
     *
     *    @return None
     */
    bool Update(){
        UpdateDataModules();
        if (isGoodStatus){
            IncrementCases();
            if (isGoodStatus){
                Increment();
                if (isGoodStatus)
                    return true;
                else
                    std::cout << _MessageTag+"Update() >>> Increment Fails" << std::endl;
            }else
                std::cout << _MessageTag+"Update() >>> IncrementCases Fails" << std::endl;
        }else
            std::cout << _MessageTag+"Update() >>> UpdateDataModules Fails" << std::endl;
        return false;
    }

    //////////////////////////////////////////////////////////////////////////
    //!<  Output stored data
    /*!<
     *    Output( ElementContainerMatrix* ecm, UInt4 caseId=1 );
     *
     *    @param ecm (ElementContainerMatrix) gives ElementContainerMatrix
     *    @param caseId (UInt4) CaseId
     *    @return None
     */
    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<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("MEASPERIOD")==1) hh->OverWrite( "MEASPERIOD", tmp );
        else hh->Add( "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("KICKERCOUNT")==1) hh->OverWrite("KICKERCOUNT", _KickersForCases[caseId]);
        else hh->Add("KICKERCOUNT", _KickersForCases[caseId]);
    }
    //////////////////////////////////////////////////////////////////////////
    //!<  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;

};

#endif
