#include "UtsusemiEventDataCreator.hh"
//////////////////////////////////////////////////////////
EventDataCreator::EventDataCreator(){
    _st = new StringTools();
    _daqID = 0;
    _modNo = 0;
}
//////////////////////////////////////////////////////////
EventDataCreator::~EventDataCreator(){
    std::cout << "destructor"<<std::endl;
    delete _st;
}
//////////////////////////////////////////////////////////
std::string EventDataCreator::encodePidClockEvent(int pid, double clock ){
    // make T0 pulseID event
    //std::cout << "T0TreatTools : PID in encoding = " << pid << std::endl;
    unsigned char event[16];
    event[0]=0x5b;
    event[1]=0x00;
    event[2]=0x00;
    event[3] = 0x00;
    event[4]=(char)( (pid>>24)&0xff );
    event[5]=(char)( (pid>>16)&0xff );
    event[6]=(char)( (pid>>8)&0xff );
    event[7]=(char)( pid&0xff );

    // make Instrument Clock event
    event[8]=0x5c;
    int sec = (int)( floor(clock) );
    //unsigned long sub = (unsigned long)( floor( (clock - sec)*32768. ) );
    int sub = (int)( floor( (clock - floor(clock))*32768. ) );

    double subsecd = (double)sub/32768.;
    int subm = (int)( floor( (clock - floor(clock) - subsecd )*40000000. + 0.5 ) );
    event[9]=(char)( ((sec)>>22)&0xff );
    event[10]=(char)( ((sec)>>14)&0xff );
    event[11]=(char)( ((sec)>>6)&0xff );
    event[12]=(char)( (((sec)&0x3f)<<2) + (((sub)&0x7fff)>>13) );
    event[13]=(char)( ((sub)&0x1fff)>>5 );
    event[14]=(char)( (((sub)&0x1f)<<3 ) + (((subm)&0x700)>>8) );
    event[15]=(char)( (subm)&0xff );

    std::string ret(event, std::end(event));
    return ret;
}
//////////////////////////////////////////////////////////
std::string EventDataCreator::encodeNeutronEvent(double tof,int mod,int psd){
    int tof_clock = (int)(tof*40.0);
    int ph = 1024;
    unsigned char event[8];
    event[0]=0x5a;
    event[1]=(char)( tof_clock>>16);
    event[2]=(char)( (tof_clock>>8)&(0xff) );
    event[3]=(char)( tof_clock&(0xff) );
    event[4]=(char)( (mod&(0x1f)<<3) + (psd&(0x7)) );
    event[5]=(char)( ph>>4 );
    event[6]=(char)( (ph&(0xf)<<4) + (ph>>8) );
    event[7]=(char)( ph&(0xff) );
    std::string ret(event, std::end(event));
    return ret;
}
//////////////////////////////////////////////////////////
std::string EventDataCreator::encodeTrignetEvent( double tof, int sid1, int sid2, int val1, int val2 ){
    unsigned char event[8];
    int tof_clock = (int)(tof*40.0);
    event[0]=0x54;
    event[1]=(char)( tof_clock>>16);
    event[2]=(char)( (tof_clock>>8)&(0xff) );
    event[3]=(char)( tof_clock&(0xff) );
    event[4]=(char)( ((sid1&(0x1f))<<3) + (sid2&(0x7)) );
    if (sid2==1){
        event[5]=0x00;
        event[6]=0x00;
        event[7]=(char) val1;
    }else if ((sid2==2)||(sid2==3)){
        event[5]=(char)( val1>>16 );
        event[6]=(char)( (val1>>8)&(0xff) );
        event[7]=(char)( val1&(0xff) );
    }else if (sid2==3){
        event[5]=(char)( val1>>4 );
        event[6]=(char)( (val1&(0xf)<<4) + (val2>>8) );
        event[7]=(char)( val2&(0xff) );
    }else{
        event[5]=0x00;
        event[6]=0x00;
        event[7]=0x00;
    }
    std::string ret(event, std::end(event));
    return ret;
}

//////////////////////////////////////////////////////////
bool EventDataCreator::output( std::string path_in, std::string path_n, std::string path_t ){
    FILE *fn;
    FILE *ft;
    if(NULL==(fn= fopen(path_n.c_str(),"wb"))){
        std::cout << "output >> Can't open " << path_n << "." << std::endl;
        return false;
    }
    if(NULL==(ft= fopen(path_t.c_str(),"wb"))){
        std::cout << "output >> Can't open " << path_t << "." << std::endl;
        return false;
    }
    std::ifstream fin;
    fin.open(path_in, std::ios::in);
    std::string tmp;
    UInt4 pulseId=0;
    Double clock = 0.0;
    Double frame_clock = 0.04;
    UInt4 eType = 0; // 0:T0, 1:Neunet, 2:TrigNET
    while( getline(fin, tmp) ){
        std::string evt = "";

        if (tmp.find("k")==0){
            std::cout << "evnet= k:"<<tmp<<std::endl;
            std::vector<std::string> tmp2 = _st->SplitString( tmp, ":" );
            if (tmp2.size()==3){
                pulseId = _st->StringToUInt4( tmp2[1] );
                clock = _st->StringToUInt4( tmp2[2] );
            }
            evt = encodePidClockEvent( pulseId, clock );
            eType = 0;
            pulseId++;
            //clock += 0.04;
            clock = frame_clock*(Double)(pulseId);
        }else if (tmp.find("n")==0){
            std::cout << "evnet=n :"<<tmp<<std::endl;
            std::vector<std::string> tmp2 = _st->SplitString( tmp, ":" );
            if (tmp2.size()==2){
                Double tof = _st->StringToDouble( tmp2[1] );
                evt = encodeNeutronEvent( tof, _daqID, _modNo );
                eType = 1;
            }
        }else if (tmp.find("t")==0){
            std::cout << "event= t: "<<tmp<<std::endl;
            UInt4 sid2 = 0;
            std::vector<std::string> tmp2 = _st->SplitString( tmp, ":" );
            if (tmp2.size()==4){
                Double tof = _st->StringToDouble( tmp2[1] );
                if (tmp2[2]=="dio") sid2=1;
                if (tmp2[2]=="adc1") sid2=2;
                if (tmp2[2]=="adc2") sid2=3;
                if (tmp2[2]=="adc") sid2=4;
                if (sid2==1){
                    if (tmp2[3].size()==2){
                        std::string t(tmp2[3]);
                        UInt4 sid1 = _st->StringToUInt4(t.substr(0,1) )-1;
                        UInt4 c = 0;
                        if (t.substr(1,1)=="u"){
                            c = (1<<(sid1));
                        }else{
                            sid1 += 16;
                            c = 0;
                        }
                        evt = encodeTrignetEvent(tof, sid1, sid2, c );
                        eType = 2;
                    }
                }
            }
        }
        if (evt!=""){
            if (eType==0) {
                std::fwrite( evt.c_str(), 1, 16, fn );
                std::fwrite( evt.c_str(), 1, 16, ft );
            }else if (eType==1)
                std::fwrite( evt.c_str(), 1, 8, fn );
            else std::fwrite( evt.c_str(), 1, 8, ft );
        }
    }
    std::cout << std::endl;
    std::cout << "Clocks= "<< clock <<std::endl;
    std::cout << "PulseId="<<pulseId << std::endl;

    fin.close();
    fclose(fn);
    fclose(ft);

    return true;
}
