using namespace std;
#include "TROOT.h"  
#include "hdetparrootfileio.h"
#include "hades.h"
#include "hruntimedb.h"
#include "hparrootfileio.h"
#include "hrun.h"
#include "hspectrometer.h"
#include "hdetector.h"
#include "hparset.h"
#include "hdetgeompar.h"
#include "hgeomcompositevolume.h"
#include "TKey.h"
#include <iostream> 
#include <iomanip>
ClassImp(HDetParRootFileIo)
HDetParRootFileIo::HDetParRootFileIo(HParRootFile* f) : HDetParIo() {
  
  pFile=f;
  modulesFound=0;    
  initModules=0;
  isActiv=kFALSE;
}
HDetParRootFileIo::~HDetParRootFileIo() {
  
  if (modulesFound) {
    delete modulesFound;
    modulesFound=0;
  }
  if (initModules) {
    delete initModules;
    initModules=0;
  }
}
Int_t HDetParRootFileIo::readModules(const Text_t* detName) {
  
  
  
  
  
  HDetector* setup=gHades->getSetup()->getDetector(detName);
  Int_t* set=setup->getModules();
  if (pFile) pFile->cd();
  HDetector* det=(HDetector*)gROOT->FindObject(detName);
  Int_t num=0;
  Int_t len=6*(setup->getMaxModules());
  if (det) {
    modulesFound=new TArrayI(len);
    Int_t* mod=det->getModules();
    for(Int_t m=0;m<len;m++) {
      if (set[m]!=0) {
        if (mod[m]!=0) modulesFound->AddAt(m+1,m);
        else num++;
      }
    }
    delete det;
  }
  isActiv=kTRUE;
  return num;
}
Bool_t HDetParRootFileIo::read(HParSet* pPar) {
  
  Text_t* name=(Char_t*)pPar->GetName();
  Int_t version=findInputVersion(name);    
  if (version<=0) {
    pPar->setInputVersion(-1,inputNumber);
    return kFALSE;
  }
  if (pPar->getInputVersion(inputNumber)==version
      && pPar->getInputVersion(inputNumber)!=-1) return kTRUE;
  TKey* key = (TKey*)gDirectory->GetKey(name,version);
  if (key) {
    pPar->clear();
    key->Read(pPar); 
    pPar->setInputVersion(version,inputNumber);
    pPar->setChanged();
    cout<<"Container "<<pPar->GetName()<<" initialized from "<<pFile->GetName()<<endl;
    return kTRUE;
  }
  pPar->setInputVersion(-1,inputNumber);
  return kFALSE;
}
Bool_t HDetParRootFileIo::write(HDetector* p) {
  
  
  if (pFile) {
    pFile->cd();
    if (pFile->IsWritable()) {
      p->Write(((Char_t*)p->GetName()));
      return kTRUE;
    }
  }
  Error("write(HDetector*)","Output %s is not writable",pFile->GetName());
  return kFALSE;
}
Int_t HDetParRootFileIo::write(HParSet* pPar) {
  
  
  if (pFile) {
    pFile->cd();
    if (pFile->IsWritable()) {
      Text_t* name=(Char_t*)pPar->GetName();
      pPar->Write(name);
      pPar->setChanged(kFALSE);
      gHades->getRuntimeDb()->setVersionsChanged(kTRUE);
      return getMaxVersion(name);
    }
  }
  Error("write(HDetector*)","Output %s is not writable",pFile->GetName());
  return -1;
}
Int_t HDetParRootFileIo::getMaxVersion(const Text_t* name) {
  
  
  TKey* key=pFile->GetKey(name);
  if (key) return key->GetCycle();
  else return -1;
}
Int_t HDetParRootFileIo::findInputVersion(const Text_t* name) {
  
  
  HParVersion* currVers=
      gHades->getRuntimeDb()->getCurrentRun()->getParVersion(name);
  Int_t v=currVers->getInputVersion(inputNumber);
  if (v>0) return v;      
  HRun* r=pFile->getRun();
  if (!r) return -1;        
  HParVersion* vers=r->getParVersion(name);
  if (!vers) return -1;     
  return vers->getRootVersion();
}  
TObject* HDetParRootFileIo::findContainer(const Text_t* name, Int_t vers) {
  
  
  
  
  
  Text_t cn[80];
  sprintf(cn,"%s;%i",name,vers);
  pFile->cd();
  TObject* p=gROOT->FindObject(cn);
  return p;
}
void HDetParRootFileIo::printInfo(const Text_t* msg) {
  
  
  Bool_t first=kTRUE;
  for(Int_t i=0;i<initModules->GetSize();i++) {
    if (initModules->At(i)) {
      if (first) {
        cout<<msg;
        cout<<pFile->GetName()<<": ";
        first=kFALSE;
      }
      cout<<(initModules->At(i)-1)<<" ";
    }
  }
  cout<<'\n';
}
Bool_t HDetParRootFileIo::read(HDetGeomPar* pPar,Int_t* set) {
  
  
  Text_t* name=(Char_t*)pPar->GetName();
  Int_t version=findInputVersion(name);    
  if (version==-1) {
    pPar->setInputVersion(-1,inputNumber);
    return kFALSE;
  }
  if (pPar->getInputVersion(inputNumber)==version) return kTRUE;
  pPar-> clear();
  HDetGeomPar* rGeom=(HDetGeomPar*)findContainer(name,version);
  if (!rGeom) return kFALSE;
  Bool_t allFound=kTRUE;
  initModules->Reset();
  pPar->copyComment(*rGeom);
  Int_t nMod=pPar->getNumModules();
  Int_t nRef=pPar->getNumRefModules();
  Int_t nComp=pPar->getNumComponents();
  for(Int_t m=0;m<nMod;m++) {
    if (set[m]) {
      HModGeomPar* pMod=pPar->getModule(m);
      HModGeomPar* rMod=rGeom->getModule(m);
      if (rMod&&allFound) {
        HGeomTransform& tp=pMod->getLabTransform();
        tp=rMod->getLabTransform();
        if (pPar->isFirstInitialization()) {
          pMod->SetName(rMod->GetName());
          pMod->setRefName(rMod->getRefName());
          const Text_t* ref=rMod->getRefName();
          pMod->setRefName(ref);
          Int_t mr=pPar->getModNumInMod(ref);
          HGeomCompositeVolume* refMod=pPar->getRefVolume(mr);
          if (refMod==0) {
            refMod=new HGeomCompositeVolume(nComp);
            refMod->SetName(ref);
            pPar->addRefVolume(refMod,mr);
          }
          pMod->setVolume(refMod);
          set[m]=0;
          initModules->AddAt(m+1,m);
        }
      } else allFound=kFALSE;
    }
  }
  if (pPar->isFirstInitialization() && allFound) {
    for(Int_t m=0;m<nRef;m++) {
      HGeomCompositeVolume* pMod=pPar->getRefVolume(m);
      HGeomCompositeVolume* rMod=rGeom->getRefVolume(m);
      if (pMod && rMod && pMod->getNumPoints()==0) {
        pMod->setShape(rMod->getShape());
        pMod->setMother(rMod->getMother());
        Int_t np=rMod->getNumPoints();
        pMod->createPoints(np);
        for(Int_t i=0;i<np;i++) pMod->setPoint(i,*(rMod->getPoint(i)));
        HGeomTransform& tp=pMod->getTransform();
        tp=rMod->getTransform();
        for(Int_t c=0;c<nComp;c++) {
          HGeomVolume* pComp=pMod->getComponent(c);
          HGeomVolume* rComp=rMod->getComponent(c);
          pComp->SetName(rComp->GetName());
          pComp->setShape(rComp->getShape());
          pComp->setMother(rComp->getMother());
          Int_t npc=rComp->getNumPoints();
          pComp->createPoints(npc);
          for(Int_t i=0;i<npc;i++) pComp->setPoint(i,*(rComp->getPoint(i)));
          HGeomTransform& tpc=pComp->getTransform();
          tpc=rComp->getTransform();
        }
      }
    }
  }
  delete rGeom;
  if (allFound) {
    pPar->setInputVersion(version,inputNumber);
    pPar->setChanged();
    pPar->setNotFirstInit();
    cout<<name<<" initialized from "<<pFile->GetName()<<endl;
  } else pPar->clear();
  return allFound;
}