#ifndef UTSUSEMIEVENTCASEDECODERTEMPLATE_CC
#define UTSUSEMIEVENTCASEDECODERTEMPLATE_CC

#include "UtsusemiEventCasesDecoderTemplate.hh"
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
UtsusemiEventCasesDecoderTemplate<T1,T2>::
UtsusemiEventCasesDecoderTemplate()
{
    Initialize();
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
UtsusemiEventCasesDecoderTemplate<T1,T2>::
~UtsusemiEventCasesDecoderTemplate()
{
    delete _TT;
    delete _FF;
    delete stools;
    Clear(0);
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
Initialize()
{
    _NumOfCases = 1;
    _TT = new T1();
    _FF = new T2();

    //_rangeSingleTimeSlice.clear();
    stools = new StringTools();
    _MessageTag = "UtsusemiEventCasesDecoderTemplate >> ";

    _CaseTable = NULL;

    _L2OfPixels.clear();
    _L1Vect.clear();
    _T0ShiftVect.clear();
    _pixelPositionVect = NULL;
    isCheckedPulseId = true;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
Clear( UInt4 flag ){
    if ((flag==0)||(flag==1)){
        if (_CaseTable!=NULL){
            if (!(_CaseTable->empty())){
                for (UInt4 i=0;i<_CaseTable->size();i++){
                    if (_CaseTable->at(i)!=NULL) delete _CaseTable->at(i);
                }
            }
            delete _CaseTable;
        }
        _CaseTable=NULL;
    }


}

/////////////////////////////////////////////////////////////
// Virtual Functions for UtsusemiEventCaseDecoderBase
/////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Double UtsusemiEventCasesDecoderTemplate<T1,T2>::
CalcIncrementPosi( Double* tof, UInt4* pixelId, UInt4* caseId )
{
    return (Double)(*tof);
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
UInt4 UtsusemiEventCasesDecoderTemplate<T1,T2>::
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){
        ret = caseVec->at(0);
    }else{
        if ( _L2OfPixels.empty() ){
        }else{
            (*tof) = ShiftTofAtSample( (*tof),pixelId );
        }
        ret = _FF->GetCaseFromTof( pixelId, tof, caseVec );
    }
    return ret;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector<UInt8> UtsusemiEventCasesDecoderTemplate<T1,T2>::
PutT0Index()
{
    return _TT->PutT0Index();
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector<UInt8> UtsusemiEventCasesDecoderTemplate<T1,T2>::
PutPulseId()
{
    return _TT->PutPulseId();
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector<Double> UtsusemiEventCasesDecoderTemplate<T1,T2>::
PutT0ClockDiff()
{
    return _TT->PutT0ClockDiff();
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector< std::vector<UInt4>* >* UtsusemiEventCasesDecoderTemplate<T1,T2>::
PutCaseTable()
{
    return _CaseTable;
}

/////////////////////////////////////////////////////////////
// Functions for T0TreatToolsXXX
/////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventCasesDecoderTemplate<T1,T2>::
ReadT0IndexEventFile( std::string t0Data, UInt4 num_of_clocks )
{
    _TT->readT0IndexEvent( t0Data );
    _TT->setNumOfClocksBeforeFirstT0( num_of_clocks );
    return 0;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Int4 UtsusemiEventCasesDecoderTemplate<T1,T2>::
ReadT0IndexEventFile( std::vector<std::string> t0DataSet, UInt4 num_of_clocks )
{
    _TT->readT0IndexEvent( t0DataSet );
    _TT->setNumOfClocksBeforeFirstT0( num_of_clocks );
    return 0;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector<Double> UtsusemiEventCasesDecoderTemplate<T1,T2>::
PutMeasPeriodFromT0()
{
    return _TT->putMeasPeriodFromT0();
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
bool UtsusemiEventCasesDecoderTemplate<T1,T2>::
SetRangeOfSingleTimeSlicing( double startSec, double endSec )
{
    return _TT->SetRangeOfSingleTimeSlicing( startSec, endSec );
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
bool UtsusemiEventCasesDecoderTemplate<T1,T2>::
SetRangeOfSingleTimeSlicing( std::string startDate, std::string endDate )
{
    return _TT->SetRangeOfSingleTimeSlicing( startDate, endDate );
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
CheckCaseTableWithT0Index(){

    if (!(_FF->isFilterReady)){
        //std::cout << _MessageTag+"::CheckCaseTableWithT0Index No Filter is set, nothing to do." << std::endl;
        return;
    }

    //std::cout << _MessageTag << "::CheckCaseTableWithT0Index start" << std::endl;
    //[inamura 160104]--> to enable SetRangeOfSingleTimeSlicing
    // When do PutCaseTable(), correct time-sliced region will return.
    //std::vector<UInt8> t0_pulse_edb = _TT->putVectorPulseId();
    //std::vector<UInt8> t0_index_edb = _TT->putVectorT0Index();
    //std::vector<Double> t0_clock_edb = _TT->putT0ClockDiffAll();
    std::vector<UInt8> t0_pulse_edb = PutPulseId();
    std::vector<UInt8> t0_index_edb = PutT0Index();
    std::vector<Double> t0_clock_edb = PutT0ClockDiff();
    //<--[inamura 160104]

    if ((t0_pulse_edb.size()==1)&&(t0_pulse_edb[0]==0)){
        UtsusemiError( _MessageTag+"No T0 Index Information, nothing to do." );
        return;
    }
    /*
    std::cout << _MessageTag+"@@@ t0_pulse_edb.size()=" << t0_pulse_edb.size() << std::endl;
    std::cout << _MessageTag+"@@@ t0_index_edb.size()=" << t0_index_edb.size() << std::endl;
    std::cout << _MessageTag+"@@@ t0_clock_edb.size()=" << t0_clock_edb.size() << std::endl;
    std::cout << _MessageTag+"@@@ _FF->filterPulseIdList.size()=" << _FF->filterPulseIdList.size() << std::endl;
    std::cout << "t0_pulse_edb =" << t0_pulse_edb[0]<<","<< t0_pulse_edb[1]<<","<< t0_pulse_edb[2]<<"," << t0_pulse_edb.back()<< std::endl;
    std::cout << "_FF->filterPulseIdList[0]=" << _FF->filterPulseIdList[0] << std::endl;
    */
    if (t0_pulse_edb.size()!=(_FF->filterPulseIdList.size()+1)){ //[inamura 161117]
        std::string msg = _MessageTag+"CheckCaseTableWithT0Index >> WARNING!! \n";
        msg +="                  The number of T0 in Neutron Event files is different from that of Case Table\n";
        msg +="                  [Neutron, Case]=["+stools->UInt4ToString((UInt4)(t0_pulse_edb.size()));
        msg +=","+stools->UInt4ToString((UInt4)(_FF->filterPulseIdList.size()))+"]";
        UtsusemiWarning( msg );
    }
    //isCheckedPulseId = false;
    if (!isCheckedPulseId){
        _FF->CheckAmbiguousFrame();
        Clear(1);
        _CaseTable = new std::vector< std::vector<UInt4>* >;
        UInt4 min_size = (UInt4)( std::min( t0_index_edb.size()-1, _FF->filterPulseIdList.size() ) );
        _CaseTable->resize( min_size, NULL);
        for (UInt4 i=0;i<min_size;i++){
            _CaseTable->at(i) = new std::vector<UInt4>;
            _CopyCaseTable( _CaseTable->at(i), _FF->filterCaseTable->at(i) );
        }
        return;
    }

    std::vector< std::vector<UInt4>* >* ckdCaseTable = new std::vector< std::vector<UInt4>* >;
    ckdCaseTable->clear();
    ckdCaseTable->resize( t0_index_edb.size(),NULL);
    for (UInt4 i=0;i<t0_index_edb.size();i++) ckdCaseTable->at(i) = new std::vector<UInt4>;

    _FF->CheckAmbiguousFrame();

    UInt4 itrig = 0;
    UInt4 iedb = 0;
    while(true){
      if ( (iedb>(t0_pulse_edb.size()-1)) || (itrig>=(_FF->filterPulseIdList.size())) ) break;
      ckdCaseTable->at(iedb)->clear();

      if ( t0_pulse_edb[iedb]==_FF->filterPulseIdList[itrig] ){
          // std::cout << _MessageTag+"           ..t0b pulse id == trig's one " << std::endl;
          //std::cout << "@@@ itrig=" << itrig << ", _FF->filterCaseTable->at(itrig)->size() ="<< _FF->filterCaseTable->at(itrig)->size() << std::endl;
        _CopyCaseTable( ckdCaseTable->at(iedb), _FF->filterCaseTable->at(itrig) );
        iedb++;
        itrig++;
      }else if ( t0_pulse_edb[iedb] > _FF->filterPulseIdList[itrig] ){
          //std::cout << _MessageTag+"           ..t0b pulse id is larger than trig's one" << std::endl;
        itrig++;
      }else{
          //std::cout << _MessageTag+"           ..t0b pulse id is smaller than trig's one" << std::endl;
        _CopyCaseTable( ckdCaseTable->at(iedb), NULL );
        iedb++;
      }
    }

    if (iedb<t0_pulse_edb.size()){
      for (UInt4 i=iedb;i<t0_pulse_edb.size();i++){
        _CopyCaseTable( ckdCaseTable->at(i), NULL );
      }
    }

    Clear(1);
    _CaseTable = ckdCaseTable;

    /*
    std::cout << _MessageTag+"::CheckCaseTableWithT0Index fin. " << std::endl;

    for (UInt4 i=0;i<_CaseTable->size();i++){
        std::cout << i << ":::";
        for (UInt4 j=0;j<_CaseTable->at(i)->size();j++) std::cout << _CaseTable->at(i)->at(j) << ",";
        std::cout << std::endl;
    }
    std::cout << _MessageTag+"@@@ UtsusemiEventCasesDecoderTemplate::CheckCaseTable fin. " << std::endl;
    */
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
_CopyCaseTable( std::vector<UInt4>* target, std::vector<UInt4>* orig ){
    target->clear();
    if (orig==NULL){
        target->push_back(0);
        target->push_back(0);

    }else{
        for (UInt4 i=0;i<orig->size();i++){
            target->push_back( orig->at(i) );
        }
    }
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
SetParamsForShiftTof( std::vector< std::vector<Double>* > *pixelPositionVect,std::vector<Double> *L1Vect, std::vector<Double> *T0ShiftVect ){
    bool isBad = true;
    if (pixelPositionVect!=NULL){
        if ((L1Vect->size()==1)||(L1Vect->size()==pixelPositionVect->size())){
            if ((T0ShiftVect->size()==1)||(L1Vect->size()==pixelPositionVect->size())){
                _pixelPositionVect = pixelPositionVect;

                _L2OfPixels.clear();
                _L2OfPixels.resize( _pixelPositionVect->size(), 0.0 );

                _L1Vect.clear();
                _L1Vect.resize( _pixelPositionVect->size(), 0.0 );

                _T0ShiftVect.clear();
                _T0ShiftVect.resize( _pixelPositionVect->size(), 0.0 );

                for (UInt4 i=0;i<_pixelPositionVect->size();i++){
                    if (_pixelPositionVect->at(i)!=NULL){
                        if ((i+1)>_L2OfPixels.size()) _L2OfPixels.resize( (i+1), 0.0 );
                        _L2OfPixels[ i ] = sqrt( (_pixelPositionVect->at(i)->at(0))*(_pixelPositionVect->at(i)->at(0))
                                                 +(_pixelPositionVect->at(i)->at(1))*(_pixelPositionVect->at(i)->at(1))
                                                 +(_pixelPositionVect->at(i)->at(2))*(_pixelPositionVect->at(i)->at(2)) );
                    }
                    if (L1Vect->size()==1){
                        _L1Vect[ i ] = L1Vect->at(0);
                    }else{
                        _L1Vect[ i ] = L1Vect->at(i);
                    }
                    if (T0ShiftVect->size()==1){
                        _T0ShiftVect[ i ] = T0ShiftVect->at(0);
                    }else{
                        _T0ShiftVect[ i ] = T0ShiftVect->at(i);
                    }
                }
                isBad = false;
            }
        }
    }

    if (isBad){
        pixelPositionVect=NULL;
        _L2OfPixels.clear();
        _L1Vect.clear();
        _T0ShiftVect.clear();
    }
}

//////////////////////////////////////////////////////////
template <typename T1, typename T2>
std::vector<UInt4> UtsusemiEventCasesDecoderTemplate<T1,T2>::
PutNumOfT0ListInCases( Double tof ){
    std::vector<UInt4> ret;
    //if (_NumOfCases==0) return ret;
    if (_CaseTable==NULL){

        if (_TT!=NULL){
            //std::vector<UInt4> t0v = _TT->putVectorT0Index();
            std::vector<UInt8> t0v = PutT0Index();
            ret.push_back( (UInt4)(t0v.size()) );
        }
        return ret;
    }
    ret.resize( _NumOfCases+1, 0 );
    for (UInt4 frm=0; frm<(_CaseTable->size()); frm++){
        if (_CaseTable->at(frm)!=NULL){
            UInt4 CaseId = GetCaseFromTof( 0, &tof, _CaseTable->at(frm) );
            //if ((CaseId+1)>ret.size()) ret.resize( (CaseId+1), 0 );
            //ret[CaseId]++;
            if (CaseId<ret.size()) ret[CaseId]++;
        }
    }
    return ret;
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
Double UtsusemiEventCasesDecoderTemplate<T1,T2>::
ShiftTofAtSample( Double tof, UInt4 pixelId ){
    Double ret = tof;

    if (_L2OfPixels.size()>pixelId){
        ret = ( tof * _L2OfPixels[pixelId]/(_L1Vect[pixelId]+_L2OfPixels[pixelId]) ) - _T0ShiftVect[pixelId];
    }

    return ret;
}


/////////////////////////////////////////////////////////////
// Functions for Filter
/////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
ReadCaseInfoFile( std::string filepath ){
    Int4 ret=_FF->ReadCaseInfoFile( filepath );
    if (ret<0) {
        _NumOfCases = 1;
    }else{
        _NumOfCases = _FF->PutNumOfCases();
    }
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
ReadCaseEventFiles( UInt4 index, std::vector<std::string> evt_files, std::vector<std::string> t0b_files ){
    std::vector< std::vector<UInt8> > t0b_index_list;
    if (t0b_files.empty()){
    }else{
        for(UInt4 i=0; i<t0b_files.size(); i++){
            ReadT0IndexEventFile( t0b_files[i] );
            t0b_index_list.push_back( PutT0Index() );
        }
    }

    Int4 ret=_FF->ReadCaseEventFiles( index, evt_files, t0b_index_list );
    if (ret<0) {
    }else{
        CheckCaseTableWithT0Index();
    }
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
ReadCaseEvent( UInt4 index, std::vector<std::string> evt_files, std::vector<std::string> t0b_files ){
    if (_FF->isTimeSlicing()){
        MakeTimeSlicingCases( t0b_files );
        return;
    }
    Int4 ret = _FF->ReadCaseEvent( index, evt_files, t0b_files );
    if (ret<0) {
        //UtsusemiError( _MessageTag+"ReadCaseEvent :: _FF->ReadCaseEvent return minus.");
        UtsusemiError("ReadCaseEvent :: _FF->ReadCaseEvent return minus.");
    }else{
        CheckCaseTableWithT0Index();
    }
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
MakeTimeSlicingCases( std::vector<std::string> _t0b_files ){
    Int4 ret = ReadT0IndexEventFile( _t0b_files, 2 );
    //_FF->MakeTimeSlicingCases( _TT->putVectorPulseId(), _TT->putVectorT0Clock() );
    _FF->MakeTimeSlicingCases( _TT->putVectorPulseId(), _TT->putT0SecVector() );

    Clear(1);
    _CaseTable = new std::vector< std::vector<UInt4>* >( (_FF->filterCaseTable->size()), NULL );
    for (UInt4 i=0; i<(_FF->filterCaseTable->size()); i++){
        _CaseTable->at(i) = new std::vector<UInt4>;
        _CopyCaseTable( _CaseTable->at(i), _FF->filterCaseTable->at(i) );
    }
}
//////////////////////////////////////////////////////////
template <typename T1, typename T2>
void UtsusemiEventCasesDecoderTemplate<T1,T2>::
SetTimeSlicing( std::vector<Double> tmp ){
    _FF->SetTimeSlicing( tmp );
    _NumOfCases = _FF->PutNumOfCases();
}
#endif
