#include "hades.h"
#include "hcategory.h"
#include "hdebug.h"
#include "hevent.h"
#include "heventheader.h"
#include "hldsource.h"
#include "hldsubevt.h"
#include "hruntimedb.h"
#include "hspectrometer.h"
#include "hemcdetector.h"
#include "hemcraw.h"
#include "hemctrb3lookup.h"
#include "hemctrb3unpacker.h"
#include "emcdef.h"
#include "htrbnetunpacker.h"
#include <iostream>
using namespace std;
ClassImp(HEmcTrb3Unpacker)
#define EMC_USE_TIME_WINDOW 1
#define EMC_TIME_MIN -300.0
#define EMC_TIME_MAX  1500.0
Bool_t HEmcTrb3Unpacker::fHasPrintedTDC = kFALSE;
HEmcTrb3Unpacker::HEmcTrb3Unpacker(vector<UInt_t>& ids) : HTrb3TdcUnpacker(ids),
    fLookup(0), fTimeRef(kTRUE), fTimeShift(650.) {
	
	pRawCat = NULL;
}
Bool_t HEmcTrb3Unpacker::init(void) {
    
    HEmcDetector* det = (HEmcDetector*) gHades->getSetup()->getDetector("Emc");
    if (!det) {
        Error("init", "No EMC Detector found.");
        return kFALSE;
    }
    pRawCat = det->buildCategory(catEmcRaw);
    if (!pRawCat)  return kFALSE;
    else gHades->getCurrentEvent()->addCategory(catEmcRaw,pRawCat,"Emc");
    fLoc.set(2, 0, 0);
    fLookup = (HEmcTrb3Lookup*) (gHades->getRuntimeDb()->getContainer("EmcTrb3Lookup"));
    if (!fLookup) {
        Error("init", "No Pointer to parameter container EmcTrb3Lookup.");
        return kFALSE;
    }
    if (NULL == trbNetUnpacker) {
        if (gHades->getDataSource()) {
            HDataSource* source = gHades->getDataSource();
            if (source->InheritsFrom("HldSource")) {
                trbNetUnpacker =
                        ((HldSource *) gHades->getDataSource())->getTrbNetUnpacker();
            } else {
                Warning("init",
                        "DataSource not inherited from HldSource! trbNetUnpacker == 0 ");
            }
        } else {
            Warning("init",
                    "Could not retrieve DataSource! trbNetUnpacker == 0 ");
        }
    }
    if (!trbNetUnpacker->init()) {
        Error("init()", "Failed to initialize HTrbNetUnpacker!");
        return kFALSE;
    }
    return kTRUE;
}
Bool_t HEmcTrb3Unpacker::reinit(void)
{
    
    
    
    
    if (numTDC() == 0 )  
    {
	if (fMinAddress == 0 && fMaxAddress == 0)
	{
	    
	    Int_t numTDC = fLookup->getSize();
	    Int_t offset = fLookup->getArrayOffset() ;
	    for (Int_t slot = 0; slot < numTDC; ++slot) {
		Int_t trbnetaddress = offset+slot;
		HEmcTrb3LookupBoard* tdc = fLookup->getBoard(trbnetaddress);
		if(tdc){
		    Int_t nChan = tdc->getSize();
		    if (trbnetaddress) {
			Int_t tindex = addTDC(trbnetaddress,nChan);
			Info("reinit", "Added TDC 0x%04x with %d channels from HEmcTrb3Lookup to map index %d",
			     trbnetaddress, nChan,tindex);
		    }
		}
	    }
	    
	    setMinAddress(fLookup->getArrayOffset());
	    setMaxAddress(fLookup->getArrayOffset() + fLookup->getSize());
	    fUseTDCFromLookup = kTRUE; 
	    fHasPrintedTDC = kTRUE;
	} else {
            Info("reinit", "TDCs will be added in auto register mode between min address 0x%04x and max address 0x%04x!",fMinAddress,fMaxAddress);
	}
    }
    
    return kTRUE;
}
Int_t HEmcTrb3Unpacker::execute(void) {
    if (gHades->isCalibration()) {
        
        return 1;
    }
    if (gHades->getCurrentEvent()->getHeader()->getId() == 0xe) {
        
        return 1;
    }
    
    
    if (!pSubEvt)
        return 1;
    Int_t nEvt = gHades->getCurrentEvent()->getHeader()->getEventSeqNumber();
    
    if (!decode()) {
        Error("decode",
                "subsubevent decoding failed!!! Evt Nr : %i SubEvtId: %x", nEvt,
                getSubEvtId());
        return -1;
    }
    
    
    
    
    if (fTimeRef) {
        correctRefTimeCh(REFCHAN);
    }
    const Double_t timeUnit=1e9;
    for (UInt_t ntdc = 0; ntdc < numActiveTDC(); ntdc++) {
        HTrb3TdcUnpacker::TDC* tdc = getActiveTDC(ntdc);
        
        HEmcTrb3LookupBoard *board = fLookup->getBoard(tdc->getTrbAddr());
        if (!board) {
            if (debugFlag > 0)
                Warning("execute",
                        "Evt Nr : %i  SubEvId: %x (%i) unpacked but TDC Board 0x%x not in lookup table",
                        nEvt, getSubEvtId(), getSubEvtId(), tdc->getTrbAddr());
            continue;
        }
	
        for (UInt_t i = 0; i < tdc->numChannels(); i++) {
            if(REFCHAN == i) continue;
	    HTrb3TdcUnpacker::ChannelRec& theRecord = tdc->getCh(i);
#ifndef EMC_USE_TRAILING_WITHOUT_LEADING_EDGES
            if (theRecord.rising_mult < 1)
                continue;
#endif
            HEmcTrb3LookupChan *chan = board->getChannel(i);
            if (chan == 0) {
                Warning("execute", "Missing channel %u in lookup table", i);
                continue;
            }
            chan->getAddress(fLoc[0], fLoc[1]);
	    
	    if (fLoc[0] < 0)  { 
		continue;
	    }
	    
            if (!chan->isDefinedChannel() || chan->isBrokenChannel())
                continue;
	    Bool_t fastchannel = chan->isFastChannel();
            if(fastchannel && chan->isSlowChannel())
            {
                Warning("execute", "NEVER COME HERE - channel %u has both fast and slow property! skip it..", i);
                    continue;
            }
#ifdef EMC_USE_TIME_WINDOW
            
            Double_t tmin = EMC_TIME_MIN;
            Double_t tmax = EMC_TIME_MAX;
#endif
            UInt_t lix = 0;
            for (lix = 0; lix < theRecord.rising_mult; ++lix) {
                Double_t tm0 = theRecord.rising_tm[lix] * timeUnit;
                if (debugFlag > 0)
                    Warning("execute", "JJJJ current hit leading: tm0:%e, apply time shift:%e", tm0, fTimeShift);
                tm0 +=fTimeShift;
#ifdef EMC_USE_TIME_WINDOW
                if ((tm0 < tmin) || (tm0 > tmax)) {
                    if (debugFlag > 0)
                        Warning("execute",
                                "JJJJ Rejecting leading hit outside tmin:%e or tmax:%e",
                                tmin, tmax);
                    continue; 
                }
#endif
                
                if (lix < theRecord.falling_mult) {
                    Double_t tm1 = theRecord.falling_tm[lix] * timeUnit;
                    if (debugFlag > 0)
                        Warning("execute", "JJJJ current hit falling: tm1:%e, apply time shift:%e",
                                tm1, fTimeShift);
                    tm1 +=fTimeShift;
#ifdef EMC_USE_TIME_WINDOW
                    if ((tm1 < tmin) || (tm1 > tmax)) {
                        if (debugFlag > 0)
                            Warning("execute",
                                    "JJJJ Rejecting trailing hit outside tmin:%e or tmax:%e",
                                    tmin, tmax);
#ifdef EMC_USE_LEADING_WITHOUT_TRAILING_EDGES
                        tm1=0.0; 
#else
                        continue; 
#endif
                    } 
#endif
                    
                    
                    
                    
                    
                    if (addRawHit(tm0, tm1, fastchannel) != 0)
                        continue; 
                } 
                else {
#ifdef EMC_USE_LEADING_WITHOUT_TRAILING_EDGES
                    
                    
                    if(addRawHit(tm0, 0.0, fastchannel)!=0)
                    continue;
#endif
                }
            } 
#ifdef EMC_USE_TRAILING_WITHOUT_LEADING_EDGES
            for (UInt_t tix=lix; tix< theRecord.falling_mult; ++tix)
            {
                Double_t tm1=theRecord.falling_tm[tix] * timeUnit;
#ifdef EMC_USE_TIME_WINDOW
                    if ((tm1 < tmin) || (tm1 > tmax)) {
                        if (debugFlag > 0)
                            Warning("execute",
                                    "JJJJ Rejecting trailing hit outside tmin:%e or tmax:%e",
                                    tmin, tmax);
			continue;
#endif
                if(addRawHit(0.0, tm1, fastchannel)!=0)
		    continue;
            }
             
#endif
        } 
    } 
    return 1;
}
Int_t HEmcTrb3Unpacker::addRawHit(Double_t t_leading, Double_t t_trailing,
        Bool_t isfastchannel) {
    
    HEmcRaw* raw = (HEmcRaw*) pRawCat->getObject(fLoc);
    if (!raw) {
        raw = (HEmcRaw *) pRawCat->getSlot(fLoc);
        if (raw) {
	    raw = new (raw) HEmcRaw;
	    Char_t row,col;
	    HEmcDetector::getRowCol(fLoc[1],row,col);
	    raw->setAddress(fLoc[0], fLoc[1],row,col);
        } else {
            if (debugFlag > 0)
                Warning("addRawHit()", "Can't get slot mod=%i, chan=%i",
                        fLoc[0], fLoc[1]);
            return -1;
        }
    }
    isfastchannel ?
            raw->addFastHit(t_leading, t_trailing) :
            raw->addSlowHit(t_leading, t_trailing);
    if (debugFlag > 1)
        Warning("addRawHit",
                "JJJJ ADDING %s hit for mod:%d chan:%d tm0:%e tm1:%e",
                (isfastchannel ? "fast" : "slow"), fLoc[0], fLoc[1], t_leading,
                t_trailing);
    return 0;
}