#include "hrootsource.h"
#include "hades.h"
#include "hrecevent.h"
#include "heventheader.h"
#include "hpartialevent.h"
#include "hcategory.h"
#include <iostream>
#include <iomanip>
#include <limits.h>
#include <unistd.h>
#include "TKey.h"
using namespace std;
ClassImp(HRootSource)
HRootSource::HRootSource(Bool_t fPers, Bool_t fMerg)
{
    
    
    
    fInput           = 0;
    fEventInFile     = 0;
    fCursor          = 0;
    fCurrentRunId    = INT_MIN;
    fCurrentRefId    = -1;
    fGlobalRefId     = -1;
    fDirectory       = "./";
    fPersistency     = fPers;
    fMerge           = fMerg;
    fEventList       = 0;
    fLastRunId       = -1;
    overwriteVersion = kFALSE;
    replaceVersion   = 0;
}
HRootSource::~HRootSource(void)
{
    
    Clear();
}
Text_t const *HRootSource::getCurrentFileName(void)
{
    if(fInput){
	TFile* file = fInput->GetCurrentFile();
	if(file){
	    return file->GetName();
	} else {
	    return "";
	}
    }
    return "";
}
Bool_t HRootSource::init(void)
{
    
    
    
    
    
    Bool_t r = kTRUE;
    if (fEventInFile != 0)
    {
	
	HRecEvent* fCurrentEvent = (HRecEvent*)gHades->getCurrentEvent();
	if (fCurrentEvent != 0) {
	    if (fMerge) {  
		Warning("init","Merging with predefined event structure");
		((HRecEvent*)fEventInFile)->merge(fCurrentEvent);
	    } else {
		Warning("init","Using predefined event structure");
	    }
	} else  { gHades->setEvent(fEventInFile); }
	if ( fInput!=0)
	{
	    Char_t sl=*(strchr(fInput->GetTitle(),'.')+1);
	    switch (sl) {
	    case '0' : fSplitLevel = 0;
	    break;
	    case '1' : fSplitLevel = 1;
	    break;
	    case '2' : fSplitLevel = 2;
	    break;
	    default : fSplitLevel  = 0;
	    }
	    fInput->SetBranchStatus("*",kFALSE);
	    gHades->activateTree(fInput);
	    if (fEventList) {
		fEntries = fEventList->GetN();
	    } else {
		fEntries=fInput->GetEntries();
	    }
	    if (fCursor >= fEntries) {
		Error("init","Entry not existing %i",fCursor);
		return kFALSE; 
	    }
	    if (fEventList) {
		fInput->GetEvent(fEventList->GetEntry(fCursor));
	    } else {
		fInput->GetEvent(fCursor);
	    }
	    fCurrentRunId = gHades->getCurrentEvent()->getHeader()->getEventRunNumber();
	    fLastRunId = fCurrentRunId;
	    if(overwriteVersion)
	    { 
		gHades->getCurrentEvent()->getHeader()->setVersion(replaceVersion);
	    }
	    if (fRefIds.find(fCurrentRunId) != fRefIds.end()) {
		fCurrentRefId = fRefIds[fCurrentRunId];
	    } else {
		fCurrentRefId = fGlobalRefId;
	    }
	    if (fPersistency == kFALSE) { 
		for(Int_t i = 0; i < 16; i ++) { 
		    HPartialEvent* fPar = ((HRecEvent*)fEventInFile)->getPartialEvent(i<<kBitCategorySize);
		    if (fPar) { fPar->setPersistency(kFALSE); }
		}
	    }
	    setCursorToPreviousEvent();
	    r = kTRUE;
	} else {
	    Warning("init","Not input");
	    Clear();
	    r = kFALSE;
	}
    } else {
	r = kFALSE;
    }
    return r;
}
EDsState HRootSource::getNextEvent(Bool_t doUnpack)
{
    
    Int_t bread = 0;
    if (fInput)
    {
	if (fSplitLevel < 2) (*fEventAddr)->clearAll(fSplitLevel);
	if (fCursor < fEntries)
	{
	    if (fEventList) {
		bread = fInput->GetEvent(fEventList->GetEntry(fCursor));
	    } else {
		bread = fInput->GetEvent(fCursor);
	    }
	    if (bread == 0) { return kDsEndData; }
	    fCursor ++;
	    fCurrentRunId = gHades->getCurrentEvent()->getHeader()->getEventRunNumber();
	    if(overwriteVersion)
	    {  
		gHades->getCurrentEvent()->getHeader()->setVersion(replaceVersion);
	    }
	    if (fCurrentRunId != fLastRunId)
	    {
		if (fRefIds.find(fCurrentRunId) != fRefIds.end()) {
		    fCurrentRefId = fRefIds[fCurrentRunId];
		} else {
		    fCurrentRefId = fGlobalRefId;
		}
		fLastRunId = fCurrentRunId;
		return kDsEndFile;
	    }
	} else { return kDsEndData; }
    } else { return kDsError; }
    return kDsOk;
}
void HRootSource::setCursorToPreviousEvent()
{
    
    
    
    
    
    
    
    if(fCursor > 0) { fCursor --; }
}
Bool_t HRootSource::getEvent(Int_t eventN) {
    
    
    if (fInput) {
	if (fEventList) {
	    if (fInput->GetEvent(fEventList->GetEntry(eventN)) > 0)
	    {
		return kTRUE;
	    } else {
		if (fInput->GetEvent(eventN)>0){ return kTRUE; }
		else                           { return kFALSE; }
	    }
	}
    }
    return kFALSE;
}
void HRootSource::Clear(void)
{
    
    if (fInput) {
	delete fInput;
	fInput = 0;
    }
}
void HRootSource::setDirectory(const Text_t dirName[])
{
    
    fDirectory = dirName;
    if (fDirectory[fDirectory.Length()-1] != '/') { fDirectory += "/"; }
}
Bool_t HRootSource::fileExists(const TString &name) {
    
    return (access(name.Data(),F_OK) == 0) ? kTRUE : kFALSE;
}
TString HRootSource::getFileName(const Text_t *file)
{
    TString fname;
    if (file[0] == '/') { 
	fname = file;
    } else {
	fname = fDirectory;
	fname += file;
    }
    return fname;
}
Bool_t HRootSource::addFile(const Text_t *file)
{
    Text_t treeName[] = "T";
    TString fname = getFileName(file);
    if (fileExists(fname))
    {
	if (!fInput)
	{ 
	    TFile *fileTemp;
	    TKey *key = 0;
	    TString title;
	    fileTemp = getFile(fname.Data()); 
	    
	    key               = fileTemp->GetKey(treeName);  
	    fEventInFile      = (HEvent *)fileTemp->Get("Event");
	    fCurrentRunId     = fEventInFile->getHeader()->getEventRunNumber();
	    if (fRefIds.find(fCurrentRunId) != fRefIds.end()) {
		fCurrentRefId = fRefIds[fCurrentRunId];
	    } else {
		fCurrentRefId = fGlobalRefId;
	    }
	    title = key->GetTitle();
	    fileTemp->Close();
	    delete fileTemp;
	    fInput = new TChain(treeName,title.Data());
	}
	fInput->Add(fname.Data());
    } else {
	Warning("addFile","File %s not found",fname.Data());
	return kFALSE;
    }
    return kTRUE;
}
Bool_t HRootSource::setInput(const Text_t *fileName,const Text_t *treeName)
{
    
    
    
    if (strcmp(treeName,"T") != 0) { return kFALSE; }
    else                           { return addFile(fileName); }
}
Bool_t HRootSource::disableCategory(Cat_t aCat)
{
    
    
    
    
    if (!fEventInFile) { return kFALSE; }
    else               { return fEventInFile->removeCategory(aCat); }
}
Bool_t HRootSource::disablePartialEvent(Cat_t aCat)
{
    if (!fEventInFile) { return kFALSE; }
    else               { return ((HRecEvent*)fEventInFile)->removePartialEvent(aCat); }
}
Int_t HRootSource::getSplitLevel(void)
{
    
    return fSplitLevel;
}
void HRootSource::deactivateBranch(const Text_t *branchName)
{
    
    
    if (fInput) {
	fInput->SetBranchStatus(branchName,kFALSE);
    }
}
TTree *HRootSource::getTree(void)
{
    
    return fInput;
}
EDsState HRootSource::skipEvents(Int_t nEv)
{
    enum EDsState state = kDsOk;
    if (nEv > 0) {
	Int_t newCursor = fCursor + nEv;
	if (newCursor < fEntries) {
	    fCursor = newCursor - 1;
	    state = getNextEvent();
	} else { state = kDsEndData; }
    }
    return state;
}
TFile * HRootSource::getFile(TString name)
{
    return TFile::Open(name.Data(),"READ");
}