#ifndef UTSUSEMIEVENTDATACONVERTERREADOUTTEMPLATE_CC
#define UTSUSEMIEVENTDATACONVERTERREADOUTTEMPLATE_CC

#include "UtsusemiEventDataConverterReadoutTemplate.hh"
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
UtsusemiEventDataConverterReadoutTemplate(){
    _MessageTag  = "UtsusemiEventDataConverterReadoutTemplate::";
    _TTR = new T0TreatToolsReadout();
    _st = new StringTools();
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
~UtsusemiEventDataConverterReadoutTemplate(){
    delete _TTR;
    delete _st;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
ReadEventData( UInt4 daqId, UInt4 modNo ){

    this->_isReady=false;
    if (this->_dataFileList.Empty()){
        UtsusemiError(_MessageTag+"ReadEventData >> dataFilelist is empty");
        return;
    }

    char filenamerootc[30];
    std::snprintf( filenamerootc, sizeof(filenamerootc), "%02d_%03d", daqId, modNo );
    std::string fileNameRoot( filenamerootc );

    if (this->_dataFileList.Check( fileNameRoot )==0){
        UtsusemiError(_MessageTag+"ReadEventData >> dataFileList has no such module:"+fileNameRoot);
        return;
    }
    if (this->_t0dataFileList.Check( fileNameRoot )==0){
        UtsusemiError(_MessageTag+"ReadEventData >> t0dataFileList has no such module:"+fileNameRoot);
        return;
    }

    std::vector<std::string> edb_files = this->_dataFileList.Put( fileNameRoot );
    std::vector<std::string> t0b_files = this->_t0dataFileList.Put( fileNameRoot );
    sort( edb_files.begin(), edb_files.end() );
    sort( t0b_files.begin(), t0b_files.end() );
    for (UInt4 i=0;i<edb_files.size();i++) UtsusemiMessage(_MessageTag+"ReadEventData > EDB="+edb_files[i]);
    for (UInt4 i=0;i<t0b_files.size();i++) UtsusemiMessage(_MessageTag+"ReadEventData > T0B="+t0b_files[i]);

    Int4 ret = this->_CaseDecoder->ReadT0IndexEventFile( t0b_files, 2 );
    if (ret<0){
        UtsusemiError(_MessageTag+"ReadEventData >> fails to read T0Index");
        return;
    }
    this->_CaseDecoder->CheckCaseTableWithT0Index();
    CheckPulseIdTables();

    std::vector< std::vector<UInt4>* >* CaseTable = this->_CaseDecoder->PutCaseTable();

    if (_Readout_T0Table.empty()){
        UtsusemiError(_MessageTag+"ReadEventData >> T0EventData may be empty.");
        return;
    }

    //Int4 num_of_preClocks = ClockTable.size()-T0Table.size();
    Int4 num_of_preClocks = (Int4)(_ReadoutGate_Clocks_diff.size()-_Readout_T0Table.size());
    if (num_of_preClocks<0){
        std::string msg = "Exception:"+_MessageTag+"Invalid size between _Readout_T0Table and ClockTable";
        UtsusemiError(msg);
        throw msg;
    }

    bool isUseCases = false;

    if (CaseTable==NULL){
        //std::cout << _MessageTag+"ReadEventData >> CaseTable==NULL"<<std::endl;
    } else if ( _Readout_T0Table.size()<=(CaseTable->size()+1) ){ //[inamura 170313]
        UtsusemiMessage(_MessageTag+"ReadEventData >> isUseCases = true");
        isUseCases = true;
    } else{
        std::string msg = _MessageTag+"ReadEventData >> Readout_T0Table.size(),CaseTable.size()=";
        msg+= _st->UInt4ToString((UInt4)(_Readout_T0Table.size()))+","+_st->UInt4ToString((UInt4)(CaseTable->size()));
        UtsusemiMessage(msg);
    }

    // EventData Files size
    std::vector<UInt8> edb_files_size = this->PutFilesSize( edb_files );

    // Open EventData Files
    std::vector<FILE*> fp_list( edb_files.size() );
    for (UInt4 i=0;i<edb_files.size();i++){
        if ( (fp_list[i]=fopen( edb_files[i].c_str(), "rb" ))==NULL ){
            UtsusemiError(_MessageTag+"ReadEventData >> fails to open event data file :"+edb_files[i]);
            for (UInt4 j=0;j<i;j++) fclose( fp_list[j] );
            return;
        }
    }

    UInt4 ind=0; // Index of EventData Files

    // The block of event-data before first T0-data should be removed.
    UInt8 ReadingNumOfEvents = _Readout_T0Table[0];
    while( true ){
        if ( edb_files_size[ind]<( ReadingNumOfEvents*(this->_eventSize) ) ){
            ReadingNumOfEvents -= (UInt4)(edb_files_size[ind]/(this->_eventSize));
            ind++;
        }else{
            if (fseek( fp_list[ind], (long)ReadingNumOfEvents*(this->_eventSize), SEEK_SET )==0) break;
            else ind=(UInt4)(fp_list.size());
        }

        if (ind>(fp_list.size()-1)){
            std::string msg = _MessageTag+"ReadEventData >>  Cannot read enough event data from files";
            UtsusemiError(msg);
            return;
        }
    }

    UInt8 current_posi = ReadingNumOfEvents*(this->_eventSize); // current position in a file

    size_t ii;
    UInt4 ReadingStep = 1500;

    UInt4 ReadingTimes = (UInt4)(_Readout_T0Table.size()-1) / ReadingStep;
    UInt4 StepRemainder = (UInt4)(_Readout_T0Table.size()-1) % ReadingStep;

    if( StepRemainder==0 ){
        StepRemainder = ReadingStep;
        ReadingTimes = ReadingTimes -1;
    }

    std::vector<UInt8> NewT0( ReadingStep+1, 0 );
    std::vector<Double> NewIC( ReadingStep+1+num_of_preClocks, 0.0 );
    std::vector< std::vector<UInt4>* > NewCase( ReadingStep+1, NULL);
    if (!isUseCases) NewCase.clear();

    std::vector<UInt4> ReadingPointer( ReadingTimes+2 );
    for (UInt4 k=0; k<(ReadingTimes+1); k++) ReadingPointer[k] = k*ReadingStep;
    ReadingPointer[ ReadingTimes+1 ] = ReadingTimes*ReadingStep + StepRemainder;

    bool isFinal = false;
    for (UInt4 k=0; k<(ReadingPointer.size()-1); k++){
        ReadingNumOfEvents = _Readout_T0Table[ReadingPointer[k+1]] - _Readout_T0Table[ReadingPointer[k]];
        UChar *Dat = new UChar [ ReadingNumOfEvents * (this->_eventSize) ];
        UInt4 start_ind = ind;
        std::vector<UInt8> read_events;
        UInt8 next_posi = (current_posi+(ReadingNumOfEvents*(this->_eventSize)));
        if (next_posi <= edb_files_size[ind]){
            read_events.push_back( ReadingNumOfEvents );
        }else{
            while( next_posi > edb_files_size[ind] ){
                if (ind==(fp_list.size()-1)){
                    std::string msg = _MessageTag+"ReadEventData >> next_posi is over size : something wrong.\n";
                    msg+= _MessageTag+"ReadEventData >> k="+_st->UInt4ToString(k);
                    msg+= ", _Readout_T0Table.size()="+_st->UInt4ToString((UInt4)(_Readout_T0Table.size()))+"\n";
                    msg+= _MessageTag+"ReadEventData >> ReadingPointer[k]="+_st->UInt4ToString(ReadingPointer[k]);
                    msg+= ", ReadingPointer[k+1]="+_st->UInt4ToString(ReadingPointer[k+1]);
                    UtsusemiWarning( msg );
                    break;
                }else{
                    next_posi = next_posi - edb_files_size[ind];
                    read_events.push_back( (edb_files_size[ind]-current_posi)/(this->_eventSize) );
                    // continue to a next file
                    ind++;
                    current_posi =0;
                }
                read_events.push_back( next_posi/(this->_eventSize) );
            }
        }

        UInt8 counter = 0;
        for (UInt4 i=0; i<read_events.size(); i++){
            UChar *Dat_tmp = new UChar [ read_events[i]*(this->_eventSize) ];
            ii = fread( Dat_tmp, (this->_eventSize), read_events[i], fp_list[ start_ind+i ] );
            for (UInt4 l=0;l<(ii*(this->_eventSize));l++) Dat[counter+l]=Dat_tmp[l];
            if (ii==read_events[i]){
                counter += ii*(this->_eventSize);
                if (i==0)
                    current_posi += ii*(this->_eventSize);
                else
                    current_posi = ii*(this->_eventSize);
            }else{
                std::string msg = _MessageTag+"ReadEventData >> (Read left part) read_events[i]!=ii:";
                msg += _st->UInt4ToString((UInt4)read_events[i])+","+_st->UInt4ToString((UInt4)ii);
                UtsusemiWarning( msg );
                msg = _MessageTag+"ReadEventData >> WARNING : start_ind=";
                msg += _st->UInt4ToString(start_ind)+"i="+_st->UInt4ToString(i)+", file="+edb_files[i+start_ind];
                UtsusemiWarning( msg );
                for (UInt8 l=(counter+ii);l<(ReadingNumOfEvents*(this->_eventSize));l++) Dat[l]=0x00;
                isFinal = true;
            }
            delete [] Dat_tmp;
            if (isFinal) break;
        }

        if (k==(ReadingPointer.size()-2)){
            NewT0.clear();
            NewIC.clear();
            NewT0.resize( StepRemainder+1,0 );
            NewIC.resize( StepRemainder+num_of_preClocks+1,0.0 );
            if (isUseCases){
                NewCase.clear();
                NewCase.resize( StepRemainder+1,NULL );
            }
        }

        //for( UInt4 i=0;i<num_of_preClocks;i++) NewIC[i] = ClockTable[i];
        for( UInt4 i=0;i<(UInt4)num_of_preClocks;i++) NewIC[i] = _ReadoutGate_Clocks_diff[i];
        for( UInt4 i=ReadingPointer[k]; i<ReadingPointer[k+1]; i++ ){ //[inamura 170313]
            NewT0[i-ReadingPointer[k]]                     = _Readout_T0Table[i]-_Readout_T0Table[ ReadingPointer[k] ] ;
            //NewIC[i-ReadingPointer[k]+num_of_preClocks]    = ClockTable[i+num_of_preClocks];
            NewIC[i-ReadingPointer[k]+num_of_preClocks]    = _ReadoutGate_Clocks_diff[i+num_of_preClocks];
            if (isUseCases) NewCase[i-ReadingPointer[k]] = CaseTable->at(i);
        }
        NewT0[ReadingPointer[k+1]-ReadingPointer[k]] = _Readout_T0Table[ReadingPointer[k+1]]-_Readout_T0Table[ReadingPointer[k]];//[inamura 170313]

        this->PreIncrement( daqId, modNo, Dat, NewT0, NewIC, &NewCase );

        delete [] Dat;
        if (isFinal) break;
    }

    std::vector<FILE*>::iterator it = fp_list.begin();
    while(it!=fp_list.end()){
        fclose( *it );
        it++;
    }

    this->_isReady=true;
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
CheckPulseIdTables(){
    std::vector<UInt8> T0Table = this->_CaseDecoder->PutT0Index();
    std::vector<UInt8> PulseIdTable = this->_CaseDecoder->PutPulseId();

    if (_ReadoutGate_PulseId.empty()){
        std::vector<Double> T0Clock_Diff = this->_CaseDecoder->PutT0ClockDiff();
        _ReadoutGate_Clocks_diff.clear();
        _ReadoutGate_PulseId.clear();
        _Readout_T0Table.clear();
        _Readout_PulseIdTable.clear();

        _ReadoutGate_Clocks_diff.resize( T0Clock_Diff.size() );
        _ReadoutGate_PulseId.resize( PulseIdTable.size() );
        _Readout_T0Table.resize( T0Table.size() );
        _Readout_PulseIdTable.resize( PulseIdTable.size() );
        copy( T0Clock_Diff.begin(), T0Clock_Diff.end(), _ReadoutGate_Clocks_diff.begin() );
        copy( PulseIdTable.begin(), PulseIdTable.end(), _ReadoutGate_PulseId.begin() );
        copy( T0Table.begin(), T0Table.end(), _Readout_T0Table.begin() );
        copy( PulseIdTable.begin(), PulseIdTable.end(), _Readout_PulseIdTable.begin() );
        std::string msg = _MessageTag+"CheckPulseIdTables >> [inamura 160208] T0Clock_Diff.size(),PulseIdTable.size(),T0Table.size(),PulseIdTable.size()=";
        msg += _st->UInt4ToString((UInt4)(T0Clock_Diff.size()))+","+_st->UInt4ToString((UInt4)(PulseIdTable.size()))+",";
        msg += _st->UInt4ToString((UInt4)(T0Table.size()))+","+_st->UInt4ToString((UInt4)(PulseIdTable.size()));
        UtsusemiWarning(msg);
        return;
    }
    std::vector<Double> tmp_RGClocks_diff;
    std::vector<UInt8> tmp_RGPulseId;
    std::vector<UInt8> tmp_T0Table;
    std::vector<UInt8> tmp_PulseIdTable;

    UInt4 ind_g = 0;
    UInt4 ind_r = 0;

    while(true){
        if (_ReadoutGate_PulseId[ind_g]==PulseIdTable[ind_r]){
            tmp_T0Table.push_back( T0Table[ind_r] );
            tmp_PulseIdTable.push_back( PulseIdTable[ind_r] );
            tmp_RGPulseId.push_back( _ReadoutGate_PulseId[ind_g] );
            tmp_RGClocks_diff.push_back( _ReadoutGate_Clocks_diff[ind_g] );
            ind_g++;
            ind_r++;
        }else if ( _ReadoutGate_PulseId[ind_g]<PulseIdTable[ind_r] ){ //lacks on Readout events
            while( _ReadoutGate_PulseId[ind_g]<PulseIdTable[ind_r] ){
                if (tmp_T0Table.empty()){
                }else{
                    tmp_T0Table.push_back( tmp_T0Table.back() );
                    tmp_PulseIdTable.push_back( tmp_PulseIdTable.back()+1 );
                    tmp_RGPulseId.push_back( _ReadoutGate_PulseId[ind_g] );
                    tmp_RGClocks_diff.push_back( _ReadoutGate_Clocks_diff[ind_g] );
                }
                ind_g++;
                if (ind_g==_ReadoutGate_PulseId.size()) break;
            }
        }else if (_ReadoutGate_PulseId[ind_g]>PulseIdTable[ind_r]){
            while(_ReadoutGate_PulseId[ind_g]>PulseIdTable[ind_r]){
                if (tmp_RGPulseId.empty()){
                }else{
                    tmp_T0Table.push_back( T0Table[ind_r] );
                    tmp_PulseIdTable.push_back( PulseIdTable[ind_r] );
                    tmp_RGPulseId.push_back( tmp_RGPulseId.back()+1 );
                    tmp_RGClocks_diff.push_back( tmp_RGClocks_diff.back()+0.04 );
                }
                ind_r++;
                if (ind_r==PulseIdTable.size()) break;
            }
        }

        if (ind_g==_ReadoutGate_PulseId.size()){
            /*
            if (ind_r<PulseIdTable.size()){
                for (UInt4 i=0; i<(PulseIdTable.size()-ind_r); i++){
                    tmp_RGPulseId.push_back( tmp_RGPulseId.back()+1 );
                    tmp_RGClocks_diff.push_back( tmp_RGClocks_diff.back()+0.04 );
                }
            }
            */
            break;
        }
        if (ind_r==PulseIdTable.size()){
            if (ind_g<_ReadoutGate_PulseId.size()){
                for (UInt4 i=0; i<(_ReadoutGate_PulseId.size()-ind_g); i++){
                        tmp_T0Table.push_back( tmp_T0Table.back() );
                        tmp_PulseIdTable.push_back( tmp_PulseIdTable.back()+1 );
                        tmp_RGPulseId.push_back( _ReadoutGate_PulseId[ind_g+i] );
                        tmp_RGClocks_diff.push_back( _ReadoutGate_Clocks_diff[ind_g+i] );
                }
            }
            break;
        }
    }
    _ReadoutGate_Clocks_diff.clear();
    _ReadoutGate_PulseId.clear();
    _Readout_T0Table.clear();
    _Readout_PulseIdTable.clear();

    _ReadoutGate_Clocks_diff.resize( tmp_RGClocks_diff.size() );
    _ReadoutGate_PulseId.resize( tmp_RGPulseId.size() );
    _Readout_T0Table.resize( tmp_T0Table.size() );
    _Readout_PulseIdTable.resize( tmp_PulseIdTable.size() );
    copy( tmp_RGClocks_diff.begin(), tmp_RGClocks_diff.end(), _ReadoutGate_Clocks_diff.begin() );
    copy( tmp_RGPulseId.begin(), tmp_RGPulseId.end(), _ReadoutGate_PulseId.begin() );
    copy( tmp_T0Table.begin(), tmp_T0Table.end(), _Readout_T0Table.begin() );
    copy( tmp_PulseIdTable.begin(), tmp_PulseIdTable.end(), _Readout_PulseIdTable.begin() );

}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
LoadEventDataFiles( UInt4 runNumber, std::string pathToData, std::string pathToT0data ){
    std::vector<UInt4> tmp(1, runNumber);
    return LoadEventDataFiles( tmp, pathToData, pathToT0data );
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
LoadEventDataFiles( std::vector<UInt4> runNumbers, std::string pathToData, std::string pathToT0data ){
    if (runNumbers.empty()) return 0;
    if (runNumbers[0]<=0){
        this->_runNumbers.clear();
        this->_runNumbers.push_back(0);
        return 0;
    }
    if (pathToData=="") pathToData="/data";
    //SetDataPath( pathToData, pathToT0data, runNumbers );
    //std::vector< std::vector<Int4>* > readoutgate_modules = this->_EventDecoder->_wirInfo->ReadoutGateStore;
    std::vector< UtsusemiReadoutGateInfo* > readoutgate_modules = this->_EventDecoder->_wirInfo->ReadoutGateStore;
    std::vector< std::pair<UInt4,UInt4> >* maskModules = NULL;
    std::vector< std::vector< std::vector< std::vector<Int4>* >* >* >* _readoutgate_store = new std::vector< std::vector< std::vector< std::vector<Int4>* >* >* >;

    _ReadoutGate_Clocks.clear();
    _ReadoutGate_Clocks_diff.clear();
    _ReadoutGate_PulseId.clear();
    if (readoutgate_modules.empty()){
        UtsusemiWarning( _MessageTag+"LoadEventDataFile > no Readoutgate module" );
    }else{
        if (maskModules==NULL) maskModules = new std::vector< std::pair<UInt4,UInt4> >;
        for (UInt4 i=0; i<readoutgate_modules.size(); i++){
            std::pair<UInt4,UInt4> tmp_mod;
            //tmp_mod.first = readoutgate_modules[i]->at(1);
            //tmp_mod.second= readoutgate_modules[i]->at(2);
            tmp_mod.first = readoutgate_modules[i]->DaqId;
            tmp_mod.second= readoutgate_modules[i]->ModNo;
            maskModules->push_back( tmp_mod );

            if ( (tmp_mod.first+1) > (_readoutgate_store->size()) ) _readoutgate_store->resize( (tmp_mod.first+1), NULL );
            if (_readoutgate_store->at( tmp_mod.first )==NULL) _readoutgate_store->at( tmp_mod.first ) = new std::vector< std::vector< std::vector<Int4>* >* >;
            if ( (tmp_mod.second+1) > (_readoutgate_store->at( tmp_mod.first )->size()) ) _readoutgate_store->at( tmp_mod.first )->resize( (tmp_mod.second+1), NULL );
            if (_readoutgate_store->at( tmp_mod.first )->at( tmp_mod.second )==NULL)
                _readoutgate_store->at( tmp_mod.first )->at( tmp_mod.second ) = new std::vector< std::vector<Int4>* >(1, NULL );
            if (_readoutgate_store->at( tmp_mod.first )->at( tmp_mod.second )->at(0)==NULL)
                _readoutgate_store->at( tmp_mod.first )->at( tmp_mod.second )->at(0) = new std::vector<Int4>;
            _readoutgate_store->at( tmp_mod.first )->at( tmp_mod.second )->at(0)->clear();
            _readoutgate_store->at( tmp_mod.first )->at( tmp_mod.second )->at(0)->resize(3,i);

        }

        for (UInt4 i_run=0; i_run<runNumbers.size(); i_run++){
            this->SetDataPath( pathToData, pathToT0data, runNumbers[i_run], true, _readoutgate_store, NULL, true );
            UInt4 num_of_keys = this->_dataFileList.PutTableSize();
            for (UInt4 i=0; i<num_of_keys; i++){
                std::string a_key = this->_dataFileList.PutKey( i );
                std::vector<std::string> rg_edb_files = this->_dataFileList.Put( a_key );
                std::vector<std::string> rg_t0b_files = this->_t0dataFileList.Put( a_key );
                for (UInt4 j=0; j<rg_t0b_files.size(); j++) UtsusemiMessage(_MessageTag+"LoadEventDataFiles > rg_t0b_files="+rg_t0b_files[j]);
                if (rg_t0b_files.size()>1){
                    sort( rg_edb_files.begin(), rg_edb_files.end() );
                    if ((_TTR->readOrgEvent( rg_edb_files ))>0){
                        std::string msg = _MessageTag+"LoadEventDataFiles : can not read ReadoutGate files=";
                        for (UInt4 k=0; k<rg_edb_files.size(); k++) msg+= "      "+rg_edb_files[k];
                        UtsusemiError( msg );
                        return 0;
                    }else{
                        for (UInt4 j=0; j<3; j++){
                            if (rg_t0b_files[j]!="")
                                if ((_TTR->saveT0IndexEvent( rg_t0b_files[j] ))==0) break;
                        }
                    }
                }else{
                    _TTR->readT0IndexEvent( rg_t0b_files );
                }
            }

            //std::vector<Double> tmp_clocks = _TTR->PutT0Clock();
            std::vector<Double> tmp_clocks = _TTR->putVectorT0Clock();
            UInt4 readoutgate_clocks_size = (UInt4)(_ReadoutGate_Clocks.size());
            _ReadoutGate_Clocks.resize( ( readoutgate_clocks_size + tmp_clocks.size()) );
            for (UInt4 i=0; i<(tmp_clocks.size()); i++)
                _ReadoutGate_Clocks[ readoutgate_clocks_size + i ] = tmp_clocks[i];

            //std::vector<Double> tmp_clocks_diff = _TTR->PutT0ClockDiff();
            std::vector<Double> tmp_clocks_diff = _TTR->putT0ClockDiffAll();
            UInt4 readoutgate_clocks_diff_size = (UInt4)(_ReadoutGate_Clocks_diff.size());
            _ReadoutGate_Clocks_diff.resize( ( readoutgate_clocks_size + tmp_clocks_diff.size()) );
            for (UInt4 i=0; i<(tmp_clocks_diff.size()); i++)
                _ReadoutGate_Clocks_diff[ readoutgate_clocks_diff_size + i ] = tmp_clocks_diff[i];

            std::vector<UInt8> tmp_pulseid = _TTR->PutPulseId();
            UInt4 readoutgate_pulseid_size = (UInt4)(_ReadoutGate_PulseId.size());
            _ReadoutGate_PulseId.resize( ( readoutgate_pulseid_size + tmp_pulseid.size()) );
            for (UInt4 i=0; i<(tmp_pulseid.size()); i++)
                _ReadoutGate_PulseId[ readoutgate_pulseid_size + i ] = tmp_pulseid[i];

        }
        //_ReadoutGate_Clocks = _TTR->PutT0Clock();
        _ReadoutGate_Clocks = _TTR->putVectorT0Clock();
        this->_CaseDecoder->PutT0TreatTools()->SetExternalClockInfo( _ReadoutGate_Clocks );
    }

    //this->_CaseDecoder->PutT0TreatTools()->SetExternalClockInfo( _ReadoutGate_Clocks );

    std::vector< std::vector< std::vector< std::vector<Int4>* >* >* >* _PixelInfoStore = this->_EventDecoder->_wirInfo->PixelInfoStore;
    if (_PixelInfoStore==NULL){
        UtsusemiError(_MessageTag+"ReadEventData >>> There is no information about pixels from WiringInfo.xml");
        return -2;
    }
    this->SetDataPath( pathToData, pathToT0data, runNumbers, true, _PixelInfoStore, maskModules );

    if (this->_isReady){
        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){
                        UtsusemiMessage(_MessageTag+"ReadEventData >> Load event data file for daq,mod="+_st->UInt4ToString(daq)+","+_st->UInt4ToString(mod));
                        if (maskModules==NULL) this->ReadEventData(daq,mod);
                        else
                            this->ReadEventData( daq, mod );
                        if (!(this->_isReady)){
                            UtsusemiWarning(_MessageTag+"ReadEventData >>> fails to read Event data (daq="+_st->UInt4ToString(daq)+", mod="+_st->UInt4ToString(mod));
                            for (UInt4 i=0; i<(_PixelInfoStore->at(daq)->at(mod)->size()); i++){
                                if (_PixelInfoStore->at(daq)->at(mod)->at(i)!=NULL){
                                    Int4 det_id = _PixelInfoStore->at(daq)->at(mod)->at(i)->at(1);
                                    if ( det_id>=(this->_isUnReadDetId.size()) ) this->_isUnReadDetId.resize( (det_id+1), false );
                                    this->_isUnReadDetId[det_id]=true;
                                    UtsusemiMessage(_MessageTag+"ReadEventData >>> masked on detId="+_st->UInt4ToString(det_id));
                                }
                            }
                        }
                    }
                }
            }
        }
        //ReadEventData();
        if (!(this->_isReady)){
            UtsusemiError(_MessageTag+"LoadEventDataFiles >>> fails to read some event data files ");
        }
    }else{
        UtsusemiError(_MessageTag+"LoadEventDataFiles >>> Not Found Data Folder.");
        return -1;
    }
    return 0;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetElementContainerReadout( UInt4 outer_pixel_id, ElementContainer* ec, UInt4 caseId ){
    if (caseId<=0) return;

    Int4 tof_bin_type = this->_EventDecoder->PutTofBinType( outer_pixel_id );
    if (tof_bin_type<0){
        UtsusemiError(_MessageTag+"There is no information of tof_bin_type.");
    }else{

        this->SetElementContainer(outer_pixel_id, ec, caseId);
    }
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
bool UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
LoadParamFiles( std::string w_file, std::string d_file, std::string c_file ){
    if (this->SetEventParams( w_file, d_file )){
        if (c_file!="") this->SetCaseInfoParams( c_file );
        return true;
    }
    return false;
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetElementContainerMatrix( ElementContainerMatrix* ecm, UInt4 caseId ){
    UInt4 outerPixelId = 0;
    Int4 tofBinType = -1;
    while(true){
        if (this->_EventDecoder->_wirInfo->TofBinInfoList[outerPixelId]!=NULL){
            std::vector<Double>* tofBinInfo = this->_EventDecoder->_wirInfo->TofBinInfoList[outerPixelId];

            UInt4 tof_pat_id = (UInt4)(tofBinInfo->at(0));
            if (this->_EventDecoder->_wirInfo->TofBinPtnInfo[ tof_pat_id ]!=NULL){
                tofBinType = this->_EventDecoder->_wirInfo->TofBinPtnInfo[ tof_pat_id ]->type;
                break;
            }
        }
        outerPixelId++;
    }

    if (tofBinType<0) return -3;

    Int4 ret = _SetElementContainerMatrix(ecm, caseId );
    if (ret!=0) return ret;

    HeaderBase* hh = ecm->PutHeaderPointer();
    std::vector<std::string> process_h = hh->PutStringVector(UTSUSEMI_KEY_HEAD_DATAPROCESSED);
    //std::cout << "@@@@@@ TOF_BIN_TYPE=" << tofBinType << std::endl;
    if (tofBinType==20){
        process_h.push_back( "TOF TO ENERGY TRANSFER" );
        //std::vector< Double > EfixV( _EventDecoder->_tofBinConv->PutEfixVect() );
        //if (!(EfixV.empty())) {
        //    hh->Add( UTSUSEMI_KEY_HEAD_EI, EfixV[0] );
        //    for (UInt4 i=0;i<ecm->PutSize();i++) ecm->PutPointer(i)->PutHeaderPointer()->Add( UTSUSEMI_KEY_HEAD_EI, EfixV[0] );
        //}
        std::vector<Double> params = this->_EventDecoder->_wirDict->PutParams(tofBinType);
        if (!(params.empty())){
            hh->Add( UTSUSEMI_KEY_HEAD_EI, params[0] );
            for (UInt4 i=0;i<ecm->PutSize();i++) ecm->PutPointer(i)->PutHeaderPointer()->Add( UTSUSEMI_KEY_HEAD_EI, params[0] );
        }
    }else if (tofBinType==21){
        process_h.push_back( "TOF TO ENERGY" );
    }else if (tofBinType==22){
        process_h.push_back( "TOF TO Q" );
    }else{
        process_h.push_back( "EVENTS TO TOF" );
    }

    hh->OverWrite(UTSUSEMI_KEY_HEAD_DATAPROCESSED,process_h);

    return 0;
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetElementContainerMatrix( ElementContainerMatrix* ecm, UInt4 runNumber, std::string pathToData, std::string pathToT0data, UInt4 caseId ){
    Int4 ret = LoadEventDataFiles( runNumber, pathToData, pathToT0data );
    if (ret==0) return SetElementContainerMatrix( ecm, caseId );
    else return ret;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetElementContainerMatrix( ElementContainerMatrix* ecm, std::vector<UInt4> runNumbers, std::string pathToData, std::string pathToT0data, UInt4 caseId ){
    Int4 ret = LoadEventDataFiles( runNumbers, pathToData, pathToT0data );
    if (ret==0) return SetElementContainerMatrix( ecm, caseId );
    else return ret;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
LoadTrignetEventFile( UInt4 runno, std::string pathToData, std::string pathToT0data )
{
    this->SetDataPath( pathToData, pathToT0data, runno, false, NULL, NULL, false );
    if (this->_isReady){
        //this->_CaseDecoder->isCheckedPulseId = false;
        this->SetFlagOfPulseIdCheck(false);
        std::vector< std::vector<Int4>* >* caseInfoStore = this->_EventDecoder->_wirInfo->TrigInfoStore;
        if (caseInfoStore!=NULL){
            for (UInt4 i=0; i<caseInfoStore->size(); i++){
                if (caseInfoStore->at(i)!=NULL){
                    Int4 type = caseInfoStore->at(i)->at(0);
                    Int4 daq = caseInfoStore->at(i)->at(1);
                    Int4 mod = caseInfoStore->at(i)->at(2);

                    char key_c[30];
                    std::snprintf( key_c, sizeof(key_c), "%02d_%03d", daq, mod );
                    std::string key( key_c );
                    if (this->_dataFileList.Check( key )==0){
                        UtsusemiError(_MessageTag+"LoadTrignetEventFile > There is no event data for daq="+_st->UInt4ToString(daq)+",mod="+_st->UInt4ToString(mod));
                        return;
                    }
                    std::vector<std::string> dfiles = this->_dataFileList.Put( key );
                    std::vector<std::string> tfiles;
                    // if Event Data is not existed.
                    if (dfiles.empty()){
                        UtsusemiWarning(_MessageTag+"LoadTrignetEventFile > Not found edb file daq_mod="+key);
                        continue;
                    }
                    if (this->_t0dataFileList.Check( key )==0){
                        T0TreatToolsNeunet* T0Tools = new T0TreatToolsNeunet();
                        UInt4 ret = T0Tools->readOrgEvent( dfiles );
                        if (ret>0) {
                            UtsusemiError(_MessageTag+"LoadTrignetEventFile > not found edb file");
                            delete T0Tools;
                            continue;
                        }
                        char t0_file_name[30];
                        std::snprintf( t0_file_name, sizeof(t0_file_name), "%3s%06d_%02d_%03d_000.t0b", this->_instCode.c_str(), this->_runNumber, daq, mod );
                        std::string t0_file( t0_file_name );
                        std::string path_dir( dfiles[0].substr(0,(dfiles[0].size()-24)) );
                        std::string path_to_t0file( path_dir );
                        _addPath( &path_to_t0file, &t0_file );
                        ret = T0Tools->saveT0IndexEvent( path_to_t0file );
                        if (ret>0){
                            std::string path_dir2 = FindTempFilePath();
                            _addPath( &path_dir2, &t0_file );
                            ret = this->_CaseDecoder->PutT0TreatTools()->saveT0IndexEvent( path_dir2 );
                            if (ret==0) path_to_t0file = path_dir2;
                        }
                        delete T0Tools;
                        if (ret==0) tfiles.push_back( path_to_t0file );
                        else{
                            UtsusemiWarning(_MessageTag+"LoadTrignetEventFile > Fails to create .t0b files ="+t0_file);
                            continue;
                        }
                    }else tfiles = this->_t0dataFileList.Put( key );

#ifdef DEBUG_UTSUSEMI
                    std::cout << "@@@ LoadTrignetEventFile i=" << i << std::endl;
                    std::cout << "@@@ data files = ";
                    for (UInt4 j=0;j<dfiles.size();j++) std::cout << dfiles[j]+",";
                    std::cout << std::endl;
                    std::cout << "@@@ t0data files = ";
                    for (UInt4 j=0;j<tfiles.size();j++) std::cout << tfiles[j]+",";
                    std::cout << std::endl;
#endif

                    this->ReadCaseEvent( i, dfiles, tfiles );
                }
            }
        }else{
            UtsusemiError(_MessageTag+"LoadTrigEventFiles >>> caseInfoStore is NULL ");
        }
        //ReadCaseEvent();
        if (!(this->_isReady)){
            UtsusemiError(_MessageTag+"LoadTrigEventFiles >>> fails to read event data files ");
            return;
        }
    }else{
        UtsusemiError(_MessageTag+"LoadTrigEventFiles >>> fails to SetDataPath ");
    }
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
ReadTrignetEventFile( std::string pathToTrigData, UInt4 index ){
    //std::vector<std::string> files(index+1,"");
    //files[index] = pathToTrigData;
    //ReadCaseEventFiles( files );
    std::vector<std::string> tmp1(1,pathToTrigData);
    std::vector<std::string> tmp2;
    tmp2.clear();
    //this->_CaseDecoder->isCheckedPulseId = false;
    this->SetFlagOfPulseIdCheck(false);
    this->ReadCaseEventFiles( index, tmp1, tmp2 );
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector<UInt4> UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
DumpCaseTable(UInt4 i1, UInt4 i2, bool isI1Size, bool isI2Size ){
    std::vector<UInt4> ret;
    ret.clear();

    if (this->_CaseDecoder->PutCaseTable()==NULL){
        std::cout << "@@@@ NULL" << std::endl;
        return ret;
    }
    if (isI1Size){
        ret.push_back( (UInt4)(this->_CaseDecoder->PutCaseTable()->size()) );
    }else if (isI2Size){
        if (i1<(this->_CaseDecoder->PutCaseTable()->size())){
            ret.push_back( (UInt4)((this->_CaseDecoder->PutCaseTable()->at(i1)->size()))/2 );
        }
    }else if (i1<(this->_CaseDecoder->PutCaseTable()->size())){
        if (i2<((this->_CaseDecoder->PutCaseTable()->at(i1)->size())/2)){
            ret.push_back( this->_CaseDecoder->PutCaseTable()->at(i1)->at(i2*2) );
            ret.push_back( this->_CaseDecoder->PutCaseTable()->at(i1)->at(i2*2+1) );
        }
    }
    return ret;
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetElementContainerMatrixForPseudOnLineMon( ElementContainerMatrix* ecm, UInt4 caseId, UInt4 runNo ){
    this->_runNumber=runNo;
    return _SetElementContainerMatrix( ecm, caseId );
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetDataPathTest( std::string dataPath, std::string t0Path, UInt4 runNo ){
    //std::cout << "@@@ " << dataPath << "," << t0Path << "," << runNo << std::endl;
    this->SetDataPath( dataPath, t0Path, runNo );
    if (this->_isReady){
        return 0;
    }else{
        return -1;
    }
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector<Double> UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
PutListOfCounterConditions(){
    std::vector< std::pair<Double,Double> > cond_list =  this->_CaseDecoder->PutFilter()->PutListOfCounterConditions();
    std::vector<Double> ret;
    //std::cout << "### cond_list.size()=" << cond_list.size()<<std::endl;
    for (UInt4 i=0;i<cond_list.size();i++){
        ret.push_back( cond_list[i].first );
        ret.push_back( cond_list[i].second );
    }
    return ret;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
bool UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetTofOriginShift( UInt4 cType ){
    return this->_EventDecoder->SetTofOriginShift( cType );
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
bool UtsusemiEventDataConverterReadoutTemplate<T1,T2>::
SetTofOriginShift( UInt4 cType, std::vector<Double> params ){
    return this->_EventDecoder->SetTofOriginShift( cType, params );
}


;
#endif
