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

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

//////////////////////////////////////////////////////////
void EmakiEventDataConverterReadout1d::
Initialize(){
    _MessageTag = "EmakiEventDataConverterReadout1d >> ";
    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 EmakiEventDataConverterReadout1d::
_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();
    std::string RUNNUMBER = "";
    for (UInt4 i=0; i<_runNumbers.size(); i++) RUNNUMBER += stools->Int4ToString( _runNumbers[i] ) + ",";
    RUNNUMBER.erase( RUNNUMBER.size()-1,1 );
    ecm_h->Add( "RUNNUMBER", RUNNUMBER );
    //ecm_h->Add( "RUNNUMBER", stools->Int4ToString(_runNumber ) );
    ecm_h->Add( "MONITORCOUNT", 0.0 );
    ecm_h->Add( "INSTRUMENT", _instCode );
    ecm_h->Add( "SAMPLETYPE", "unknown" );
    ecm_h->Add( "MEASPERIOD", _CaseDecoder->PutMeasPeriodFromT0() );

    UInt4 num_of_case = PutNumOfCases();
    std::vector<UInt4> num_of_t0_list = PutNumOfT0ListInCases();
    Int4 num_of_t0 = 0;
    if (num_of_t0_list.size()==1) num_of_t0 = num_of_t0_list[0];
    else num_of_t0 = num_of_t0_list[ caseId ];
    ecm_h->Add( "KICKERCOUNT", num_of_t0 );

    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( "DATAPROCESSED", process_h );

    ecm_h->Add( "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;
                if (table_ECA.size()<=detId) table_ECA.resize( detId+1,-1 );
                table_ECA[detId]=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( "BANKIDLIST", bankIdList );
        //ecm_h->Add( "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]<num_of_det) {
                            hashTableOfBankId[(UInt4)(tmp[j])]=bankIdList[i];
                            hashTableOfIndexInBank[(UInt4)(tmp[j])]=j;
                        }
                    }
                }
            }
        }
        //ecm_h->Add( "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 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;
                Int4 head_pixelId = pixelInfoStore->at(daqId)->at(modNo)->at(psdNo)->at(2);
                Int4 num_pixels = pixelInfoStore->at(daqId)->at(modNo)->at(psdNo)->at(3);

                ElementContainerArray* ECA = new ElementContainerArray();
                HeaderBase* h_ECA = ECA->PutHeaderPointer();
                if ( (detId<_isUnReadDetId.size())&&(_isUnReadDetId[detId]) )
                    h_ECA->Add( std::string("MASKED"), 1 );
                else
                    h_ECA->Add( std::string("MASKED"), 0 );
                h_ECA->Add( std::string("TYPE"), std::string("PSD") );
                h_ECA->Add( std::string("PSDID"), Int4(detId) );
                h_ECA->Add( std::string("DETID"), Int4(detId) );
                if (isSetBankInfo) {
                    h_ECA->Add( std::string("BANKID"), hashTableOfBankId[detId] );
                    h_ECA->Add( std::string("INDEXINBANK"), hashTableOfIndexInBank[detId] );
                }
                std::vector<Int4> maskedEC;
                maskedEC.push_back(-1);
                h_ECA->Add( std::string("MASKEDElementContainer"), maskedEC );

                ECA->Allocate( (UInt4)num_pixels );

#pragma omp parallel for
#if (_OPENMP >= 200805)  // OpenMP 3.0 and later
                for (UInt4 pixel=0; pixel<(UInt4)num_pixels; pixel++){
#else
                for (Int4 pixel=0; pixel<(UInt4)num_pixels; pixel++){
#endif
                    UInt4 pixelId = head_pixelId + pixel;
                    ElementContainer* EC = new ElementContainer();
                    HeaderBase* h_EC = EC->PutHeaderPointer();
                    h_EC->Add(std::string("PSDID"), Int4(detId) );
                    h_EC->Add(std::string("DETID"), Int4(detId) );
                    h_EC->Add(std::string("MASKED"), 0 );
                    h_EC->Add(std::string("PIXELID"), Int4(pixelId) );

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

                    SetElementContainerReadout( pixelId, EC, caseId );

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

                    ECA->Set( pixel, EC );

                }
                ecm->Set( table_ECA[detId], ECA );
            }
        }

    }

    // <- [TI 20151105] Add a raw TOF std::vector<Double> to EC
    for (UInt4 i=0; i<ecm->PutSize(); ++i){
        ElementContainerArray* _eca = ecm->PutPointer(i);
        for (UInt4 j=0; j< _eca->PutSize(); ++j){
            HeaderBase* hh = _eca->PutPointer(j)->PutHeaderPointer();
            if (hh->CheckKey( std::string("PIXELID") )==1 && _eca->PutPointer(j)->CheckKey( std::string("TOF") )==0 ){
                _eca->PutPointer(j)->Add("TOF", _EventDecoder->PutHistBin(hh->PutInt4( std::string("PIXELID" ) )), "microsec");
            }
        }
    }
    // -> [TI 20151105]

    if (isSetBankInfo) {
        std::cout << _MessageTag+" Create Bank Info" << std::endl;
        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("BANKID") )==1){
                Int4 bank_id = hhh->PutInt4( std::string("BANKID") );
                if (bank_id<0){
                    Int4 det_id = hhh->PutInt4( std::string("DETID") );
                    std::cout << _MessageTag+"DETID=" << det_id << " is not set in bank info" << std::endl;
                }else{
                    if (reqBank[bank_id]) continue;
                    else reqBank[bank_id]=true;
                }
            }else{
                std::cout << _MessageTag+"ecm(" << i <<  ") has no key BANKID" << std::endl;
            }
        }
        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( "BANKIDLIST", set_bankIdList );
        ecm_h->Add( "BANKNAMELIST", set_bankNameList );
        ecm_h->Add( "BANKSIZELIST", set_bankSizeList );
    }

    //t2 = clock();
    //std::cout << _MessageTag <<">> Cost of time="<< (t2-t1) << std::endl;
    return 0;
}

