using namespace std;
#include "hwallunpacker.h"
#include "walldef.h"
#include "hwalllookup.h"
#include "hwallraw.h"
#include "hdebug.h"
#include "hades.h"
#include "hevent.h"
#include "hspectrometer.h"
#include "hdetector.h"
#include "hruntimedb.h"
#include "hcategory.h"
#include "hldsubevt.h"
#include "heventheader.h"
#include <iostream>
#include <iomanip>
#include <stdlib.h>
ClassImp(HWallUnpacker)
HWallUnpacker::HWallUnpacker(UInt_t id) {
  
  subEvtId=id;
  pRawCat=NULL;
  lookup=0;
}
Bool_t HWallUnpacker::init(void) {
  
  pRawCat=gHades->getCurrentEvent()->getCategory(catWallRaw);
  if (!pRawCat) {
    pRawCat=gHades->getSetup()->getDetector("Wall")->buildCategory(catWallRaw);
    if (!pRawCat) return kFALSE;
    gHades->getCurrentEvent()->addCategory(catWallRaw,pRawCat,"Wall");
  }
  loc.set(1,0);
  lookup=(HWallLookup*)(gHades->getRuntimeDb()->getContainer("WallLookup"));
  return kTRUE;
}
Int_t HWallUnpacker::execute(void) {
  HWallRaw* pRaw=0;
  Int_t nCrate=-1, nChannel=0, nCell=-1;
  Int_t nEvt        = 0;    
  UInt_t nSlot      = 0;
  UInt_t uWordCount = 0;    
  UInt_t uBlockSize = 0;    
  UInt_t uBoardType = 0;    
  UInt_t *uTmp      = NULL; 
  Char_t dcType='U';
  if (gHades->isCalibration()){
    
    
    return 1;
  }
  if (pSubEvt) {
    UInt_t* data = pSubEvt->getData();
    UInt_t* end  = pSubEvt->getEnd();
    nEvt = gHades->getCurrentEvent()->getHeader()->getEventSeqNumber();
    
    while ( ++data<end && *data!=0x0 ) {
      #if DEBUG_LEVEL>4
         printf("Data word: %p\n",*data);
      #endif
      
      
      if ( ((*data >>24) & 0x6)==0 ) {
        uBlockSize = (*data) & 0x0000003ff;
        uBoardType = (*data >> 12 ) & 0x1;
        
        if (uBoardType==1) {
          data+=uBlockSize;
          continue;
        }
        
        else if (uBoardType==0) {
          
          #if DEBUG_LEVEL>2
             printf("TIP-block 0x%08x Size %i Board  %i\n",
                    *data,uBlockSize,uBoardType);
          #endif
          continue;
        } else {
          #if DEBUG_LEVEL>2
             Warning("execute","Uknown BoardType=%i",uBoardType);
          #endif
        }
      }
      
      else if ( ((*data>>24) & 0x6)==2 ){
        
        uBlockSize = ( (*data) >> 8   ) & 0xff;
        nCrate     = ( (*data) >> 16  ) & 0xff;
        nSlot      = ( (*data) >> 27  ) & 0x1f;
        
        if ((*(data + uBlockSize+1) >>24 & 0x6)!=4) {
          Warning("execute","Header found but no trailer!!!");
          continue;
        }
        
        if ((*(data+uBlockSize+1)&0xff)!=((UInt_t)pSubEvt->getTrigNr()&0xFF)) {
          Error("execute","Trigger tag mismatch!");
          exit(EXIT_FAILURE);
        }
        
        #if DEBUG_LEVEL>4
           printf("TDC header 0x%08x.Size: %i.Crate: %i.Slot: %i.\n",
                  *data,uBlockSize,nCrate,nSlot);
        #endif
        uTmp=data;
        HWallLookupSlot* dc=lookup->getSlot(nCrate-1,nSlot-1);
        if (dc && (dcType=dc->getType())!='U') {
          uWordCount=0;
          while( ++data && data<(uTmp + uBlockSize+1) && *data!=0x0 ) {
            uWordCount++;
            if (nSlot!=((*data>>27)&0x1f)) {
              Warning("execute",
                      "Slot (%d) different that in header(%d)",
                      nSlot,(*data>>27)&0x1f);
              continue;
            }
            nChannel = (*(data) >> 16 ) & 0x003f;
            HWallLookupChan* dcs=dc->getChannel(nChannel);
            if (dcs) {
              nCell=dcs->getCell();
              loc[0]=nCell;
              pRaw=(HWallRaw *)pRawCat->getObject(loc);
              if (!pRaw) {
                pRaw=(HWallRaw *)pRawCat->getSlot(loc);
                if (pRaw) {
                  pRaw=new (pRaw) HWallRaw;
                  pRaw->setCell(nCell);
                } else {
                  Error("execute()","Can't get slot\n");
                  return -1;
                }
              } else {
                #if DEBUG_LEVEL>4
                   Info("execute()","Slot already exists!\n");
                #endif
              }
              Float_t val = (*data & 0xfff);
              if (dcType=='T') pRaw->setTime(val);
              else pRaw->setCharge(val);
            } else Info("execute()","TDC channel: %i not found",nChannel);
          } 
          if (uWordCount!=uBlockSize) {
            
            Warning("execute()",
                    "Found %i but expecting %i words!!!",
                    uWordCount,uBlockSize);
            continue;
          }
        } else {
          
          data+=uBlockSize+1;
          #if DEBUG_LEVEL>4
             Info("execute()",
                  "Can not get TDC for crate %i and slot %i",
                  nCrate-1,nSlot-1);
          #endif
        }
      } else if ( ((*data>>24) & 0x6)==6 ) {
        
        
        #if DEBUG_LEVEL>2
           Warning("execute()",
                   "Evt: %i, Invalid Data Word! Type: %d,Skipping 0x%08x",
                   nEvt,((*data>>24) & 0x6),*data);
          #if DEBUG_LEVEL>4
             pSubEvt->dumpIt();
          #endif
        #endif
      } else if ( ((*data>>24) & 0x6)==0 ) {
        Warning("execute()",
                "Evt: %i, Data follow, but no header",nEvt);
      } else {
        Warning("execute()",
                "Evt: %i, Unknow raw data type %i",
                nEvt,((*data>>24) & 0x6));
      }
    } 
  }
  return 1;
}