#include "hratree.h"
#include "hcategory.h"
#include "hlocation.h"
#include "hlocateddataobject.h"
#include "hiterator.h"
#include "hdebug.h"
#include "TIterator.h"
#include "TArrayI.h"
#include "TClass.h"
void HRaNode::clear(void) {
  
  TIter next(fSubNodes);
  HRaNode *node;
  while ( (node=(HRaNode *)next())!=NULL) {
    node->clear();
  }
}
HRaNode::~HRaNode(void) {
    delete fSubNodes;
}
void HRaIndexNode::clear(void) {
  
  fCells.Clear();
}
HRaTree::HRaTree(void) {
  
 fRoot=NULL;
 fSourceCategory=NULL;
 fDepth=0;
 fLoc.setNIndex(0);
 fLowerLevel=0;
 fIter = NULL;
}
HRaTree::HRaTree(HCategory *cat,TArrayI *sizes) {
  
  
  if (!cat->getClass()->InheritsFrom("HLocatedDataObject")) {
    Warning("HRaTree::HRaTree",
	    "Data class not inheriting from HlocatedDataObject");
    fSourceCategory=NULL;
    fDepth=0;
  } else {
    HLocatedDataObject *obj;
    fSourceCategory=cat;
    obj=(HLocatedDataObject *)cat->getClass()->New();
    fDepth=obj->getNLocationIndex();
    delete obj;
    fIter=(HIterator *)cat->MakeIterator();
  }
  buildTree(sizes);
  fLoc.setNIndex(0);
  fLowerLevel=0;
}
HRaTree::HRaTree(HCategory *cat,HLocation &loc,TArrayI *sizes) {
  
  
  if (!cat->getClass()->InheritsFrom("HLocatedDataObject")) {
    Warning("HRaTree::HRaTree",
	    "Data class not inheriting from HlocatedDataObject");
    fSourceCategory=NULL;
    fDepth=0;
  } else {
    HLocatedDataObject *obj;
    fSourceCategory=cat;
    obj=(HLocatedDataObject *)cat->getClass()->New();
    fDepth=obj->getNLocationIndex()-loc.getNIndex();
    delete obj;
    fIter=(HIterator *)cat->MakeIterator();
    fIter->gotoLocation(loc);
  }
  buildTree(sizes);
  fLoc=loc; 
  fLowerLevel=loc.getNIndex();
}
HRaNode *HRaTree::buildNode(TArrayI *sizes,Int_t lvl) {
  
  Int_t i;
  HRaNode *r=new HRaNode(sizes->At(lvl));
  if (sizes->GetSize()-2>lvl) {
    for (i=0;i<sizes->At(lvl);i++) {
      r->addSubNode(buildNode(sizes,lvl+1));
    }
  } else {
    for (i=0;i<sizes->At(lvl);i++) {
      r->addSubNode(new HRaIndexNode(sizes->At(lvl+1)));
    } 
  }
  return r;
}
Bool_t HRaTree::buildTree(TArrayI *sizes) {
  
  Bool_t r=kTRUE;
  if (fDepth==sizes->GetSize()) {
    if (fDepth==1) {
      fRoot=new HRaIndexNode(sizes->At(0));
    } else {
      fRoot=buildNode(sizes,0);
    }
  } else {
    r=kFALSE;
    Error("buildTree","Sizes vector dimension and tree depth don't match");
  }
  return r;
}
HRaTree::~HRaTree(void) {
  
  if (fRoot) delete fRoot;
  fSourceCategory=NULL;
  if(fIter) {
      delete fIter;
      fIter = NULL;
  }
}
Bool_t HRaTree::addObject(HLocatedDataObject *obj) {
  
  
  Int_t level=fLowerLevel;
  HRaNode *node=fRoot;
  HRaIndexNode *inode=NULL;
#if DEBUG_LEVEL>2
  gDebuger->enterFunc("HRaTree::addObject");
#endif
  if (fDepth==1) {
    inode=(HRaIndexNode *)fRoot;
  } else {
    for (level=fLowerLevel;level<fLowerLevel+fDepth-2;level++) { 
      
      node=node->getSubNode(obj->getLocationIndex(level));
      if (node==NULL) return kFALSE;
    }
    inode=(HRaIndexNode *)node->getSubNode(obj->getLocationIndex(level));
    if (!node) return kFALSE;
  }
  level++;
#if DEBUG_LEVEL>2
  gDebuger->leaveFunc("HRaTree::addObject");
#endif
  inode->setCell(obj,obj->getLocationIndex(level));
  return kTRUE;
}
Bool_t HRaTree::update(void) {
  
  HLocatedDataObject *obj;
  if (fDepth==0 || fRoot==NULL || fSourceCategory==NULL || fIter==NULL) {
    Error("update","Tree not properly constructed");
    return kFALSE;
  } else {
    fRoot->clear();
    fIter->gotoLocation(fLoc);
    while ( (obj=(HLocatedDataObject *)fIter->Next())!=NULL) {
      if (!addObject(obj)) {
	return kFALSE;
      }
    }
  }
  return kTRUE;
}
TObject *HRaTree::getObject(HLocation &aLoc) {
  
  
  HRaNode *node=fRoot;
  Int_t level=0;
  
  for (level=0;level<fDepth-1;level++) {
    node=node->getSubNode(aLoc.getUncheckedIndex(level));
    if (!node) return NULL;
  }
  return ((HRaIndexNode *)node)->getCell(aLoc.getUncheckedIndex(level));
}
TObject *HRaTree::getObject(Int_t i1,Int_t i2,Int_t i3,Int_t i4,
					  Int_t i5,Int_t i6,Int_t i7,Int_t i8,
					  Int_t i9) {
  
  
  HRaNode *node=NULL;
  TObject *r=NULL;
  if (i1>-1 && fDepth>0) {
    node=fRoot;
    if(i2>-1 && fDepth>1) {
      node=node->getSubNode(i1);
      if (i3>-1&& fDepth>2) {
	node=node->getSubNode(i2);
	if (i4>-1&& fDepth>3) {
	  node=node->getSubNode(i3);
	  if (i5>-1&& fDepth>4) {
	    node=node->getSubNode(i4);
	    if (i6>-1&& fDepth>5) {
	      node=node->getSubNode(i5);
	      if (i7>-1&& fDepth>6) {
		node=node->getSubNode(i6);
		if (i8>-1&& fDepth>7) {
		  node=node->getSubNode(i7);
		  if (i9>-1&& fDepth>8) {
		    node=node->getSubNode(i8);
		    r=((HRaIndexNode *)node)->getCell(i9);
		  } else r=((HRaIndexNode *)node)->getCell(i8);
		} else r=((HRaIndexNode *)node)->getCell(i7);
	      } else r=((HRaIndexNode *)node)->getCell(i6);
	    } else r=((HRaIndexNode *)node)->getCell(i5);
	  } else r=((HRaIndexNode *)node)->getCell(i4);
	} else r=((HRaIndexNode *)node)->getCell(i3);
      } else r=((HRaIndexNode *)node)->getCell(i2);
    } else r=((HRaIndexNode *)node)->getCell(i1);
  } else r=NULL;
  return (r);
}
ClassImp(HRaNode)
ClassImp(HRaIndexNode)
ClassImp(HRaTree)