#include "UtsusemiFilterTrignet.hh"
//////////////////////////////////////////////////////////
UtsusemiFilterTrignet::
UtsusemiFilterTrignet(){
    Initialize();
}
//////////////////////////////////////////////////////////
UtsusemiFilterTrignet::
~UtsusemiFilterTrignet(){

    if (_filterCaseTables!=NULL){
        for (UInt4 i=0; i<_filterCaseTables->size(); i++)
            ClearAllTables(i, false);
        if (_filterCaseTables!=NULL) delete _filterCaseTables;
        if (_filterPulseIdLists!=NULL) delete _filterPulseIdLists;
        if (_filterInstClockLists!=NULL) delete _filterInstClockLists;
    }

    UInt4 multh_num = _NumOfMulTh;
    if (_UCR->PutTrignetCounterInfo()!=NULL) multh_num = 1;

    Clear();
    delete _UCR;
    delete _UTD;
    delete _UTS;
    delete _stools;
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
Initialize(){
    _filterCaseTables=NULL;
    _filterPulseIdLists=NULL;
    _filterInstClockLists=NULL;

    _UCR = new UtsusemiCaseInfoReaderTrignet();
    _UTD = new UtsusemiTrignetEventDecoderBase();

    isCaseInfoReady = false;
    isTrigTableReady = false;

    MessageTag = "UtsusemiFilterTrignet::";
    _eventSize = 8;

    _NumOfMulTh = UtsusemiGetNumOfMulTh();

    _UTS = new UtsusemiOneTrignetStorage(_NumOfMulTh);
    _firstT0InstClock = 0.0;
    _stools = new StringTools();
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ClearCaseTables(UInt4 index, bool makeNew){
    if (_filterCaseTables!=NULL){
        if (index<_filterCaseTables->size()){
            if (_filterCaseTables->at(index)!=NULL){
                for (UInt4 j=0;j<_filterCaseTables->at(index)->size();j++){
                    if (_filterCaseTables->at(index)->at(j)!=NULL){
                        delete _filterCaseTables->at(index)->at(j);
                    }
                }
                delete _filterCaseTables->at(index);
                _filterCaseTables->at(index)=NULL;
            }
        }
    }

    if (makeNew){
        if (_filterCaseTables==NULL) _filterCaseTables = new std::vector< std::vector< std::vector<UInt4>* >* >;
        if (_filterCaseTables->size()<(index+1)) _filterCaseTables->resize( (index+1), NULL );
        if (_filterCaseTables->at(index)==NULL)  _filterCaseTables->at(index) = new std::vector< std::vector<UInt4>* >;
    }
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ClearPIDLists(UInt4 index, bool makeNew){
    if (_filterPulseIdLists!=NULL){
        if (index<_filterPulseIdLists->size()){
            if (_filterPulseIdLists->at(index)!=NULL){
                delete _filterPulseIdLists->at(index);
                _filterPulseIdLists->at(index)=NULL;
            }
        }
    }

    if (makeNew){
        if (_filterPulseIdLists==NULL) _filterPulseIdLists = new std::vector< std::vector<UInt8>* >;
        if (_filterPulseIdLists->size()<(index+1)) _filterPulseIdLists->resize( (index+1), NULL );
        if (_filterPulseIdLists->at(index)==NULL)  _filterPulseIdLists->at(index) = new std::vector<UInt8>;
    }
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ClearICLists(UInt4 index, bool makeNew){
    if (_filterInstClockLists!=NULL){
        if (index<_filterInstClockLists->size()){
            if (_filterInstClockLists->at(index)!=NULL){
                delete _filterInstClockLists->at(index);
                _filterInstClockLists->at(index)=NULL;
            }
        }
    }

    if (makeNew){
        if (_filterInstClockLists==NULL) _filterInstClockLists = new std::vector< std::vector<Double>* >;
        if (_filterInstClockLists->size()<(index+1)) _filterInstClockLists->resize( (index+1), NULL );
        if (_filterInstClockLists->at(index)==NULL)  _filterInstClockLists->at(index) = new std::vector<Double>;
    }
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ClearAllTables(UInt4 index, bool makeNew){
    ClearCaseTables(index, makeNew);
    ClearPIDLists(index, makeNew);
    ClearICLists(index, makeNew);
}

//////////////////////////////////////////////////////////
Int4 UtsusemiFilterTrignet::
ReadCaseInfoFile( std::string caseInfo_file ){
    //std::cout << MessageTag+"ReadCaseInfoFile start" << std::endl;
    Int4 ret=_UCR->ImportCaseInfo(caseInfo_file);

#ifdef DEBUG_UTSUSEMI
    _UCR->DumpCases2();
    _UCR->DumpTrignetCounter();
#endif

    // Set numOfCases
    if (ret<0) return ret;
    numOfCases = _UCR->PutNumOfCases();
    _CaseAmbiguity = _UCR->_CaseAmbiguity;
    _CaseAmbiguity_params = _UCR->_CaseAmbiguity_params;
    isCaseInfoReady=true;
    //std::cout << MessageTag+"ReadCaseInfoFile fin" << std::endl;
    return 0;
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
CaseSorting( const UChar* data, UInt8 size, UInt4 index, UInt4 ThNum ){
    bool debug = false;

    std::vector< std::vector< UtsusemiTrignetCondGroup* >* >* ti = _UCR->PutTrignetInfo();
    std::vector<UtsusemiTrignetCounter*>* tc = _UCR->PutTrignetCounterInfo();

    UInt4 current_case = 0;

    UInt8 pulse_id = 0;
    bool isPulseIdDecoded = false;
    Double clock = 0.0;
    Double first_clock = _firstT0InstClock; //[second]

    _UTS->StartAFrame( ThNum );

    for (UInt4 i=0; i<size; i++){
        UInt4 evt_index = i*_eventSize;
        UChar evt = *(data+evt_index);
        // if T0 event
        if ( _UTD->isHeaderT0(evt) ){
            pulse_id = _UTD->decodePulseIdEvent( data+evt_index );
            isPulseIdDecoded = true;
        }

        // if clock event
        if ( _UTD->isHeaderClock(evt) ) {
            //clock = _UTD->decodeInstClockEvent( data+evt_index );
            //if (first_clock==0.0) first_clock = clock;
            clock = _UTD->decodeInstClockEvent( data+evt_index );  // unit[second]
            if (tc!=NULL){
                current_case = UTSUSEMIMASKVALUEUINT4;
                for (UInt4 i=0;i<tc->size();i++){
                    UInt4 tmp = tc->at(i)->SetClock(clock);
                    if (tmp!=UTSUSEMIMASKVALUEUINT4){
                        current_case = tmp;
                        _UTS->AddCounterCaseSort( ThNum, 0, current_case );
                        break;
                    }
                }
                //if (current_case==0) _UTS->AddCounterCaseSort( ThNum, 0, current_case );
            }
        }

        // if TrigEvent
        if ( _UTD->isTrigEvent(evt) ){
            std::vector<UInt4> *values = new std::vector<UInt4> (12,0);
            if ( -1<( _UTD->DecodeTrigEvent( (data+evt_index), values, index ) ) ){
                UInt4 tof = values->at(0);
                UInt4 ind = values->at(1);
                UInt4 sid1 = values->at(2);
                UInt4 sid2 = values->at(3);
#ifdef DEBUG_UTSUSEMI
                std::cout << "get : sid1,sid2="<<sid1<<","<<sid2<<std::endl;
#endif
                std::vector<UInt4>* cond = new std::vector<UInt4>(8,0);
                for (UInt4 i=4;i<(values->size());i++){
                    cond->at(i-4)=values->at(i);
                }
#ifdef DEBUG_UTSUSEMI
                std::cout << "get : cond=";
                for (UInt4 i=0; i<cond->size(); i++) std::cout << cond->at(i) << ",";
                std::cout << std::endl;
#endif
                bool isDecided=false;
                bool isDecidedTmp=false;
                current_case = 0;
                std::vector<UInt4> current_cases;
                if (ti!=NULL){
                    for(UInt4 caseNo=0;caseNo<ti->size();caseNo++){
                        if (ti->at(caseNo)==NULL) continue;
                        for (UInt4 i=0;i<ti->at(caseNo)->size();i++){

                            UtsusemiTrignetCondGroup* utg = ti->at(caseNo)->at(i);
                            if (utg==NULL) continue;
                            Int4 filterflag = utg->TrigFilter(index,sid1,sid2,cond);
                            Int4 tofflag = utg->TofFilter( tof );
                            Int4 timeflag = utg->TimeFilter( clock, first_clock );
                            // If the event is unrelated to filter condition
                            if ( (filterflag==0)&&(tofflag==0)&&(timeflag==0) ) continue;
                            // if the event does not pass a filter
                            if ( (filterflag==-1)||(tofflag==-1)||(timeflag==-1) ) isDecidedTmp = true;
                            // if the event passes a filter
                            else{
                                current_case = caseNo;
                                current_cases.push_back(caseNo);
                                isDecided = true;
                            }
                            if (isDecided) break;
                        }
#ifdef DEBUG_UTSUSEMI
                        if (isDecided) {
                            std::cout << "caseNo=" << caseNo <<":True /" << std::endl;
                        }else{
                            std::cout << "caseNo=" << caseNo <<":False /" << std::endl;
                        }
#endif
                        //if (isDecided) break;
                    }
                    if (isDecided){
                        _UTS->AddFilterCaseSort( ThNum, sid2, tof, current_cases );
                    }else if (isDecidedTmp){
                        current_case = 0;
                        current_cases.push_back(0);
                        _UTS->AddFilterCaseSort( ThNum, sid2, tof, current_cases );
                    }

                }


                if (tc!=NULL){
                    current_case = 0;
                    for (UInt4 i=0;i<tc->size();i++){
                        UInt4 tmp = tc->at(i)->CountEvent( ind,sid1,sid2,cond,clock );
#ifdef DEBUG_UTSUSEMI
                        std::cout << "@@@@[tc] index="<<index<<",sid1="<<sid1<<",sid2="<<sid2<< std::endl;
                        std::cout << "@@@@[tc] TriggerCounter->at("<<i<<")->CountEvent()="<<tmp << std::endl;
#endif
                        if (tmp!=UTSUSEMIMASKVALUEUINT4){
                            current_case = tmp;
                            _UTS->AddCounterCaseSort( ThNum, tof, current_case );
                            break;
                        }
                    }
                }else{
                    //std::cout << "@@@ TriggerCounter is empty!!!" << std::endl;
                }

                delete cond;

            }

            delete values;

        }

    }

    if (isPulseIdDecoded){
        _UTS->AddPulseId( ThNum, (UInt4)pulse_id, clock );
    }else{
        std::cout << MessageTag+"CaseSorting :: data includes no PulseId" << std::endl;
    }

}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
PreCaseSorting( const UChar* data, std::vector<UInt8> T0Table, UInt4 index ){
    UInt4 multh_num = _NumOfMulTh;
    if ( _UCR->PutTrignetCounterInfo()!=NULL){
        multh_num = 1;
        _UTS->_NumOfMulTh=1;
    }
    _UTS->StartFrame();

    UInt4 TableSize = (UInt4)(T0Table.size());
    UInt8 size = T0Table[ TableSize-1 ];

#ifdef MULTH
    omp_set_num_threads( multh_num );
#endif

#pragma omp parallel for
#if (_OPENMP >= 200805)  // OpenMP 3.0 and later
    for( UInt4 i=0; i<TableSize-1; i++){
#else
    for( Int4 i=0; i<(Int4)TableSize-1; i++){
#endif
        UInt8 Ini = T0Table[i];
        UInt8 DataSize = T0Table[i+1]-T0Table[i];
        UInt4 ThNum = 0;

#ifdef MULTH
        ThNum = omp_get_thread_num();
#endif
        try{
            CaseSorting( data+(Ini*_eventSize), DataSize, index, ThNum );
        }
        catch(...){
            std::cout << MessageTag+"preCaseSorting >> ERROR in preCaseSorting; ThNum=" << ThNum << std::endl;
        }
    }
    //std::cout << "UtsusemiFilterTrignet>> start MergeOnMulTh " << std::endl;
    if (_UTS->MergeOnMulTh()){
    }else{
        std::cout << MessageTag+"preCaseSorting >> ERROR in MergeOnMulTh." << std::endl;
        return;
    }


    std::vector< std::vector<UInt4>* > *merged_case_table = new std::vector< std::vector<UInt4>* >;

    std::vector< std::vector< UtsusemiTrignetCondGroup* >* >* ti = _UCR->PutTrignetInfo();
    UInt4 num_filter_cases = 0;
    std::vector<bool> filter_and_list;

    if (ti!=NULL){
        num_filter_cases = (UInt4)(ti->size());
        filter_and_list.resize( num_filter_cases, true );
        for (UInt4 caseNo=0;caseNo<num_filter_cases;caseNo++){
            if (ti->at(caseNo)!=NULL){
                std::vector<bool> tmp_And;
                for ( UInt4 i=0; i<(ti->at(caseNo)->size()); i++)
                    tmp_And.push_back(ti->at(caseNo)->at(i)->_TriggerCondArrayIsAnd);
                if (tmp_And.empty()){
                }else{
                    filter_and_list[caseNo] = tmp_And[0];
                }
            }
        }
    }

    UInt4 num_of_counter_cases = 0;
    //if (_UCR->PutNumOfCases(true)==0) num_of_counter_cases=_UCR->PutNumOfCases();
    //else num_of_counter_cases = (_UCR->PutNumOfCases())/(_UCR->PutNumOfCases(true));
    std::pair<UInt4,UInt4> num_of_each_cases = _UCR->PutNumOfEachCases();
    num_of_counter_cases = num_of_each_cases.second;

    UInt4 lastCase = _UCR->_InitialCase;
    if (_filterCaseTables->at(index)->empty()){
    }else{
        std::vector<UInt4> *case_info = _filterCaseTables->at(index)->back();
        if ((case_info==NULL)||(case_info->empty())){
        }else{
            lastCase = case_info->at( case_info->size() -2 );
        }
    }
    //std::cout << "UtsusemiFilterTrignet:: num_of_counter_cases="<<num_of_counter_cases << std::endl;;
    if (_UTS->Merge( merged_case_table, filter_and_list, num_of_counter_cases, lastCase) ){
    }else{
        UtsusemiError( MessageTag+"preCaseSorting >> ERROR in Merge.");
        return;
    }

    // make _filterCaseTable
    if (_filterPulseIdLists->at(index)==NULL){
        _filterPulseIdLists->at(index) = new std::vector<UInt8>;
        _filterInstClockLists->at(index) = new std::vector<Double>;
        _filterCaseTables->at(index) = new std::vector< std::vector<UInt4>* >;
    }

    UInt4 num_of_casetables = (UInt4)(_UTS->PulseIdTable.size());
#ifdef DEBUG_UTSUSEMI
    std::cout << "---UtsusemiFilterTrignet:: num_of_casetables="<<num_of_casetables<<std::endl;
#endif
    UInt4 size_of_filter_list = (UInt4)(_filterPulseIdLists->at(index)->size());
    _filterPulseIdLists->at(index)->resize( (size_of_filter_list+num_of_casetables) );
    _filterInstClockLists->at(index)->resize( (size_of_filter_list+num_of_casetables) );
    for (UInt4 i=0; i<num_of_casetables; i++){
        _filterPulseIdLists->at(index)->at(size_of_filter_list+i)= _UTS->PulseIdTable[i];
        _filterInstClockLists->at(index)->at(size_of_filter_list+i)= _UTS->InstClockTable[i];
    }
#ifdef DEBUG_UTSUSEMI
    if (num_of_casetables!=merged_case_table->size()){
        std::cout << "## PulseIdTable size != Merged case table size "<< std::endl;

    }
#endif
    _filterCaseTables->at(index)->resize( (size_of_filter_list+num_of_casetables) );
    for (UInt4 i=0; i<num_of_casetables; i++)
        _filterCaseTables->at(index)->at(size_of_filter_list+i)=merged_case_table->at(i);

    delete merged_case_table;
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ReadTrigEventFile( std::string trig_event_file, std::vector<UInt8> T0Table, UInt4 index ){
    isTrigTableReady=false;
    bool debug = false;

    if ((T0Table.size()==1)&&(T0Table[0]==0)) return;
    if (!(isCaseInfoReady)) return;

    struct stat filestat;
    if( stat( trig_event_file.c_str(), &filestat ) != 0 ){
        UtsusemiError( MessageTag + "ReadEventDataFile : Cannot open " + trig_event_file );
        return;
    }

    ClearCaseTables(index, true);
    ClearPIDLists(index, true);
    ClearICLists(index, true);

    FILE *fin;
    fin = fopen( trig_event_file.c_str(), "rb" );

    UInt8 ReadingNumOfEvents = T0Table[0];

    if (fseek( fin, (long)(ReadingNumOfEvents*_eventSize), SEEK_SET )!=0){
        std::string msg = MessageTag+"ReadEventDataFile :  Cannot read enough event data from file";
        UtsusemiError( msg );
        return;
    }

    // The block of event-data before first T0-data should be removed.
    size_t ii;
    UInt4 ReadingStep = 1500;

    UInt4 ReadingTimes = (UInt4)(T0Table.size()) / ReadingStep;
    UInt4 StepRemainder = (UInt4)(T0Table.size()) % ReadingStep;

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

    std::vector<UInt8> NewT0( ReadingStep+1, 0 );

    //StringTools *_stools = new StringTools();
    for( UInt4 k=0; k<ReadingTimes; k++ ){
        ReadingNumOfEvents = T0Table[(k+1)*ReadingStep] - T0Table[k*ReadingStep];
        UInt8 StartPoint = T0Table[ k * ReadingStep ];
        UChar *Dat = new UChar [ ReadingNumOfEvents * _eventSize ];

        ii = fread( Dat, _eventSize, ReadingNumOfEvents, fin );
        if (ii!=ReadingNumOfEvents){
            std::string msg = MessageTag+"ReadEventDataFile : Cannot read enough event data from file (ReadingNumOfEvents,ii = ";
            msg += _stools->UInt4ToString((UInt4)ReadingNumOfEvents) + "," + _stools->UInt4ToString((UInt4)(ii)) + ")";
            UtsusemiWarning( msg );
        }else{
            for( UInt4 i=k*ReadingStep; i<=(k+1)*ReadingStep; i++ ){
                NewT0[i-k*ReadingStep] = T0Table[i]-StartPoint ;
            }
            PreCaseSorting( Dat, NewT0, index );
        }
        delete [] Dat;

    }

    ReadingNumOfEvents = T0Table[ T0Table.size()-1 ] - T0Table[ ReadingTimes*ReadingStep ];
    UInt8 StartPoint = T0Table[ ReadingTimes*ReadingStep ];
    UChar *Dat = new UChar [ ReadingNumOfEvents * _eventSize ];

    ii = fread( Dat, _eventSize, ReadingNumOfEvents, fin );
    if (ii!=ReadingNumOfEvents){
        std::string msg = MessageTag+"ReadEventDataFile : Cannot read enough event data from file (ReadingNumOfEvents,ii = ";
        msg += _stools->UInt4ToString((UInt4)ReadingNumOfEvents) +","+ _stools->UInt4ToString((UInt4)ii) + ")";
        UtsusemiWarning( msg );
    }else{
        std::vector<UInt8> NewT0( StepRemainder,0 );

        for( UInt4 i=ReadingTimes*ReadingStep; i<ReadingTimes*ReadingStep+StepRemainder; i++ ){
            NewT0[i-ReadingTimes*ReadingStep] = T0Table[i]-StartPoint;
        }
        PreCaseSorting( Dat, NewT0, index );
    }
    fclose(fin);
    delete [] Dat;
    //delete _stools;

    isTrigTableReady=true;
    MakeCaseTable();

}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ReadTrigEvent( std::string trig_event_file, std::string trig_t0_file, UInt4 index ){
    std::vector<std::string> f1(1,trig_event_file);
    std::vector<std::string> f2(1,trig_t0_file);
    ReadTrigEvent( f1, f2, index );
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ReadTrigEvent( std::vector<std::string> trig_event_files, std::vector<std::string> trig_t0_files, UInt4 index ){
    isTrigTableReady=false;
    bool debug = false;

    T0TreatToolsNeunet *TT = new T0TreatToolsNeunet();
    Int4 ret = TT->readT0IndexEvent( trig_t0_files );
    if (ret<0){
        UtsusemiError( MessageTag + "ReadTrigEvent >> fails to read T0Index File" );
        return;
    }
    std::vector<UInt8> T0Table = TT->putVectorT0Index();
    std::vector<Double> T0InstClockTable = TT->putVectorT0Clock();
    _firstT0InstClock = T0InstClockTable[0]; //[second]
    delete TT;

    if ((T0Table.size()==1)&&(T0Table[0]==0)) return;
    if (!(isCaseInfoReady)) return;

    std::vector<UInt4> trig_event_files_size( trig_event_files.size(), 0 );
    for (UInt4 i=0; i<trig_event_files.size(); i++){
        const boost::filesystem::path trig_event_files_path( trig_event_files[i].c_str() );
        const boost::uintmax_t size = boost::filesystem::file_size(trig_event_files_path);
        trig_event_files_size[i] = (UInt4)size;
    }

    ClearCaseTables(index, true);
    ClearPIDLists(index, true);
    ClearICLists(index, true);

    std::vector<FILE*> fp_list( trig_event_files.size() );
    for (UInt4 i=0; i<trig_event_files.size(); i++)
        fp_list[i] = fopen( trig_event_files[i].c_str(), "rb" );

    UInt8 ReadingNumOfEvents = T0Table[0];
    UInt4 ind = 0;

    if (fseek( fp_list[ind], (long)(ReadingNumOfEvents*_eventSize), SEEK_SET )!=0){
        std::string msg = MessageTag+"ReadTrigEvent : Cannot read enough event data from file";
        UtsusemiError( msg );
        return;
    }

    // The block of event-data before first T0-data should be removed.
    size_t ii;
    UInt4 ReadingStep = 1500;

    UInt4 ReadingTimes = (UInt4)(T0Table.size()) / ReadingStep;
    UInt4 StepRemainder = (UInt4)(T0Table.size()) % ReadingStep;

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

    std::vector<UInt8> NewT0( ReadingStep+1, 0 );

    //StringTools *_stools = new StringTools();
    bool isRead = true;
    bool isReadLast = true;
    UInt8 current_posi = ReadingNumOfEvents*_eventSize;
    for( UInt4 k=0; k<ReadingTimes; k++ ){
        ii = 0;
        ReadingNumOfEvents = T0Table[(k+1)*ReadingStep] - T0Table[k*ReadingStep];
        UInt8 StartPoint = T0Table[ k * ReadingStep ];
        UChar *Dat = new UChar [ ReadingNumOfEvents * _eventSize ];

        if ((current_posi+(ReadingNumOfEvents*(_eventSize))) <= trig_event_files_size[ind]){
            ii = fread( Dat, _eventSize, ReadingNumOfEvents, fp_list[ind] );
            if (ii==ReadingNumOfEvents){
                current_posi += ReadingNumOfEvents*(_eventSize);
            }else{
                isRead = false;
            }
        }else{
            if (ind==(fp_list.size()-1)){
                isRead = false;
            }else{
                UInt4 RE_tmp = (trig_event_files_size[ind]-(UInt4)current_posi)/(_eventSize);
                UChar *Dat_tmp = new UChar [RE_tmp*(_eventSize)];
                ii = fread( Dat_tmp, _eventSize, RE_tmp, fp_list[ind] );
                if (ii==RE_tmp){
                    for (UInt4 l=0;l<(ii*(_eventSize));l++) Dat[l]=Dat_tmp[l];
                }else{
                    isRead = false;
                }
                delete [] Dat_tmp;

                if (isRead){
                    ind++;
                    RE_tmp = (UInt4)ReadingNumOfEvents - (UInt4)ii;
                    UChar *Dat_tmp = new UChar [RE_tmp*(_eventSize)];
                    UInt4 ii_tmp = (UInt4)fread( Dat_tmp, _eventSize, RE_tmp, fp_list[ind] );
                    if (ii_tmp==RE_tmp){
                        for (UInt4 l=0;l<(ii_tmp*(_eventSize));l++) Dat[(ii*(_eventSize))+l]=Dat_tmp[l];
                        current_posi = ii_tmp*(_eventSize);
                    }else{
                        isRead = false;
                    }
                    delete [] Dat_tmp;
                }
            }
        }

        if (isRead){
            for( UInt4 i=k*ReadingStep; i<=(k+1)*ReadingStep; i++ ){
                NewT0[i-k*ReadingStep] = T0Table[i]-StartPoint ;
            }
            PreCaseSorting( Dat, NewT0, index );
        }else{
            std::string msg = "";
            if (ii != 0){
                msg += MessageTag + "ReadTrigEvent : Cannot read enough event data from file (ReadingNumOfEvents,ii = ";
                msg += _stools->UInt4ToString((UInt4)ReadingNumOfEvents) + "," + _stools->UInt4ToString((UInt4)ii) + ")";
            }else{
                msg += MessageTag + "ReadTrigEvent : Cannot read enough event data from file (TrigNET event file size is smaller)";
            }
            UtsusemiError( msg );
            delete [] Dat;
            break;
        }

        delete [] Dat;
    }

    if (isRead){
        ii = 0;
        ReadingNumOfEvents = T0Table[ T0Table.size()-1 ] - T0Table[ ReadingTimes*ReadingStep ];
        UInt8 StartPoint = T0Table[ ReadingTimes*ReadingStep ];
        UChar *Dat = new UChar [ ReadingNumOfEvents * _eventSize ];

        isReadLast = true;
        if ((current_posi+(ReadingNumOfEvents*(_eventSize))) <= trig_event_files_size[ind]){
            ii = fread( Dat, _eventSize, ReadingNumOfEvents, fp_list[ind] );
            if (ii!=ReadingNumOfEvents) isReadLast = false;
        }else{
            if (ind==(fp_list.size()-1)){
                isReadLast = false;
            }else{
                UInt8 RE_tmp = (trig_event_files_size[ind] - current_posi)/(_eventSize);
                UChar *Dat_tmp = new UChar [RE_tmp*(_eventSize)];
                ii = fread( Dat_tmp, _eventSize, RE_tmp, fp_list[ind] );
                if (ii==RE_tmp){
                    for (UInt4 l=0;l<(ii*(_eventSize));l++) Dat[l]=Dat_tmp[l];
                }else{
                    isReadLast = false;
                }
                delete [] Dat_tmp;

                if (isReadLast){
                    ind++;
                    RE_tmp = ReadingNumOfEvents - ii;
                    UChar *Dat_tmp = new UChar [RE_tmp*(_eventSize)];
                    UInt8 ii_tmp = fread( Dat_tmp, _eventSize, RE_tmp, fp_list[ind] );
                    if (ii_tmp==RE_tmp) {
                        for (UInt4 l=0;l<(ii_tmp*(_eventSize));l++) Dat[(ii*(_eventSize))+l]=Dat_tmp[l];
                    } else {
                        isReadLast = false;
                    }
                    delete [] Dat_tmp;
                }
            }
        }

        if (isReadLast){
            NewT0.clear();
            NewT0.resize( StepRemainder,0 );
            for( UInt4 i=ReadingTimes*ReadingStep; i<ReadingTimes*ReadingStep+StepRemainder; i++ ){
                NewT0[i-ReadingTimes*ReadingStep] = T0Table[i]-StartPoint;
            }
            PreCaseSorting( Dat, NewT0, index );
        }else{
            std::string msg = "";
            if (ii != 0){
                msg += MessageTag + "ReadTrigEvent (Last): Cannot read enough event data from file (ReadingNumOfEvents,ii = ";
                msg += _stools->UInt4ToString((UInt4)ReadingNumOfEvents) + "," + _stools->UInt4ToString((UInt4)ii) + ")";
            }else{
                msg += MessageTag + "ReadTrigEvent (Last): Cannot read enough event data from file (TrigNET event file size is smaller)";
            }
            UtsusemiWarning( msg );
        }
        delete [] Dat;
    }
    std::vector<FILE*>::iterator it = fp_list.begin();
    while(it!=fp_list.end()){
        fclose( *it );
        it++;
    }

    //delete _stools;

    if (isRead){
        isTrigTableReady=true;
        MakeCaseTable();
    }
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
ReadTrigEventFile( std::string trig_event_file, UInt4 index ){
    isTrigTableReady=false;
    bool debug = false;

    if (!(isCaseInfoReady)) return;
    std::vector< std::vector< UtsusemiTrignetCondGroup* >* >* ti = _UCR->PutTrignetInfo();
    std::vector<UtsusemiTrignetCounter*>* tc = _UCR->PutTrignetCounterInfo();

    FILE *fin;
    if ((fin = fopen( trig_event_file.c_str(), "rb" ))==NULL){
        UtsusemiError(MessageTag+"ReadTrigEventFile : Fails to open event data "+trig_event_file);
      return;
    }

    if (_filterCaseTables==NULL) _filterCaseTables = new std::vector< std::vector< std::vector<UInt4>* >* >((index+1),NULL);
    if (_filterPulseIdLists==NULL) _filterPulseIdLists = new std::vector< std::vector<UInt8>* > ((index+1),NULL);
    if (_filterInstClockLists==NULL) _filterInstClockLists = new std::vector< std::vector<Double>* > ((index+1),NULL);

    if (_filterCaseTables->size()>(index+1)){
        _filterCaseTables->resize( (index+1), NULL );
        _filterPulseIdLists->resize( (index+1), NULL );
        _filterInstClockLists->resize( (index+1), NULL );
    }

    ClearCaseTables(index,true);
    ClearPIDLists(index,true);
    ClearICLists(index,true);

    _filterCaseTables->at(index) = new std::vector< std::vector<UInt4>* >;
    _filterPulseIdLists->at(index) = new std::vector<UInt8>;
    _filterInstClockLists->at(index) = new std::vector<Double>;

    //size_t ii;
    UChar buf0[8];
    UChar buf1[8];
    UInt4 flg = 0;
    Double clock = 0.0;
    Double first_clock = 0.0;
    UInt4 pre_tof = 0; //[clock]

    UInt4 frameNo =0;
    bool isAfterFirstT0=false;
    bool isShiftT0=false;

    UInt4 prev_case = 0;
    UInt4 current_case = 0;

    for(;;){
        if ( flg==0 ){
            if ( fread( buf0, sizeof(buf0), 1, fin )!=1 ){
                fclose( fin );
                flg=3;
            }else{
                if ((_UTD->isTrigEvent(buf0[0]))&&(isAfterFirstT0)){
                    std::vector<UInt4> *values = new std::vector<UInt4> (12,0);
                    UInt4 tof = pre_tof;
                    if ( -1<(_UTD->DecodeTrigEvent( buf0, values, index )) ){
                        tof = values->at(0);
                        // ignore event at top
                        //if ((frameNo==0)&&(pre_tof<=tof)) break;
                        if (pre_tof>tof){
                            frameNo +=1;
                            isShiftT0=true;
                        }
                        UInt4 size_of_table = (UInt4)(_filterCaseTables->at(index)->size());
                        if (size_of_table<(frameNo+1)){
                            std::vector<UInt4> *tmp_vec = new std::vector<UInt4>;
                            tmp_vec->push_back(prev_case);
                            tmp_vec->push_back(0);
                            _filterCaseTables->at(index)->push_back( tmp_vec );
                        }

                        tof = values->at(0);
                        UInt4 ind = values->at(1);
                        UInt4 sid1 = values->at(2);
                        UInt4 sid2 = values->at(3);
                        std::vector<UInt4>* cond = new std::vector<UInt4>(8,0);
                        for (UInt4 i=4;i<(values->size());i++){
                            cond->at(i-4)=values->at(i);
                        }

                        bool isDecided=false;
                        bool isDecidedTmp=false;
                        current_case = 0;
                        if (ti!=NULL){
                            for(UInt4 caseNo=0;caseNo<ti->size();caseNo++){
                                if (ti->at(caseNo)==NULL) continue;
                                for (UInt4 i=0;i<ti->at(caseNo)->size();i++){

                                    UtsusemiTrignetCondGroup* utg = ti->at(caseNo)->at(i);
                                    if (utg==NULL) continue;
                                    Int4 filterflag = utg->TrigFilter(ind,sid1,sid2,cond);
                                    Int4 tofflag = utg->TofFilter( tof );
                                    Int4 timeflag = utg->TimeFilter( clock, first_clock );
                                    if ( (filterflag==0)&&(tofflag==0)&&(timeflag==0) ) continue;
                                    if ( (filterflag==-1)||(tofflag==-1)||(timeflag==-1) ){
                                        current_case = 0;
                                        isDecidedTmp = true;
                                    }else{
                                        current_case = caseNo;
                                        isDecided = true;
                                    }
                                    if (isDecided) break;
                                }
                                if (debug){
                                    if (isDecided) {
                                        std::cout << "caseNo=" << caseNo <<":True /" << std::endl;
                                    }else{
                                        std::cout << "caseNo=" << caseNo <<":False /" << std::endl;
                                    }
                                }
                                if (isDecided) break;
                            }
                            if (isDecided){
                            }else if (isDecidedTmp){
                                current_case = 0;
                            }else{
                                current_case = prev_case;
                            }
                        }

                        if (tc!=NULL){
                            if (isDecided){ // Filter conditions have priority over a std::couter condition
                            }else{
                                for (UInt4 i=0;i<tc->size();i++){
                                    UInt4 tmp = tc->at(i)->CountEvent( ind,sid1,sid2,cond );
                                    if (tmp!=UTSUSEMIMASKVALUEUINT4){
                                        current_case = tmp;
                                        break;
                                    }
                                }
                            }
                        }else{
                            //std::cout << MessageTag+"::ReadTrigEventFile >> TriggerCounter is empty!!!" << std::endl;
                        }

                        delete cond;

                        if (current_case!=prev_case){
                            _filterCaseTables->at(index)->at(frameNo)->push_back(current_case);
                            _filterCaseTables->at(index)->at(frameNo)->push_back(tof);
                            prev_case=current_case;
                        }
                    }

                    delete values;

                    pre_tof = tof;
                }
            }
        }

        // finish
        if ( flg==3 ){
            break;
        }

        // if T0 event
        if (_UTD->isHeaderT0(buf0[0])){
            if (isAfterFirstT0==false) {
                isAfterFirstT0=true;
            }else{
                if (isShiftT0){
                    isShiftT0=false;
                }else{
                    frameNo++;
                    pre_tof = 0;
                }
            }
            _filterPulseIdLists->at(index)->push_back(_UTD->_decodePulseIdEvent( buf0 ) );
            UInt4 diff_num = (UInt4)( _filterPulseIdLists->at(index)->size() - _filterCaseTables->at(index)->size() );
            for (UInt4 i_diff=0;i_diff<diff_num;i_diff++){
                std::vector<UInt4> *tmp_vec = new std::vector<UInt4>;
                tmp_vec->push_back(prev_case);
                tmp_vec->push_back(0);
                _filterCaseTables->at(index)->push_back( tmp_vec );
            }

            if (fread( buf1, sizeof(buf1), 1, fin )!=1){
                fclose( fin );
                flg=3;
            }else{
                if (_UTD->isHeaderClock( buf1[0] )){
                    clock = _UTD->_decodeInstClockEvent( buf1 );
                    if (first_clock==0.0) first_clock = clock;
                    flg=0;
                }else{
                    //clock = 0.0;
                    memcpy( buf0, buf1, 8 );
                    flg=1;
                }
                _filterInstClockLists->at(index)->push_back(clock);
                if (flg==1){
                    if (_UTD->isHeaderT0( buf0[0] )) {
                    }else{
                        fseek( fin, -1*(Int4)sizeof(buf0), SEEK_CUR );
                        flg=0;
                    }
                }
            }
        }
    }
    if (_filterCaseTables->at(index)->size()!=_filterPulseIdLists->at(index)->size()){
        std::string msg = MessageTag + "ReadTrigEventFile : sizes are not same between CaseTable and PulseId ";
        msg += _stools->UInt4ToString((UInt4)(_filterCaseTables->at(index)->size()))+",";
        msg += _stools->UInt4ToString((UInt4)(_filterPulseIdLists->at(index)->size()))+",";
        msg += "frameNo="+_stools->UInt4ToString(frameNo);
        UtsusemiError( msg );
        return;
    }

    UtsusemiMessage(MessageTag + "ReadTrigEventFile >> CaseTable is ready.");
    if (debug){
        for (UInt4 i=0;i<_filterCaseTables->at(index)->size();i++){
            std::cout << "[index,frm=" << index << "," << i << "]";
            if (_filterCaseTables->at(index)->at(i)==NULL){
                std::cout << "  !!! NULL ";
            }else{
                for (UInt4 j=0;j<_filterCaseTables->at(index)->at(i)->size();j++){
                    std::cout << _filterCaseTables->at(index)->at(i)->at(j) << ",";
                }
            }
            std::cout << std::endl;
        }
        std::cout << std::endl;
    }
    isTrigTableReady=true;

    MakeCaseTable();

}

//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
MakeCaseTable( bool isAppend ){
    /* unify all CaseTables */
    std::vector< std::vector<bool> > isAndList( numOfCases+1 );
    std::vector< std::vector< UtsusemiTrignetCondGroup* >* >* ti = _UCR->PutTrignetInfo();
    //std::vector< std::vector<bool> > isAndList( ti->size() );
    if (ti!=NULL){
        for (UInt4 caseNo=0;caseNo<ti->size();caseNo++){
            if (ti->at(caseNo)!=NULL){
                std::vector<bool> tmp_And;
                for ( UInt4 i=0; i<(ti->at(caseNo)->size()); i++)
                    tmp_And.push_back(ti->at(caseNo)->at(i)->_TriggerCondArrayIsAnd);
                isAndList[caseNo] = tmp_And;
            }
        }
    }

    isFilterReady=false;
#ifdef DEBUG_UTSUSEMI
    std::cout << "@@@ UtsusemiFilterTrignet::MakeCaseTable start" << std::endl;
#endif
    if (isTrigTableReady){
        if (isAppend){
        }else{
            Clear();  // clear filterCaseTable and filterPulseIdList
            //std::cout << "@@@ UtsusemiFilterTrignet::MakeCaseTable > Make New filterCaseTable" << std::endl;
            filterCaseTable = new std::vector< std::vector<UInt4>* >;
        }
        if (filterCaseTable==NULL) filterCaseTable = new std::vector< std::vector<UInt4>* >;
        std::vector< std::pair<Int4,UInt4> > IndexOfTrigFile;
        for (UInt4 i=0;i<_filterCaseTables->size();i++){
            if (_filterCaseTables->at(i)!=NULL){
                std::pair<UInt4,UInt4> tmp;
                tmp.first=(Int4)i;  // filter index
                tmp.second=0;       // frame No
                IndexOfTrigFile.push_back(tmp);
            }
        }

        UInt8 minPID=0;
#ifdef DEBUG_UTSUSEMI
        std::cout << "@@@ UtsusemiFilterTrignet::MakeCaseTable > while loop " << std::endl;
        std::cout << "@@@ UtsusemiFilterTrignet::MakeCaseTable > _filterCaseTables->size()= "<<_filterCaseTables->size() << std::endl;
        std::cout << "@@@ UtsusemiFilterTrignet::MakeCaseTable > _filterCaseTables->at(0)->size()= "<<_filterCaseTables->at(0)->size() << std::endl;
        std::cout << "## _filterPulseIdLists->at( 0 )->size()="<<(_filterPulseIdLists->at( 0 )->size()) << std::endl;
#endif
        // Loop for frames
        std::vector<bool> n_list( IndexOfTrigFile.size(), true );
        bool isContinueFrames=true;
        while( isContinueFrames ){
            // Search minimum pulse id
            std::vector<UInt8> ap_list;
            ap_list.clear();

            for( UInt4 i=0;i<IndexOfTrigFile.size();i++ ){
                if (_filterPulseIdLists->at( IndexOfTrigFile[i].first )->empty()){
                    UtsusemiError(MessageTag + "_filterPulseIdList[ IndexOfTrigFile[i].first ] is Empty. i="+_stools->UInt4ToString(i));
                    return;
                }else{
                    ap_list.push_back(_filterPulseIdLists->at( IndexOfTrigFile[i].first )->at( IndexOfTrigFile[i].second ) );
                }
            }

            std::vector<bool> m_list( IndexOfTrigFile.size(), false );
            std::vector<UInt8>::iterator it_minPID = min_element( ap_list.begin(), ap_list.end() );
            minPID=(*it_minPID);
            for (UInt4 i=0;i<ap_list.size();i++)
                if (minPID==ap_list[i]) m_list[i]=true;

            // Loop in a frame
            std::vector<UInt4> tof_i( ap_list.size(), 0 );
            std::vector<UInt4> tof( ap_list.size(), 0 );
            std::vector<UInt4> caseId( ap_list.size(), 0 );
            std::vector<UInt4>* caseTableInAFrame = new std::vector<UInt4>;
            bool isContinueInAFrame=true;

            while(isContinueInAFrame){
                // Take current tof value for each TrigNET line
                for (UInt4 i=0;i<ap_list.size();i++){
                    if (m_list[i]){
#ifdef DEBUG_UTSUSEMI
                        std::cout << "IndexOfTrigFile[ i ].first=" << IndexOfTrigFile[ i ].first <<", IndexOfTrigFile[ i ].second="<<IndexOfTrigFile[ i ].second << std::endl;
                        std::cout << "_filterCaseTables->at( IndexOfTrigFile[ i ].first )->size()="<<_filterCaseTables->at( IndexOfTrigFile[ i ].first )->size() << std::endl;
#endif
                        caseId[i]=_filterCaseTables->at( IndexOfTrigFile[ i ].first )->at( IndexOfTrigFile[ i ].second )->at( tof_i[ i ] );
                        if (_filterCaseTables->at( IndexOfTrigFile[ i ].first )->at( IndexOfTrigFile[ i ].second )->size()==1){
                            tof[i]=0;
                        }else if (_filterCaseTables->at( IndexOfTrigFile[ i ].first )->at( IndexOfTrigFile[ i ].second )->size()==(tof_i[i]+1)){
                            tof[i] = 100000000;
                        }else{
                            tof[i]=_filterCaseTables->at( IndexOfTrigFile[ i ].first )->at( IndexOfTrigFile[ i ].second )->at( tof_i[ i ]+1 );
                        }
#ifdef DEBUG_UTSUSEMI
                        std::cout << "i="<<i<<", caseId[i]="<<caseId[i]<<", tof[i]="<<tof[i]<<std::endl;
#endif
                    }
                }

                // Choose minimum tof values and increment tof_i for the lines
                std::vector<UInt4>::iterator it_min_tof_in_index=min_element( tof.begin(), tof.end() );
                for (UInt4 i=0;i<ap_list.size();i++){
                    if (m_list[i]){
                        if ((*it_min_tof_in_index)==tof[i]){
                            tof_i[i]+=2;
                            if (tof_i[i]>=(_filterCaseTables->at( IndexOfTrigFile[ i ].first )->at( IndexOfTrigFile[ i ].second )->size()))
                                m_list[i]=false;
                        }
                    }
                }

                // Case Decision
                UInt4 cur_case=0;
                for ( UInt4 i=0;i<ap_list.size();i++){
                    if (isAndList.size()<=caseId[i]) continue;
                    std::vector<bool> flag_And = isAndList[ caseId[i] ];
                    if (flag_And.empty()) cur_case = caseId[i];
                    else{
                        for (UInt4 j=0; j<flag_And.size(); j++){
                            if (flag_And[j]){
                                std::vector<UInt4> andCaseList=ti->at(caseId[i])->at(j)->_TriggerCondArrayAndList;
                                for (std::vector<UInt4>::iterator it=andCaseList.begin(); it!=andCaseList.end(); ++it)
                                    if (m_list[i])
                                        if (caseId[ (*it) ]!=caseId[i]) continue;
                                cur_case = caseId[i];
                            }else{
                                cur_case = caseId[i];
                                break;
                            }
                        }
                    }
                }

                // Add to filterCaseTable; TOF=min_tof_in_index, Case=cur_case
                caseTableInAFrame->push_back( cur_case );
                caseTableInAFrame->push_back( *it_min_tof_in_index );

                // Loop check
                isContinueInAFrame=false;
                for (std::vector<bool>::iterator it=m_list.begin(); it!=m_list.end(); ++it){
                    if ((*it)==true) {
                        isContinueInAFrame=true;
                        break;
                    }
                }
            }

            // Add filterCaseTable and filterPulseIdList
            filterCaseTable->push_back( caseTableInAFrame );
            filterPulseIdList.push_back( minPID );

            // Increment frame and loop check
            for( UInt4 i=0;i<(UInt4)(IndexOfTrigFile.size());i++ ){
                if (n_list[i]){
#ifdef DEBUG_UTSUSEMI
                    std::cout << "## _filterPulseIdLists->at( IndexOfTrigFile[i].first )->size()="<<(_filterPulseIdLists->at( IndexOfTrigFile[i].first )->size()) << std::endl;
#endif
                    if (IndexOfTrigFile[i].second<((_filterPulseIdLists->at( IndexOfTrigFile[i].first )->size())-1)){
                        IndexOfTrigFile[i].second++;
#ifdef DEBUG_UTSUSEMI
                        std::cout << "IndexOfTrigFile[i].second++; ->"<<IndexOfTrigFile[i].second<< std::endl;
#endif
                    }else{
                        n_list[i]=false;
                    }
                }
            }

            isContinueFrames=false;
            for ( std::vector<bool>::iterator it_nlist=n_list.begin(); it_nlist!=n_list.end(); ++it_nlist ){
                if ((*it_nlist)==true) {
                    isContinueFrames=true;
                    break;
                }
            }
        }
    }
#ifdef DEBUG_UTSUSEMI
    for (UInt4 i=0; i<filterCaseTable->size(); i++){
        std::cout << "filterCaseTable->at("<<i<<") = ";
        for (UInt4 j=0; j<filterCaseTable->at(i)->size(); j++){
            std::cout << filterCaseTable->at(i)->at(j) << ",";
        }
        std::cout << std::endl;
    }
    std::cout << "@@@ UtsusemiFilterTrignet::MakeCaseTable fin" << std::endl;
#endif

    isFilterReady=true;
    _UCR->_InitialCase = filterCaseTable->back()->at(0);//[inamura 161118]
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
MakeFilterTables(){
    MakeCaseTable();
}
//////////////////////////////////////////////////////////
Int4 UtsusemiFilterTrignet::
ReadCaseEventFiles( UInt4 index, std::vector<std::string> evt_files, std::vector< std::vector<UInt8> > t0b_index_list ){
    if (t0b_index_list.empty()){
        ReadTrigEventFile( evt_files[index], index );
    }else{
        for (UInt4 i=0; i<evt_files.size(); i++){
            ReadTrigEventFile( evt_files[i], t0b_index_list[i], index );
        }
    }
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiFilterTrignet::
ReadCaseEvent( UInt4 index, std::vector<std::string> evt_files, std::vector<std::string> t0b_files ){
    ReadTrigEvent( evt_files, t0b_files, index );
    if (isFilterReady){
        return 0;
    }else{
        return -1;
    }
}
//////////////////////////////////////////////////////////
std::vector<UInt4> UtsusemiFilterTrignet::
PutListOfCases(){
    std::vector<UInt4> ret,filter_cases,counter_cases;
    if (isTimeSlicing()){
        ret.clear();
        for (UInt4 i=0; i<(_UCR->_TimeSlicing->size()); i++)
            if (_UCR->_TimeSlicing->at(i)!=NULL) ret.push_back(i);
        return ret;
    }

    if (!(isCaseInfoReady)) return ret;

    std::vector< std::vector< UtsusemiTrignetCondGroup* >* >* ti = _UCR->PutTrignetInfo();
    std::vector<UtsusemiTrignetCounter*>* tc = _UCR->PutTrignetCounterInfo();
    if (ti!=NULL){
        for (UInt4 caseNo=0;caseNo<(ti->size());caseNo++){
            if (ti->at(caseNo)!=NULL) filter_cases.push_back( caseNo );
        }
    }

    if (tc!=NULL){
        for (UInt4 i=0;i<(tc->size());i++){
            if (tc->at(i)!=NULL){
                if (tc->at(i)->ConditionType==1){
                    for (UInt4 caseId=0; caseId<tc->at(i)->ConditionList.size(); caseId++)
                        if (tc->at(i)->ConditionList[caseId]!=NULL)
                            counter_cases.push_back( caseId );
                }else if (tc->at(i)->ConditionType==2){
                    for (UInt4 j=0; j<tc->at(i)->ConditionList.size(); j++){
                        if (tc->at(i)->ConditionList[j]!=NULL){
                            double cond_start = tc->at(i)->ConditionList[j]->at(0);
                            double cond_end   = tc->at(i)->ConditionList[j]->at(1);
                            double cond_step  = tc->at(i)->ConditionList[j]->at(2);
                            UInt4 cnt = (UInt4)((cond_end - cond_start)/cond_step);
                            for (UInt4 caseId=1; caseId<cnt+1; caseId++) counter_cases.push_back( caseId );
                        }
                    }
                }
            }
        }
    }

    if ((filter_cases.empty())&&(!(counter_cases.empty()))){
        ret.resize( counter_cases.size() );
        copy( counter_cases.begin(), counter_cases.end(), ret.begin() );
    }else if ((!(filter_cases.empty()))&&(counter_cases.empty())){
        ret.resize( filter_cases.size() );
        copy( filter_cases.begin(), filter_cases.end(), ret.begin() );
    }else{
        for (UInt4 i=0; i<filter_cases.size(); i++)
            for (UInt4 j=0; j<counter_cases.size(); j++)
                ret.push_back( (filter_cases[i]-1)*(UInt4)(counter_cases.size()) + counter_cases[j] );
    }

    return ret;
}
//////////////////////////////////////////////////////////
std::vector< std::pair<Double,Double> > UtsusemiFilterTrignet::
PutListOfCounterConditions(){
    std::vector< std::pair<Double,Double> > ret;
    if (!(isCaseInfoReady)) {
        UtsusemiError( MessageTag+"PutListOfContainerConditions > CaseInfo is not ready." );
        return ret;
    }

    std::vector<UtsusemiTrignetCounter*>* tc = _UCR->PutTrignetCounterInfo();
    if (tc!=NULL){
        for (UInt4 i=0;i<(tc->size());i++){
            if (tc->at(i)!=NULL){
                if (tc->at(i)->ConditionType==1){
                    for (UInt4 caseId=0; caseId<tc->at(i)->ConditionList.size(); caseId++){
                        if (tc->at(i)->ConditionList[caseId]!=NULL){
                            std::pair<Double,Double> tmp;
                            tmp.first  = tc->at(i)->ConditionList[caseId]->at(0);
                            tmp.second = tc->at(i)->ConditionList[caseId]->at(1);
                            if (caseId>=ret.size()) ret.resize( caseId+1 );
                            ret[caseId] = tmp;
                        }
                    }
                }else if (tc->at(i)->ConditionType==2){
                    for (UInt4 j=0; j<tc->at(i)->ConditionList.size(); j++){
                        if (tc->at(i)->ConditionList[j]!=NULL){
                            double cond_start = tc->at(i)->ConditionList[j]->at(0);
                            double cond_end   = tc->at(i)->ConditionList[j]->at(1);
                            double cond_step  = tc->at(i)->ConditionList[j]->at(2);
                            UInt4 cnt = (UInt4)( (cond_end - cond_start)/cond_step );
                            for (UInt4 caseId=1; caseId<cnt+1; caseId++){
                                std::pair<Double,Double> tmp;
                                tmp.first  = cond_start + cond_step*(caseId-1);
                                tmp.second = cond_start + cond_step*caseId;
                                if (caseId>=ret.size()) ret.resize( caseId+1 );
                                ret[caseId] = tmp;
                            }
                        }
                    }
                }else{
                    UtsusemiError( MessageTag+"PutListOfContainerConditions > ConditionType is invalid." );
                }
            }
        }
    }else{
        UtsusemiError( MessageTag+"PutListOfContainerConditions > TrigCounter is empty." );
    }
    return ret;
}
//////////////////////////////////////////////////////////
UInt4 UtsusemiFilterTrignet::
GetCaseFromTof( const UInt4 pixelId, Double* tof, std::vector<UInt4>* caseVec ){
    UInt4 ret=0;
    UInt4 num_of_cases = (UInt4)(caseVec->size());

    if (num_of_cases==1){
        UtsusemiMessage( MessageTag+"GetCaseFromTof > num_of_cases=1" );
        ret = caseVec->at(0);
    }else{
        for (UInt4 i=(num_of_cases-1); i>0; i-=2){
            if ( (*tof)/MLF_NEUNET_CLOCK_MICROSEC >= (caseVec->at(i) ) ){ //Unit of tof in cases is [clock(25nano-sec)]
                ret = caseVec->at(i-1);
                break;
            }
        }
    }
    return ret;
}
//////////////////////////////////////////////////////////
bool UtsusemiFilterTrignet::
DumpTrigEventFile( std::string trig_file, std::string out_file, bool isDecorated, bool withT0 ){
    FILE *fin;
    if ((fin = fopen( trig_file.c_str(), "rb" ))==NULL){
        UtsusemiError( MessageTag+"DumpTrigEventFile : Fails to open event data "+trig_file );
        return false;
    }
    FILE *fout;
    if ((fout = fopen( out_file.c_str(), "wb" ))==NULL){
        UtsusemiError( MessageTag+"DumpTrigEventFile : Fails to open event data "+out_file );
        return false;
    }

    std::vector<std::string> SID1(32,"---------");
    for (UInt4 i=0;i<8;i++){
        Char ckey[10];
        std::snprintf( ckey, sizeof(ckey), "DIO%d  Up ", i+1);
        std::string key(ckey);
        SID1[i] = key;
    }
    for (UInt4 i=0;i<8;i++){
        Char ckey[10];
        std::snprintf( ckey, sizeof(ckey), "DIO%d Down", i+1);
        std::string key(ckey);
        SID1[i+16] = key;
    }
    SID1[14] = "T0 Up    ";
    SID1[15] = "TI Event ";
    SID1[31] = "S/W Event";

    std::vector<std::string> SID2(5,"-------");
    SID2[1] = "    DIO";
    SID2[2] = "LS ADC1";
    SID2[3] = "LS ADC2";
    SID2[4] = " HS ADC";

    UChar *evt = new UChar [_eventSize];
    size_t ii;
    UInt8 pulse_id = 0;
    Double clock = 0.0;
    Double first_clock=-1.0;
    if (isDecorated){
        //                 2025/12/05 03:59:52,      0.000000,  393317.4750, DIO1  Up , LS ADC1 [8388608,0,0,0,0,0,0,0]
        std::string tmp = "#         Date Time,     Time(sec),   TOF(m-sec),   Trigger, Type [bits]\n";
        ii=std::fwrite( tmp.c_str(), tmp.size(), 1, fout );
    }
    T0TreatToolsNeunet* TT = new T0TreatToolsNeunet();
    while(true){
        ii = fread( evt, _eventSize, 1, fin );
        if (ii==1){
            // if T0 event
            //if ( _UTD->isHeaderT0(*evt) ) pulse_id = _UTD->decodePulseIdEvent( evt );
            if ( _UTD->isHeaderT0(*evt) ){
                pulse_id = _UTD->decodePulseIdEvent( evt );
                if (withT0){
                    Char pp[50];
                    std::snprintf(pp, sizeof(pp), "=== Kicker ID : %lld\n", pulse_id);
                    std::string tmp(pp);
                    size_t ret = std::fwrite( pp, tmp.size(), 1, fout );
                }
            }
            // if clock event
            if ( _UTD->isHeaderClock(*evt) ) {
                clock = _UTD->decodeInstClockEvent( evt );
                if (first_clock<0.0) first_clock = clock;
            }

            // if TrigEvent
            if ( _UTD->isTrigEvent(*evt) ){
                std::vector<UInt4> *values = new std::vector<UInt4> (12,0);
                if ( -1<( _UTD->DecodeTrigEvent( evt, values, 0 ) ) ){
                    UInt4 tof = values->at(0);
                    UInt4 sid1 = values->at(2);
                    UInt4 sid2 = values->at(3);
                    std::vector<UInt4>* cond = new std::vector<UInt4>(8,0);
                    for (UInt4 i=4;i<(values->size());i++) cond->at(i-4)=values->at(i);

                    // Calculate date time from clocks
                    std::vector<Double> dtv = TT->convertInstClockToDateTime(clock);
                    Char dtc[100];
                    std::snprintf(dtc, sizeof(dtc), "%4d/%02d/%02d %02d:%02d:%02d, ", UInt4(dtv[0]), UInt4(dtv[1]), UInt4(dtv[2]), UInt4(dtv[3]), UInt4(dtv[4]), UInt4(dtv[5]));
                    std::string dt_s(dtc);

                    Char a_line[100];
                    Double f_tof = (Double)tof*MLF_NEUNET_CLOCK_MICROSEC;
                    if (isDecorated){
                        std::snprintf( a_line, sizeof(a_line), "%s %12.6f, %12.4f, %s, %s [%d,%d,%d,%d,%d,%d,%d,%d]\n",dt_s.c_str(),(clock-first_clock),f_tof,SID1[sid1].c_str(),SID2[sid2].c_str(),cond->at(0),cond->at(1),cond->at(2),cond->at(3),cond->at(4),cond->at(5),cond->at(6),cond->at(7));
                    }else{
                        std::snprintf( a_line, sizeof(a_line), "%12.6f,%12.4f,%2d,%2d,%d,%d,%d,%d,%d,%d,%d,%d\n",(clock-first_clock),f_tof,sid1,sid2,cond->at(0),cond->at(1),cond->at(2),cond->at(3),cond->at(4),cond->at(5),cond->at(6),cond->at(7));
                    }
                    std::string tmp( a_line );
                    //std::cout << tmp << std::endl;
                    size_t ret = std::fwrite( a_line, tmp.size(), 1, fout );
                    delete cond;
                    if (ret!=1){
                        UtsusemiError(MessageTag+"DumpTrigEventFile : Failed to write into file ");
                        delete values;
                        fclose( fin );
                        fclose( fout );
                        return false;
                    }
                }
                delete values;
            }
        }else{
            break;
        }
    }
    delete TT;
    delete [] evt;
    fclose( fin );
    fclose( fout );
    return true;
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
DumpCaseTable(std::string file){
    if (isFilterReady){
    }else{
        return;
    }
    if (file==""){
        for (UInt4 i=0; i<filterCaseTable->size(); i++){
            std::cout << "filterCaseTable->at("<<i<<") = ";
            for (UInt4 j=0; j<filterCaseTable->at(i)->size(); j++){
                std::cout << filterCaseTable->at(i)->at(j) << ",";
            }
            std::cout << std::endl;
        }
    }else{
        std::ofstream ofs( file.c_str() );
        for (UInt4 i=0; i<filterCaseTable->size(); i++){
            ofs << "filterCaseTable->at("<<i<<") = ";
            for (UInt4 j=0; j<filterCaseTable->at(i)->size(); j++){
                ofs << filterCaseTable->at(i)->at(j) << ",";
            }
            ofs << std::endl;
        }
        ofs.close();
    }
}
//////////////////////////////////////////////////////////
bool UtsusemiFilterTrignet::
isTimeSlicing(){
    if (_UCR->_TimeSlicing==NULL) return false;
    return true;
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
MakeTimeSlicingCases( std::vector<UInt8> _pulseId, std::vector<double> _seconds ){
    if (_UCR->_TimeSlicing==NULL){
        UtsusemiError(MessageTag+"MakeTimeSlicingCases false");
        return;
    }
    Clear();
    filterPulseIdList.resize( _pulseId.size() );
    copy(_pulseId.begin(), _pulseId.end(), filterPulseIdList.begin() );
    filterCaseTable = new std::vector< std::vector<UInt4>* >( _pulseId.size(), NULL );
    for (UInt4 i=0; i<_pulseId.size(); i++)
        filterCaseTable->at(i) = new std::vector<UInt4>(1,0);
    double first_second = _seconds[0];
    //_UCR->DumpCases();
    for (UInt4 caseId=1; caseId<(_UCR->_TimeSlicing->size()); caseId++){
        if (_UCR->_TimeSlicing->at(caseId)!=NULL){

            double min_second = (_UCR->_TimeSlicing->at(caseId)->first);
            double max_second = (_UCR->_TimeSlicing->at(caseId)->second);
            UInt4 last_frame = 0;
            for (UInt4 i=0; i<_seconds.size(); i++){
                if (_seconds[i]>=(max_second+first_second)) break;
                if ((_seconds[i]>=(min_second+first_second))&&(_seconds[i]<(max_second+first_second))){
                    filterCaseTable->at(i)->at(0) = caseId;
                    last_frame = i;
                }
            }
            filterCaseTable->at(last_frame)->at(0) = 0;
        }
    }
    isFilterReady=true;
}
//////////////////////////////////////////////////////////
void UtsusemiFilterTrignet::
SetTimeSlicing( std::vector<Double> tmp ){
    _UCR->SetTimeSlicing( tmp );
    numOfCases = _UCR->PutNumOfCases();
}
