#include "UtsusemiEventDataConverterRPMT.hh"
//////////////////////////////////////////////////////////
UtsusemiEventDataConverterRPMT::
UtsusemiEventDataConverterRPMT(){
    Initialize();
}

//////////////////////////////////////////////////////////
UtsusemiEventDataConverterRPMT::
~UtsusemiEventDataConverterRPMT(){
    delete stools;
}

//////////////////////////////////////////////////////////
void UtsusemiEventDataConverterRPMT::
Initialize(){
    _MessageTag = "UtsusemiEventDataConverterRPMT >> ";
    stools = new StringTools();
#ifdef MULTH
    //_NumOfMulTh = std::min( MULTH, std::min( omp_get_max_threads(), omp_get_num_procs() ) );
    _NumOfMulTh = UtsusemiGetNumOfMulTh();
#else
    _NumOfMulTh = 1;
#endif
}

//////////////////////////////////////////////////////////
Int4 UtsusemiEventDataConverterRPMT::
_SetElementContainerMatrix( ElementContainerMatrix* ecm, UInt4 caseId ){

    std::vector< std::vector< std::vector< std::vector<Int4>* >* >* >* pixelInfoStore = _EventDecoder->_wirInfo->PixelInfoStore;
    std::vector< std::vector<Double>* >* detPositionInfoVect = _EventDecoder->_detInfo->detPositionInfoVect;

    HeaderBase* ecm_h = ecm->PutHeaderPointer();
    if (!AddRunInfoToHeader( ecm_h, caseId )){
        return -4;
    }

    UInt4 outerPixelId=0;
    Int4 tofBinType = -1;
    while(true){
        if (_EventDecoder->_wirInfo->TofBinInfoList[outerPixelId]!=NULL){
            std::vector<Double>* tofBinInfo = _EventDecoder->_wirInfo->TofBinInfoList[outerPixelId];

            UInt4 tof_pat_id = (UInt4)(tofBinInfo->at(0));
            if (_EventDecoder->_wirInfo->TofBinPtnInfo[ tof_pat_id ]!=NULL){
                tofBinType = _EventDecoder->_wirInfo->TofBinPtnInfo[ tof_pat_id ]->type;
                break;
            }
        }
        outerPixelId++;
    }

    if (tofBinType<0) return -3;

    std::vector<std::string> process_h;
    process_h.push_back( "E2H" );

    ecm_h->Add( UTSUSEMI_KEY_HEAD_DATAPROCESSED, process_h );

    ecm_h->Add( UTSUSEMI_KEY_HEAD_L1,  _EventDecoder->_detInfo->PutInstL1() );

    std::vector<Int4> table_ECA;
    UInt4 index_ECA = 0;
    for (UInt4 daqId=0; daqId<(pixelInfoStore->size()); daqId++){
        if (pixelInfoStore->at(daqId)==NULL) continue;
        for (UInt4 modNo=0; modNo<(pixelInfoStore->at(daqId)->size()); modNo++){
            if (pixelInfoStore->at(daqId)->at(modNo)==NULL) continue;
            for (UInt4 psdNo=0; psdNo<(pixelInfoStore->at(daqId)->at(modNo)->size()); psdNo++){
                UInt4 detId = pixelInfoStore->at(daqId)->at(modNo)->at(psdNo)->at(1);
                if (detId<0) continue;
                UInt4 xpos_size = pixelInfoStore->at(daqId)->at(modNo)->at(psdNo)->at(5);
                if (table_ECA.size()<=(detId*1000+xpos_size)) table_ECA.resize( (detId*1000+xpos_size+1),-1 );
                for (UInt4 xpos=0; xpos<xpos_size; xpos++){
                    table_ECA[detId*1000+xpos]=index_ECA;
                    index_ECA++;
                }
            }
        }
    }
    clock_t t1,t2;
    t1=clock();

    ecm->Allocate(index_ECA);

    std::vector<Int4> bankIdList = _EventDecoder->_detInfo->PutBankIdList();
    std::vector<std::string> bankNameList = _EventDecoder->_detInfo->PutBankName();
    bool isSetBankInfo = true;
    if (bankIdList.empty()) isSetBankInfo = false;

    UInt4 num_of_det = (_EventDecoder->_wirInfo->MaxDetId)+1;
    std::vector<Int4> hashTableOfBankId( num_of_det, -1 );
    std::vector<Int4> hashTableOfIndexInBank( num_of_det, -1 );
    std::vector<Int4> bankSizeList( bankIdList.size(), 0 );

    if (isSetBankInfo){
        //ecm_h->Add( UTSUSEMI_KEY_HEAD_BANKIDLIST, bankIdList );
        //ecm_h->Add( UTSUSEMI_KEY_HEAD_BANKNAMELIST, bankNameList );

        for (UInt4 i=0; i<bankIdList.size(); i++){
            std::vector<Int4> tmp = _EventDecoder->_detInfo->PutDetIdInBank( bankIdList[i] );
            if (tmp.empty()){
            }else{
                bankSizeList[i]=(Int4)(tmp.size());
                for (UInt4 j=0; j<tmp.size(); j++){
                    if (tmp[j]<0){
                    }else{
                        if (tmp[j]<(Int4)num_of_det) {
                            hashTableOfBankId[(UInt4)(tmp[j])]=bankIdList[i];
                            hashTableOfIndexInBank[(UInt4)(tmp[j])]=j;
                        }
                    }
                }
            }
        }
        //ecm_h->Add( UTSUSEMI_KEY_HEAD_BANKSIZELIST, bankSizeList );
    }


#ifdef MULTH
    omp_set_num_threads( _NumOfMulTh );
#endif

    for (UInt4 daqId=0; daqId<(pixelInfoStore->size()); daqId++){
        if (pixelInfoStore->at(daqId)==NULL) continue;
        for (UInt4 modNo=0; modNo<(pixelInfoStore->at(daqId)->size()); modNo++){
            if (pixelInfoStore->at(daqId)->at(modNo)==NULL) continue;
            for (UInt4 detNo=0; detNo<(pixelInfoStore->at(daqId)->at(modNo)->size()); detNo++){
                UInt4 detId = pixelInfoStore->at(daqId)->at(modNo)->at(detNo)->at(1);
                if (detId<0) continue;
                Int4 head_pixelId = pixelInfoStore->at(daqId)->at(modNo)->at(detNo)->at(2);
                Int4 xpos_size = pixelInfoStore->at(daqId)->at(modNo)->at(detNo)->at(5);
                Int4 ypos_size = pixelInfoStore->at(daqId)->at(modNo)->at(detNo)->at(7);

                for (UInt4 xpos=0; xpos<(UInt4)xpos_size; xpos++){
                    ElementContainerArray* ECA = new ElementContainerArray();
                    HeaderBase* h_ECA = ECA->PutHeaderPointer();

                    if ( (detId<_isUnReadDetId.size())&&(_isUnReadDetId[detId]) )
                        h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_MASKED), 1 );
                    else
                        h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_MASKED), 0 );
                    h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_DETTYPE), std::string(UTSUSEMI_KEY_HEAD_DETTYPE_PSD) );
                    h_ECA->Add( std::string("PSDID"), Int4(detId*xpos_size+xpos) );
                    h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_DETID), Int4(detId*xpos_size+xpos) );
                    h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_XPOS), Int4(xpos) );
                    if (isSetBankInfo) {
                        h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_BANKID), hashTableOfBankId[detId] );
                        h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_INDEXINBANK), hashTableOfIndexInBank[detId] );
                    }

                    std::vector<Int4> maskedEC;
                    maskedEC.push_back(-1);
                    h_ECA->Add( std::string(UTSUSEMI_KEY_HEAD_MASKDEC), maskedEC );

                    ECA->Allocate( (UInt4)ypos_size );

#pragma omp parallel for
#if (_OPENMP >= 200805)  // OpenMP 3.0 and later
                    for (UInt4 ypos=0; ypos<ypos_size; ypos++){
#else
                    for (Int4 ypos=0; ypos<(Int4)ypos_size; ypos++){
#endif
                        UInt4 pixelId = head_pixelId + ypos_size*xpos + ypos;
                        ElementContainer* EC = new ElementContainer();
                        HeaderBase* h_EC = EC->PutHeaderPointer();
                        h_EC->Add(std::string("PSDID"), Int4(detId) );
                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_DETID), Int4(detId) );
                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_MASKED), 0 );
                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_PIXELID), Int4(pixelId) );
                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_YPOS), Int4(ypos) );
                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_XPOS), Int4(xpos) );

                        std::string label = "Run"+stools->Int4ToString(_runNumber)+"("+stools->Int4ToString(detId)+","+stools->Int4ToString(xpos)+","+stools->Int4ToString(ypos)+")";
                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_LABEL), label );

                        std::vector<Double> ppv(3,0.0);
                        ppv[0] = _EventDecoder->_pixelPositionVect[ pixelId ]->at(0);
                        ppv[1] = _EventDecoder->_pixelPositionVect[ pixelId ]->at(1);
                        ppv[2] = _EventDecoder->_pixelPositionVect[ pixelId ]->at(2);
                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_PIXELPOSITION),ppv);

                        if ((_EventDecoder->_pixelPositionVect[ pixelId ]->size())==6){
                            std::vector<Double> psv(3,0.0);
                            psv[0] = _EventDecoder->_pixelPositionVect[ pixelId ]->at(3);
                            psv[1] = _EventDecoder->_pixelPositionVect[ pixelId ]->at(4);
                            psv[2] = _EventDecoder->_pixelPositionVect[ pixelId ]->at(5);
                            h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_PIXELCOVERAGE),psv);
                        }

                        h_EC->Add(std::string(UTSUSEMI_KEY_HEAD_PIXELSOLIDANGLE), _EventDecoder->_pixelSolidAngleVect[ pixelId ] );

                        SetElementContainerReadout( pixelId, EC, caseId );

                        EC->AddToHeader(std::string(UTSUSEMI_KEY_HEAD_TOTALCOUNTS), EC->Sum() );

                        ECA->Set( ypos, EC );
                    }
                    ecm->Set( table_ECA[detId*1000+xpos], ECA );
                    //std::cout << "##### detId, ypos=" << detId << "," << ypos << std::endl;
                }
            }
        }
    }

    if (isSetBankInfo) {
        UtsusemiMessage(_MessageTag+" Create Bank Info");
        std::vector<bool> reqBank( bankIdList.size(), false );
        for (UInt4 i=0;i<ecm->PutSize();i++){
            HeaderBase* hhh = ecm->PutPointer(i)->PutHeaderPointer();
            if (hhh->CheckKey( std::string(UTSUSEMI_KEY_HEAD_BANKID) )==1){
                Int4 bank_id = hhh->PutInt4( std::string(UTSUSEMI_KEY_HEAD_BANKID) );
                if (bank_id<0){
                    Int4 det_id = hhh->PutInt4( std::string(UTSUSEMI_KEY_HEAD_DETID) );
                    UtsusemiWarning(_MessageTag+"DETID="+stools->UInt4ToString(det_id)+" is not set in bank info");
                }else{
                    if (reqBank[bank_id]) continue;
                    else reqBank[bank_id]=true;
                }
            }else{
                UtsusemiWarning(_MessageTag+"ecm("+stools->UInt4ToString(i)+") has no key BANKID");
            }
        }
        std::vector<Int4> set_bankIdList;
        std::vector<std::string> set_bankNameList;
        std::vector<Int4> set_bankSizeList;
        for (UInt4 i=0;i<bankIdList.size();i++){
            if (reqBank[ bankIdList[i] ]){
                set_bankIdList.push_back( bankIdList[i] );
                set_bankNameList.push_back( bankNameList[i] );
                set_bankSizeList.push_back( bankSizeList[i] );
            }
        }
        ecm_h->Add( UTSUSEMI_KEY_HEAD_BANKIDLIST, set_bankIdList );
        ecm_h->Add( UTSUSEMI_KEY_HEAD_BANKNAMELIST, set_bankNameList );
        ecm_h->Add( UTSUSEMI_KEY_HEAD_BANKSIZELIST, set_bankSizeList );
    }

    t2 = clock();
    UtsusemiMessage(_MessageTag+">> Cost of time="+stools->DoubleToString(t2-t1));

    return 0;
}
