//////////////////////////////////////////////////////////////////////
// Author: Henrik Tydesjo                                           //
// This class implements the use of a list of clusters.             //
//////////////////////////////////////////////////////////////////////  

#include "HenrikClusterList.h"
#include "HenrikClusterListNode.h"

//______________________________________________________________________________
HenrikClusterList::HenrikClusterList():
  fNrEntries(0),
  fFirst(NULL),
  fLast(NULL),
  fFastAccess(kFALSE),
  fFastAccessArray(NULL),
  fDummyIndex(0)
{}
//______________________________________________________________________________
HenrikClusterList::HenrikClusterList(HenrikClusterListNode* first, UInt_t nrEntries):
  fNrEntries(nrEntries),
  fFirst(first),
  fLast(NULL),
  fFastAccess(kFALSE),
  fFastAccessArray(NULL),
  fDummyIndex(0)
{
  SetLastNode();
}
//______________________________________________________________________________
HenrikClusterList::HenrikClusterList(const HenrikClusterList& ilist):
  fNrEntries(0),
  fFirst(NULL),
  fLast(NULL),
  fFastAccess(kFALSE),
  fFastAccessArray(NULL),
  fDummyIndex(0)
{
  // copy constructor
  *this = ilist;
}
//______________________________________________________________________________
HenrikClusterList::~HenrikClusterList() {
  Clear();
}
//______________________________________________________________________________
HenrikClusterList& HenrikClusterList::operator=(const HenrikClusterList& ilist) {
  // assignment operator
  if (this!=&ilist) {
    this->Clear();
    fFirst = CloneNode(ilist.fFirst);
    SetLastNode();
    fFastAccess=kFALSE;
    fFastAccessArray=NULL;
    fDummyIndex=0;
  }
  return *this;
}
//______________________________________________________________________________
void HenrikClusterList::Clear() {
  // clear the whole list
  ClearFastAccess();
  ClearNode(fFirst);
  fLast=fFirst;
}
//______________________________________________________________________________
void HenrikClusterList::ClearNode(HenrikClusterListNode* &node) {
  // clear this node and all children nodes
  if (node==NULL) return;
  ClearNode(node->Next());
  delete node;
  fNrEntries--;
  node = NULL;
  fFastAccess=kFALSE;
}
//______________________________________________________________________________
HenrikClusterList* HenrikClusterList::Clone() const {
  // returns a clone of the list
  HenrikClusterListNode *newFirst;
  newFirst = CloneNode(fFirst);
  HenrikClusterList* newList = new HenrikClusterList(newFirst,fNrEntries);
  return newList;
}
//______________________________________________________________________________
HenrikClusterListNode* HenrikClusterList::CloneNode(HenrikClusterListNode* node) const {
  if (node==NULL) return NULL;
  else return new HenrikClusterListNode(node->Col(),node->Row(),node->Size(),node->WidthZ(),node->WidthPhi(),node->Type(),CloneNode(node->Next()));
}
//______________________________________________________________________________
Bool_t HenrikClusterList::Insert(Float_t col, Float_t row, UShort_t size, UShort_t widthZ, UShort_t widthPhi, UShort_t type) {
  // insert a new node into the list (returns true if the node was not present before)
  fNrEntries++;
  HenrikClusterListNode* node = new HenrikClusterListNode(col,row,size,widthZ,widthPhi,type,NULL);
  if (fFirst==NULL) {
    fFirst = node;
  }
  else {
    fLast->Next() = node;
  }
  fLast = node;
  return kTRUE;
}
//______________________________________________________________________________
void HenrikClusterList::SetLastNode() {
  HenrikClusterListNode* node = fFirst;
  if (node==NULL) {
    fLast = fFirst;
  }
  else {
    while (1) {
      if (node->Next()==NULL) {
	fLast = node;
	break;
      }
    }
  }
}
//______________________________________________________________________________
void HenrikClusterList::ClearFastAccess(){
  // clears the fast access array of pointers
  if (fFastAccessArray!=NULL) {
    delete [] fFastAccessArray;
    fFastAccessArray=NULL;
  }
  fFastAccess=kFALSE;
}
//______________________________________________________________________________
void HenrikClusterList::InitFastAccess(){
  // initializes the fast access array
  if (fFastAccess) return;
  ClearFastAccess();
  if (fNrEntries>0) {
    fFastAccessArray = new HenrikClusterListNode*[fNrEntries];
    fDummyIndex=0;
    InitFastAccessNode(fFirst);
    fFastAccess=kTRUE;
  }
}
//______________________________________________________________________________
void HenrikClusterList::InitFastAccessNode(HenrikClusterListNode* node) {
  // initializes the fast access array starting from node (used recursively)
  if (node==NULL) return;
  fFastAccessArray[fDummyIndex++] = node;
  InitFastAccessNode(node->Next());
}
//______________________________________________________________________________
Float_t HenrikClusterList::GetColIndex(UInt_t index) {
  // returns the col of the node at position 'index' in the list
  // returns -1 if out of bounds
  if (index<fNrEntries) {
    if (!fFastAccess) InitFastAccess();
    return fFastAccessArray[index]->Col();
  }
  return -1;
}
//______________________________________________________________________________
Float_t HenrikClusterList::GetRowIndex(UInt_t index) {
  // returns the row of the node at position 'index' in the list
  // returns -1 if out of bounds
  if (index<fNrEntries) {
    if (!fFastAccess) InitFastAccess();
    return fFastAccessArray[index]->Row();
  }
  return -1;
}
//______________________________________________________________________________
UShort_t HenrikClusterList::GetSizeIndex(UInt_t index) {
  // returns the size of the node at position 'index' in the list
  // returns 0 if out of bounds
  if (index<fNrEntries) {
    if (!fFastAccess) InitFastAccess();
    return fFastAccessArray[index]->Size();
  }
  return 0;
}
//______________________________________________________________________________
UShort_t HenrikClusterList::GetWidthZIndex(UInt_t index) {
  // returns the width z of the node at position 'index' in the list
  // returns 0 if out of bounds
  if (index<fNrEntries) {
    if (!fFastAccess) InitFastAccess();
    return fFastAccessArray[index]->WidthZ();
  }
  return 0;
}
//______________________________________________________________________________
UShort_t HenrikClusterList::GetWidthPhiIndex(UInt_t index) {
  // returns the width phi of the node at position 'index' in the list
  // returns 0 if out of bounds
  if (index<fNrEntries) {
    if (!fFastAccess) InitFastAccess();
    return fFastAccessArray[index]->WidthPhi();
  }
  return 0;
}
//______________________________________________________________________________
UShort_t HenrikClusterList::GetTypeIndex(UInt_t index) {
  // returns the type of the node at position 'index' in the list
  // returns 99 if out of bounds
  if (index<fNrEntries) {
    if (!fFastAccess) InitFastAccess();
    return fFastAccessArray[index]->Type();
  }
  return 99;
}
//______________________________________________________________________________


