#include "UtsusemiRedisPubSubEventContainer.hh"
//////////////////////////////////////////////////////////
UtsusemiRedisPubSubEventContainer::
UtsusemiRedisPubSubEventContainer(){
    _Reader = NULL;
    _MessageTag="UtsusemiRedisPubSubEventContainer::";
    PulseIdOfCases = NULL;
    CaseList = NULL;
    MeasClockSliced.first = -1.0;
    MeasClockSliced.second= -1.0;
    CurrentClockSliced.first = -1.0;
    CurrentClockSliced.second= -1.0;
    _isSubscribed=false;
    _ByteOfEvent = 8;

}
//////////////////////////////////////////////////////////
UtsusemiRedisPubSubEventContainer::
~UtsusemiRedisPubSubEventContainer(){
    if (_Reader!=NULL) delete _Reader;
}
//////////////////////////////////////////////////////////
bool UtsusemiRedisPubSubEventContainer::
Initialize( std::string instCode, UInt4 runNo, UInt4 daqId, UInt4 modNo, std::string host, UInt4 port, std::string date ){
    if (_Reader!=NULL) delete _Reader;
    _isSubscribed=false;
    _Reader = new UtsusemiRedisPubSubEventReader();
    if (_Reader->Subscribe( instCode, runNo, daqId, modNo, host, port, date )){
    }else{
        UtsusemiError(_MessageTag+"Initialize : Subscribe failed" );
        return false;
    }
    PulseIdOfCases = NULL;
    CaseList = NULL;
    MeasClockSliced.first = -1.0;
    MeasClockSliced.second= -1.0;
    CurrentClockSliced.first = -1.0;
    CurrentClockSliced.second= -1.0;
    _isSubscribed=true;
    isDebug=false;
    return true;
}
//////////////////////////////////////////////////////////
bool UtsusemiRedisPubSubEventContainer::
Reset(){
    if (_Reader!=NULL){
        if (_Reader->Unsubscribe()){
            delete _Reader;
            _Reader=NULL;
        }else{
            return false;
        }
    }
    LeftPulseIdTable.clear();
    LeftT0IndexTable.clear();
    LeftDiffClockTable.clear();
    LeftEdbEvents.clear();

    PulseIdOfCases = NULL;
    CaseList = NULL;

    MeasClockSliced.first = -1.0;
    MeasClockSliced.second= -1.0;
    CurrentClockSliced.first = -1.0;
    CurrentClockSliced.second= -1.0;
    _isSubscribed=false;
    return true;
}
//////////////////////////////////////////////////////////
bool UtsusemiRedisPubSubEventContainer::
Update(){
    UInt4 left_pid_num = LeftPulseIdTable.size();
    UInt4 left_clk_num = LeftDiffClockTable.size();
    UInt4 left_ind_num = LeftT0IndexTable.size();
    UInt4 left_events_num = LeftEdbEvents.size();

    std::vector<UInt8> retPid;
    std::vector<Double> retClk;
    std::vector<UInt8> retInd;

    UChar* buf = new UChar [UtsusemiRedisPubSubEventReader::REDIS_PUBSUB_BUF_SIZE];
    UInt4 num_of_buf=0;
    _Reader->isDebug = isDebug;
    if (_Reader->Read( buf, &num_of_buf, &retPid, &retClk, &retInd )){
        //std::cout << "Container::Update() Read return num_of_buf = "<<num_of_buf<<std::endl;
        UtsusemiMessage( _MessageTag+"Put >> Read succeeded." );
    }else{
        UtsusemiError( _MessageTag+"Put >> Read fails." );
        delete [] buf;
        return false;
    }


    /*
    std::cout << "### Container::Update ------------------" << std::endl;
    std::cout << "num_of_buf="<<num_of_buf<<std::endl;
    std::cout << "retPid size="<< retPid.size() << std::endl;;
    for (UInt4 i=0; i<retPid.size();i++) std::cout << retPid[i]<<",";
    std::cout << std::endl;
    std::cout << "retClk size= "<< retClk.size() << std::endl;;
    for (UInt4 i=0; i<retClk.size();i++) std::cout << retClk[i]<<",";
    std::cout << std::endl;
    std::cout << "retInd size=" << retInd.size() << std::endl;;
    for (UInt4 i=0; i<retInd.size();i++) std::cout << retInd[i]<<",";
    std::cout << std::endl;
    */

    if (MeasClockSliced.first<0.0) MeasClockSliced.first=_Reader->PutFirstClock();
    MeasClockSliced.second = _Reader->PutLastClock();
    CurrentClockSliced.first = CurrentClockSliced.second;
    CurrentClockSliced.second = _Reader->PutLastClock();

    UInt4 num_of_retPid = retPid.size();
    LeftPulseIdTable.resize( left_pid_num + num_of_retPid );
    LeftDiffClockTable.resize( left_clk_num + num_of_retPid );
    LeftT0IndexTable.resize( left_ind_num + num_of_retPid );
    LeftEdbEvents.resize( left_events_num + num_of_buf );

    copy( retPid.begin(), retPid.end(), LeftPulseIdTable.begin()+left_pid_num );
    copy( retClk.begin(), retClk.end(), LeftDiffClockTable.begin()+left_clk_num );
    copy( retInd.begin(), retInd.end(), LeftT0IndexTable.begin()+left_ind_num );
    for (UInt4 i=0; i<num_of_buf; i++)
        LeftEdbEvents[left_events_num+i] = buf[i];

    delete [] buf;
    //std::cout << "UtsusemiRedisPubSubEventContainer::Update() LeftEdbEvents.size()="<<LeftEdbEvents.size()<<std::endl;
    return true;

}
//////////////////////////////////////////////////////////
bool UtsusemiRedisPubSubEventContainer::
SetReference( std::vector<UInt8> *pulseId, std::vector< std::vector<UInt4>* > *caseList ){
    PulseIdOfCases = pulseId;
    CaseList = caseList;
    if (pulseId==NULL) return false;
    else if (caseList!=NULL){
        if ((PulseIdOfCases->size())!=(CaseList->size())) return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
bool UtsusemiRedisPubSubEventContainer::
Put( UChar *data, UInt4 *num_of_data, std::vector<UInt8> *t0PulseId, std::vector<Double> *t0DiffClock, std::vector<UInt8> *t0Index, std::vector< std::vector<UInt4>* > *caseList ){
    UInt4 left_pid_num = LeftPulseIdTable.size();
    UInt4 left_clk_num = LeftDiffClockTable.size();
    UInt4 left_ind_num = LeftT0IndexTable.size();
    UInt4 left_events_num = LeftEdbEvents.size();

    if (left_pid_num==0){
        UtsusemiError( _MessageTag+"Put >> LeftXXX vector is empty, nothing to do");
        return false;
    }

    t0PulseId->clear();
    t0DiffClock->clear();
    t0Index->clear();

    if (left_events_num>(*num_of_data)){
        UtsusemiError( _MessageTag+"Put >> given data size is too small" );
        std::cout << "left_events_num=" << left_events_num << std::endl;
        std::cout << "num_of_data=" << (*num_of_data) << std::endl;
        return false;
    }

    if ((PulseIdOfCases == NULL)||(PulseIdOfCases->empty())||(caseList==NULL)){
        for (UInt4 i=0; i<left_events_num; i++) data[i]=LeftEdbEvents[i];
        (*num_of_data) = left_events_num;

        t0PulseId->resize( left_pid_num, 0 );
        t0DiffClock->resize( left_clk_num, 0. );
        t0Index->resize( left_ind_num, 0 );

        copy( LeftPulseIdTable.begin(), LeftPulseIdTable.end(), t0PulseId->begin() );
        copy( LeftDiffClockTable.begin(), LeftDiffClockTable.end(), t0DiffClock->begin() );
        //copy( LeftT0IndexTable.begin(), LeftT0IndexTable.end(), t0Index->begin() );
        if (left_ind_num>0)
            for (UInt4 i=0; i<(left_ind_num); i++)
                t0Index->at(i) = LeftT0IndexTable[i]-LeftT0IndexTable[0];

        LeftPulseIdTable.clear();
        LeftT0IndexTable.clear();
        LeftDiffClockTable.clear();
        LeftEdbEvents.clear();
    }else{
        /*
        std::cout << "------------------------" << std::endl << "LeftPulseIdTable = ";
        for (UInt4 i=0; i<left_pid_num; i++) std::cout << LeftPulseIdTable[i] << ",";
        std::cout << std::endl << "LeftT0IndexTable = ";
        for (UInt4 i=0; i<left_ind_num; i++) std::cout << LeftT0IndexTable[i] << ",";
        std::cout << std::endl;
        */

        for (UInt4 i=0; i<caseList->size(); i++)
            if (caseList->at(i)!=NULL)
                delete caseList->at(i);

        UInt4 i0 = 1; // Index of PulseId for event data
        UInt4 i1 = 0; // Index of PulseId for trignet
        UInt4 i2 = 0; // EDB
        bool isMissMatch = false;
        while(true){

            if (LeftPulseIdTable[i0]>(PulseIdOfCases->at(i1)+1)){
                while( LeftPulseIdTable[i0]!=(PulseIdOfCases->at(i1)+1) ){
                    i1++;
                    if (i1==(PulseIdOfCases->size())){
                        UtsusemiError(_MessageTag+"Put >> PulseIdOfCases is too short." );
                        isMissMatch=true;
                        break;
                    }
                    if ( LeftPulseIdTable[i0]<(PulseIdOfCases->at(i1)+1) ){
                        t0PulseId->push_back( LeftPulseIdTable[i0] );
                        t0DiffClock->push_back( LeftDiffClockTable[i0] );
                        for (UInt4 i=0; i<((LeftT0IndexTable[i0]-LeftT0IndexTable[i0-1])*_ByteOfEvent); i++) data[i2*_ByteOfEvent+i]=LeftEdbEvents[i2*_ByteOfEvent+i];
                        i2 = LeftT0IndexTable[i0]-LeftT0IndexTable[0];
                        t0Index->push_back(i2);
                        if (caseList!=NULL)
                            caseList->push_back( NULL );
                        break;
                    }
                }
            }
            if (isMissMatch) return true;

            if ( LeftPulseIdTable[i0]<(PulseIdOfCases->at(i1)+1) ){
                while( LeftPulseIdTable[i0]!=(PulseIdOfCases->at(i1)+1) ){
                    t0PulseId->push_back( LeftPulseIdTable[i0] );
                    t0DiffClock->push_back( LeftDiffClockTable[i0] );
                    for (UInt4 i=0; i<((LeftT0IndexTable[i0]-LeftT0IndexTable[i0-1])*_ByteOfEvent); i++) data[i2*_ByteOfEvent+i]=LeftEdbEvents[i2*_ByteOfEvent+i];
                    i2 = LeftT0IndexTable[i0]-LeftT0IndexTable[0];
                    t0Index->push_back(i2);
                    if (CaseList->at(i1)!=NULL){
                        std::vector<UInt4>* a_case = new std::vector<UInt4>();
                        for (UInt4 i=0; i<(CaseList->at(i1)->size()); i++)
                            a_case->push_back( CaseList->at(i1)->at(i));
                        caseList->push_back( a_case );
                    }

                    i0++;
                    if (i0==(LeftPulseIdTable.size())){
                        isMissMatch=true;
                        break;
                    }

                }
            }
            if (isMissMatch) return true;

            t0PulseId->push_back( LeftPulseIdTable[i0] );
            t0DiffClock->push_back( LeftDiffClockTable[i0] );
            for (UInt4 i=0; i<((LeftT0IndexTable[i0]-LeftT0IndexTable[i0-1])*_ByteOfEvent); i++)
                data[i2*_ByteOfEvent+i]=LeftEdbEvents[i2*_ByteOfEvent+i];
            i2 = LeftT0IndexTable[i0-1]-LeftT0IndexTable[0];
            t0Index->push_back(i2);
            std::vector<UInt4>* a_case = new std::vector<UInt4>();
            for (UInt4 i=0; i<( CaseList->at(i1)->size() ); i++)
                a_case->push_back( CaseList->at(i1)->at(i) );
            caseList->push_back(a_case);

            i0++;
            i1++;

            if ((i0==(LeftPulseIdTable.size()))||(i1==(PulseIdOfCases->size()))) break;

        }
        if (i0==(LeftPulseIdTable.size())){
            if (left_pid_num>1){
                std::vector<UInt4> tmp(2);
                copy(LeftPulseIdTable.end()-2,LeftPulseIdTable.end(),tmp.begin());
                LeftPulseIdTable.clear();
                LeftPulseIdTable.push_back(tmp[0]);
                LeftPulseIdTable.push_back(tmp[1]);
            }
            if (left_ind_num>1){
                UInt4 st = (t0Index->back())*_ByteOfEvent;
                UInt4 en = LeftEdbEvents.size();
                std::vector<Char> tmp1( en-st );
                copy( LeftEdbEvents.begin()+st, LeftEdbEvents.end(), tmp1.begin() );
                LeftEdbEvents.clear();
                LeftEdbEvents.resize( tmp1.size() );
                copy( tmp1.begin(), tmp1.end(), LeftEdbEvents.begin() );

                std::vector<UInt8> tmp(2);
                copy(LeftT0IndexTable.end()-2,LeftT0IndexTable.end(),tmp.begin());
                LeftT0IndexTable.clear();
                LeftT0IndexTable.push_back( tmp[0] );
                LeftT0IndexTable.push_back( tmp[1] );

            }
            if (left_clk_num>1){
                std::vector<Double> tmp(2);
                copy(LeftDiffClockTable.end()-2,LeftDiffClockTable.end(), tmp.begin());
                LeftDiffClockTable.clear();
                LeftDiffClockTable.push_back(tmp[0]);
                LeftDiffClockTable.push_back(tmp[1]);
            }else
                LeftDiffClockTable.clear();

        }else if (i1==(PulseIdOfCases->size())){
            std::vector<UInt8> tmp_LeftPulseIdTable(left_pid_num-i0+1, 0);
            std::vector<UInt4> tmp_LeftT0IndexTable(left_ind_num-i0+1, 0);
            std::vector<Double> tmp_LeftDiffClockTable(left_clk_num-i0+1, 00.0);
            std::vector<Char>  tmp_LeftEdbEvents(left_events_num-i2);

            copy( LeftPulseIdTable.begin()+i0-2, LeftPulseIdTable.end(), tmp_LeftPulseIdTable.begin());
            copy( LeftT0IndexTable.begin()+i0-2, LeftT0IndexTable.end(), tmp_LeftT0IndexTable.begin());
            copy( LeftDiffClockTable.begin()+i0-2, LeftDiffClockTable.end(), tmp_LeftDiffClockTable.begin());
            copy( LeftEdbEvents.begin()+i0-2, LeftEdbEvents.end(), tmp_LeftEdbEvents.begin());

            LeftPulseIdTable.clear();
            LeftT0IndexTable.clear();
            LeftDiffClockTable.clear();
            LeftEdbEvents.clear();

            LeftPulseIdTable.resize(tmp_LeftPulseIdTable.size());
            LeftT0IndexTable.resize(tmp_LeftT0IndexTable.size());
            LeftDiffClockTable.resize(tmp_LeftDiffClockTable.size());
            LeftEdbEvents.resize(tmp_LeftEdbEvents.size());

            copy( tmp_LeftPulseIdTable.begin(), tmp_LeftPulseIdTable.end(), LeftPulseIdTable.begin());
            copy( tmp_LeftT0IndexTable.begin(), tmp_LeftT0IndexTable.end(), LeftT0IndexTable.begin());
            copy( tmp_LeftDiffClockTable.begin(), tmp_LeftDiffClockTable.end(), LeftDiffClockTable.begin());
            copy( tmp_LeftEdbEvents.begin(), tmp_LeftEdbEvents.end(), LeftEdbEvents.begin());

            tmp_LeftPulseIdTable.clear();
            tmp_LeftT0IndexTable.clear();
            tmp_LeftDiffClockTable.clear();
            tmp_LeftEdbEvents.clear();
        }
    }

    PulseIdOfCases = NULL;
    CaseList = NULL;
    return true;
}

