#include "UtsusemiTrignetEventDecoderBase.hh"

//////////////////////////////////////////////////////////
UtsusemiTrignetEventDecoderBase::
UtsusemiTrignetEventDecoderBase(){
    Initialize();
}
//////////////////////////////////////////////////////////
UtsusemiTrignetEventDecoderBase::
~UtsusemiTrignetEventDecoderBase(){
    delete _UTD;
    delete stools;
}

//////////////////////////////////////////////////////////
void UtsusemiTrignetEventDecoderBase::
Initialize(){
    headerTrigEvent = (UChar)0x54;
    _UTD = new UtsusemiTrignetDictionary();

    stools = new StringTools();
    _MessageTag="UtsusemiTrignetEventDecoderBase >> ";

}

//////////////////////////////////////////////////////////
bool UtsusemiTrignetEventDecoderBase::
isTrigEvent( UChar buf ){
    if (buf == headerTrigEvent){
        return true;
    }else{
        return false;
    }
}

/////////////////////////////////////////////////////////
bool UtsusemiTrignetEventDecoderBase::
isHeaderT0( UChar aByte ){
    if (aByte==0x5b){
        return true;
    }else{
        return false;
    }
}
/////////////////////////////////////////////////////////
bool UtsusemiTrignetEventDecoderBase::
isHeaderClock( UChar aByte ){
    if (aByte==0x5c){
        return true;
    }else{
        return false;
    }
}
/////////////////////////////////////////////////////////
UInt8 UtsusemiTrignetEventDecoderBase::
_decodePulseIdEvent(UChar buf[]){
    UInt8 pid;
    pid=((UInt8)buf[3]<<32)
        +((UInt4)buf[4]<<24)
        +((UInt4)buf[5]<<16)
        +((UInt4)buf[6]<<8)
        +(UInt4)buf[7];

    return pid;
}
/////////////////////////////////////////////////////////
Double UtsusemiTrignetEventDecoderBase::
_decodeInstClockEvent(UChar buf[]){
    UInt4 sec;
    Double subsec;
    Double submicrosec;
    sec=((UInt4)buf[1]<<22)
        +((UInt4)buf[2]<<14)
        +((UInt4)buf[3]<<6)
        +((UInt4)buf[4]>>2);

    subsec=(Double)(
        ((UInt4)(buf[4]&3)<<13)
        +((UInt4)buf[5]<<5)
        +((UInt4)buf[6]>>3)
        )/32768.;
    submicrosec=(Double)(
        ((UInt4)(buf[6]&7)<<8)
        +(UInt4)buf[7]
        )*MLF_NEUNET_CLOCK_SEC;

    return ((Double)sec + subsec + submicrosec);
}
/////////////////////////////////////////////////////////
UInt8 UtsusemiTrignetEventDecoderBase::
decodePulseIdEvent(const UChar *buf){
    UInt8 pid;
    pid=((UInt8)(*(buf+3))<<32)
        +((UInt4)(*(buf+4))<<24)
        +((UInt4)(*(buf+5))<<16)
        +((UInt4)(*(buf+6))<<8)
        +(UInt4)(*(buf+7));

    return pid;
}
//////////////////////////////////////////////////////////
Double UtsusemiTrignetEventDecoderBase::
decodeInstClockEvent(const UChar *buf){
    UInt4 sec;
    Double subsec;
    Double submicrosec;
    sec=((UInt4)(*(buf+1))<<22)
        +((UInt4)(*(buf+2))<<14)
        +((UInt4)(*(buf+3))<<6)
        +((UInt4)(*(buf+4))>>2);
    subsec=(Double)(
        ((UInt4)((*(buf+4))&3)<<13)
        +(UInt4)((*(buf+5))<<5)
        +(UInt4)((*(buf+6))>>3)
        )/32768.;
    submicrosec=(Double)(
        ((UInt4)((*(buf+6))&7)<<8)
        +(UInt4)(*(buf+7))
        )*MLF_NEUNET_CLOCK_SEC;
    return ((Double)sec + subsec + submicrosec);
}

//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetEventDecoderBase::
DecodeTrigEvent( const UChar *data, std::vector<UInt4> *values, UInt4 index){
    if (*(data)!=headerTrigEvent){
        return -1;
    }
    if (values->size()!=12){
        return -2;
    }else{
        for (UInt4 i=0;i<10;i++) values->at(i)=0;
    }

    UInt4 tof = (UInt4)( Double( (UInt4)( *(data+1)<<16 )
                            + (UInt4)( *(data+2)<<8 )
                                 + (UInt4)( *(data+3) ) )); //[clock(25nano-sec)]

    values->at(0) = tof;
    UInt4 SID1 = (UInt4)( *(data+4)>>3 );
    if (((SID1>7)&&(SID1<14))||((SID1>23)&&(SID1<31))){
        return -1;
    }
    values->at(1) = index;
    values->at(2) = SID1;

    UInt4 SID2 = (UInt4)( (*(data+4))&0x7 );
    values->at(3) = SID2;

    //If Type is DIO
    if (SID2==1){
        //for (UInt4 i=0;i<8;i++) values->at(i+4) = ((*(data+7))&((UInt4)pow(2,i))>>i);
        for (UInt4 i=0;i<8;i++) values->at(i+4) = ( ( (*(data+7))&((UInt4)pow(2.0,(Int4)i)) )>>i);
    }else if ((SID2==2)||(SID2==3)){
        values->at(4) = (UInt4)(*(data+5)<<16) + (UInt4)(*(data+6)<<8) + (UInt4)(*(data+7));
    }else if (SID2==4){
        values->at(4) = (UInt4)(*(data+5)<<3)+(UInt4)((*(data+6)&0xf0)>>3);
        values->at(5) = (UInt4)((*(data+6)&0x7)<<8)+(UInt4)(*(data+7));
    }
    return 0;
}

//////////////////////////////////////////////////////////
std::vector<std::string> UtsusemiTrignetEventDecoderBase::
DumpTrigEvent( std::vector<UInt4> evt, bool debug ){
    //std::cout << "String=" << evt << std::endl;

    std::vector<std::string> ret;
    ret.clear();

    if (evt[0]!=headerTrigEvent){
        return ret;
    }

    int* cc;
    cc = new int [8];
    //for (UInt4 i=0;i<8;i++) cc[i]=(UChar)(evt[i].c_str());
    if (debug) std::cout << "cc=";
    for (UInt4 i=0;i<8;i++){
        *(cc+i) = evt[i];
        if (debug) std::cout << (UInt4)(*(cc+i)) << ",";
    }
    if (debug) std::cout << std::endl;
    Double tof = Double( (UInt4)( *(cc+1)<<16 )
                         + (UInt4)( *(cc+2)<<8 )
                         + (UInt4)( *(cc+3) ) );
    tof = tof*MLF_NEUNET_CLOCK_MICROSEC;;

    UInt4 SID1 = (UInt4)( (cc[4]&0x78)>>3 );
    if (((SID1>7)&&(SID1<14))||((SID1>23)&&(SID1<31))){
        return ret;
    }

    UInt4 SID2 = (UInt4)( cc[4]&0x7 );

    ret.push_back( _UTD->PutTrigString(SID1) );
    ret.push_back( stools->DoubleToString( tof ) );
    ret.push_back( _UTD->PutTypeString(SID2) );
    if (debug) {
        std::cout << "tof=" << tof <<","<< (UInt4)(*(cc+1)<<16) << "," << (UInt4)( *(cc+2)<<8 ) << "," << (UInt4)( *(cc+3) )<< std::endl;
        std::cout << "SID1=" << SID1 << std::endl;
        std::cout << "SID2=" << SID2 << std::endl;
        std::cout << "Type=" << ret[0] << "= ";
    }

    char moji[50];

    if (SID2==1){
        std::vector<UInt4> tmp;
        tmp.clear();
        for (UInt4 i=0;i<8;i++){
            tmp.push_back( ( (*(cc+7))&(UInt4)(pow(2.0,(Int4)i)) )>>i );
            if (debug) std::cout << tmp[i] << ":";
        }
        std::snprintf(moji,sizeof(moji),"%1d:%1d:%1d:%1d:%1d:%1d:%1d:%1d\n",tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5],tmp[6],tmp[7]);
        if (debug) std::cout << moji << std::endl;
        std::string moji_s( moji );
        ret.push_back( moji_s );

    }else if ((SID2==2)||(SID2==3)){
        UInt4 a_value = (UInt4)(*(cc+5)<<16) + (UInt4)(*(cc+6)<<8) + (UInt4)(*(cc+7));
        UInt4 a1 = (UInt4)((*(cc+5)) << 16);
        UInt4 a2 = (UInt4)((*(cc+6)) << 8);
        UInt4 a3 = (UInt4)(*(cc+7));
        ret.push_back( stools->UInt4ToString( a_value ) );
        if (debug) std::cout << a_value << "," << a1 <<","<< a2 <<","<< a3  << std::endl;


    }else if (SID2==4){
        Int4 f1_val = (Int4)(*(cc+5)<<3)+(Int4)((*(cc+6)&0xf0)>>3);
        Int4 f2_val = (Int4)((*(cc+6)&0x7)<<8)+(Int4)(*(cc+7));
        std::snprintf(moji,sizeof(moji),"%d,%d",f1_val,f2_val);
        if (debug) std::cout << "F1=" << f1_val << ", F2=" << f2_val << std::endl;
        std::string moji_s(moji);
        ret.push_back( moji_s );
    }else{
        if (debug) std::cout << "SID2=" << SID2 << std::endl;
        ret.push_back( "-1" );
    }
    delete [] cc;
    return ret;

}
