#include "UtsusemiReadoutRPMTEventDecoder.hh"
//////////////////////////////////////////////////////////
UtsusemiReadoutRPMTEventDecoder::
UtsusemiReadoutRPMTEventDecoder():
UtsusemiReadoutEventDecoderTemplate<WiringInfoEditorReadout,DetectorInfoEditorReadout2d>()
{
    Initialize();
}
//////////////////////////////////////////////////////////
UtsusemiReadoutRPMTEventDecoder::
~UtsusemiReadoutRPMTEventDecoder(){
    Clear();
}
//////////////////////////////////////////////////////////
void UtsusemiReadoutRPMTEventDecoder::
Initialize(){
    //UtsusemiReadoutEventDecoderTemplate<WiringInfoEditorReadout,UtsusemiDetectorInfoReaderReadout2d>::Initialize();

    _EventSize = (UInt4)8;
    _HeaderT0Event      = (UChar)0xb7;
    _HeaderClockEvent   = (UChar)0x00;
    _HeaderNeutronEvent = (UChar)0xb5;

    _MessageTag="UtsusemiReadoutRPMTEventDecoder >> ";

}

//////////////////////////////////////////////////////////
UInt4 UtsusemiReadoutRPMTEventDecoder::
DecodeEventData( UInt4 daqId, UInt4 modNo, const UChar *data, UInt4 *pixel_id, double *tof, std::vector<Double>* Clock, UInt4 ThNum ){

    UInt4 ret = 0;
    //std::cout << "[inamura 160208] RPMT::DecodeEventData start "<<std::endl;
    // if given event is neutron event;
    if (*data == _HeaderNeutronEvent){
        if (_prevT0Event[_EventSize*ThNum+0]!=0x00){
            // decode neutron event
            *tof = (Double)( (UInt4)( *(data+1) ) +
                             ((UInt4)( *(data+2) ) << 8) +
                             ((UInt4)( *(data+3) ) << 16 ) ); // [micro-sec]

            // frame treatment : minus clock means this frame must be ignored.
            /*
            if ( (_wirInfo->FrameBoundaryInfo.first)>1 ){
                if ( *tof < (_wirInfo->FrameBoundaryInfo.second) ){
                    if (Clock->at( _wirInfo->FrameBoundaryInfo.first -1 )<0) return ret;
                    *tof += Clock->at( _wirInfo->FrameBoundaryInfo.first -1 );
                }else{
                    if (Clock->at( _wirInfo->FrameBoundaryInfo.first -2 )<0) return ret;
                    *tof += Clock->at( _wirInfo->FrameBoundaryInfo.first -2 );
                }
            }
            */

            // position decode
            //UInt4 xpos = (UInt4)( *(data+4)>>4 ) + (UInt4)( *(data+5)<<4 );
            //UInt4 ypos = (UInt4)( *(data+6) ) + (UInt4)( ( *(data+7)&0xF )<<8 );
            UInt4 xpos = (UInt4)( *(data+4)>>7 ) + (UInt4)( *(data+5)<<1 );
            UInt4 ypos = (UInt4)( *(data+6)>>3 ) + (UInt4)( ( *(data+7)&0xF )<<5 );
            //std::cout << "[inamura 160208] xpos,ypos=" << xpos << "," << ypos << std::endl;
            // Pixel ID
            std::vector< std::vector<Int4>* > *pixel_info = NULL;
            try{
                pixel_info = _wirInfo->PixelInfoStore->at(daqId)->at(modNo);
            }catch(...){
                return ret;
            }
            if (pixel_info!=NULL){
                //std::cout << "[inamura 160208] RPMT::pixel_info.size()= "<<pixel_info->size()<<std::endl;
                for (UInt4 i=0; i<(pixel_info->size()); i++){
                    UInt4 xpos_start = pixel_info->at(i)->at(4);
                    UInt4 x_size = pixel_info->at(i)->at(5);
                    UInt4 ypos_start = pixel_info->at(i)->at(6);
                    UInt4 y_size = pixel_info->at(i)->at(7);
                    //std::cout << "[inamura 160208] xpos_start,x_size,ypos_start, y_size= "<< xpos_start <<","<< x_size <<","<< ypos_start <<","<< y_size <<std::endl;
                    if ( (xpos>=xpos_start) && (xpos<(xpos_start+x_size))
                         && (ypos>=ypos_start) && (ypos<(ypos_start+y_size)) ){
                        UInt4 head_pixelId = pixel_info->at(i)->at(2);
                        *pixel_id = head_pixelId + y_size*(xpos-xpos_start) + (ypos-ypos_start);
                        ret = _isNeutronEvent;
                        //std::cout << "[inamura 160208] xpos,ypos,pixel_id="<< xpos << "," << ypos << "," << pixel_id << std::endl;

                        // offset tof
                        if(_wirInfo->TofBinInfoList[(*pixel_id)]!=NULL)
                            *tof += _wirInfo->TofBinInfoList[(*pixel_id)]->at(1);
                        if (_isSetFrameBoundary){
                            UInt4 fno = _wirDict->FrameBoundaryInfoList[(*pixel_id)]->first;
                            Double boundary = _wirDict->FrameBoundaryInfoList[(*pixel_id)]->second;
                            if ( *tof < boundary){
                                if (Clock->at( fno -1 )<0) return ret;
                                *tof += Clock->at( fno -1 );
                            }else if ( *tof < (boundary+_MicroSec_Par_Frame) ){
                                if (Clock->at( fno -2 )<0) return ret;
                                *tof += Clock->at( fno -2 );
                            }
                        }
                        break;
                    }
                }
            }else{
                //std::cout << "[inamura 160208] pixel_info=NULL "<< std::endl;
            }
        }else{
            //std::cout << "[inamura160208] _prevT0Event[_EventSize*ThNum+0]!=0x00" << std::endl;
        }
    }else if (*data == _HeaderT0Event){
        //std::cout << "[inamura 160208] this is T0Event" << std::endl;
        for (UInt4 i=0;i<_EventSize;i++) (*(_prevT0Event+(_EventSize*ThNum)+i))=(*(data+i));
        ret = _isT0Event;
    }else if (*data == _HeaderClockEvent){
        //std::cout << "[inamura 160208] this is ClockEvent" << std::endl;
        ret = _isClockEvent;
    }else{
        std::cout << "[inamura 160208] this is unknown event" << std::endl;
    }
    return ret;

}
//////////////////////////////////////////////////////////
void UtsusemiReadoutRPMTEventDecoder::
CalcPixelPosition(){
    Clear();
    if (_wirInfo->PixelInfoStore->empty()) {
        UtsusemiError(_MessageTag+" not ready wiring info.");
        return;
    }

    for (UInt4 daq=0; daq<_wirInfo->PixelInfoStore->size();daq++){

        if (_wirInfo->PixelInfoStore->at(daq)==NULL) continue;

        for (UInt4 mod=0; mod<_wirInfo->PixelInfoStore->at(daq)->size(); mod++){

            if (_wirInfo->PixelInfoStore->at(daq)->at(mod)==NULL) continue;

            for (UInt4 det=0; det<_wirInfo->PixelInfoStore->at(daq)->at(mod)->size(); det++){
                if (_wirInfo->PixelInfoStore->at(daq)->at(mod)->at(det)!=NULL){
                    std::vector<Int4>* pic = _wirInfo->PixelInfoStore->at(daq)->at(mod)->at(det);
                    UInt4 det_id = pic->at(1);
                    UInt4 head_px = pic->at(2);
                    UInt4 xpos_st = pic->at(4);
                    UInt4 xpos_size = pic->at(5);
                    UInt4 ypos_st = pic->at(6);
                    UInt4 ypos_size = pic->at(7);

                    if (_pixelPositionVect.size()<(head_px + (xpos_size*ypos_size) ) ){
                        _pixelPositionVect.resize( (head_px + (xpos_size*ypos_size) ), NULL );
                        _pixelSolidAngleVect.resize( (head_px + (xpos_size*ypos_size) ), 0.0 );
                    }

                    std::vector< std::vector<Double>* > pos_vec;
                    pos_vec.resize( (xpos_size*ypos_size), NULL );
                    for (UInt4 i=0; i<(xpos_size*ypos_size); i++)
                        pos_vec[i] = new std::vector<Double> (3,0.0);

                    if ( _detInfo->CalcReadout2dPixelPosition( det_id, xpos_size, ypos_size, &pos_vec ) ){
                        std::vector<Double> tmp_solid_angles = _detInfo->CalcReadout2dPixelSolidAngle( det_id, xpos_size, ypos_size, &pos_vec );
                        for (UInt4 i=0; i<(xpos_size*ypos_size); i++){
                            _pixelPositionVect[head_px+i] = pos_vec[i];
                            _pixelSolidAngleVect[head_px+i] = tmp_solid_angles[i];
                        }
                    }else{
                        for (UInt4 i=0; i<(xpos_size*ypos_size); i++)
                            delete pos_vec[i];
                    }
                }
            }
        }
    }

}
