//*-- Author :    Damir Buskulic   20/05/99

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Local data base                                                      //
//                                                                      //
// The local database is used to quickly access frame data contained in //
// a handful of different frame files.                                  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


#include "VFrUtil.h"
#include "TSystem.h"
#include "TStorage.h"
#include "TRegexp.h"
#include "TArrayD.h"
#include "TBenchmark.h"
#include <iostream.h>
#include "VFrameMetaDB.h"

// need XOPEN for strptime()
#ifndef _XOPEN_SOURCE
#  define __USE_XOPEN
#  define _XOPEN_SOURCE
#    include <time.h>
#  undef __USE_XOPEN
#  undef _XOPEN_SOURCE
#else
#  include <time.h>
#endif

// _USE_FRDIRECT is defined if one uses a framelib version>=3.80 which
// implements the direct frame access within a file
#define _USE_FRDIRECT
#define SMSSTAMAX 128
#define SMSVALMAX 512
#define MAXCONDITIONS 512

// TString spDebug = "";

//______________________________________________________________________________
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//------------------------------------------------------------------------------
ClassImp(VFrFileIndex)

//______________________________________________________________________________
VFrFileIndex::VFrFileIndex()
{
   mStartTime = 0;
   mEndTime = 0;
   mFirstMetaIndex = 0;
   mLastMetaIndex = 0;
   mConditionsIndex = 0;
   mFirstGroup = 0;
   mLastGroup = 0;
}

//______________________________________________________________________________
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//------------------------------------------------------------------------------
ClassImp(VMetaDataFMDB)

//______________________________________________________________________________
VMetaDataFMDB::VMetaDataFMDB(TString fileName, UInt_t runNumber,
                  UInt_t frameNumber, VGPSTime startTime,
                  VGPSTime localStartTime, Double_t length, TString detector,
                  TString state, Int_t quality, Int_t trigger) : TObject()
{
// Metadata constructor
   mRunNumber = runNumber;
   mFrameNumber = frameNumber;
   mStartTime = startTime;
    mLength = length;
   mQuality = quality;
   mTrigger = trigger;
   mGroup = 0;
}

//______________________________________________________________________________
VMetaDataFMDB::VMetaDataFMDB() : TObject()
{
// Metadata default constructor
   mRunNumber = 0;
   mFrameNumber = 0;
   mStartTime = VGPSTime(0,0);
   mLength = 0;
   mQuality = 0;
   mTrigger = 0;
   mGroup = 0;
}

//______________________________________________________________________________
VMetaDataFMDB::~VMetaDataFMDB()
{
// Metadata destructor
}

//______________________________________________________________________________
void VMetaDataFMDB::Streamer(TBuffer &R__b)
{
   // Custom stream an object of class VMetaDataFMDB

   UInt_t R__s, R__c;
   VGPSTime temptime;
   if (R__b.IsReading()) {
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 1) {
         VMetaDataFMDB::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
   // process old versions before automatic schema evolution
      TObject::Streamer(R__b);
      R__b >> mRunNumber;
      R__b >> mFrameNumber;
      mStartTime.Streamer(R__b);
      temptime.Streamer(R__b); // this object is not used anymore
      R__b >> mLength;
      R__b >> mQuality;
      R__b >> mTrigger;
      R__b >> mGroup;
      R__b.CheckByteCount(R__s, R__c, VMetaDataFMDB::IsA());
   // end of old versions
   } else {
      VMetaDataFMDB::Class()->WriteBuffer(R__b, this);
   }
}

//______________________________________________________________________________
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//------------------------------------------------------------------------------
ClassImp(VFrameMetaDB)

//______________________________________________________________________________
VFrameMetaDB::VFrameMetaDB() : VVirtualFrameInfoDB()
{
//
// Local frame data base constructor
//
   mPathToDB = "";
   mDBFile = 0;
   mOption = "";
   mIsOpened = 0;
   mMetaTree = 0;
   mConditionTree = new THashList();
   mConditionsIndex = 0;
   mTmpConditions = new VFrCondition*[MAXCONDITIONS];
   memset(mTmpConditions,0,sizeof(VFrCondition*)*MAXCONDITIONS);
   mNConditions = 0;
   mTmpCondIndex = new CondIndex_t[MAXCONDITIONS];
   mHashTable = 0;
   mCurMetaIndex = 0;
   mCurCondTreeIndex = new Int_t[MAXCONDITIONS];
   mCurFrameStart = 0;
   mCurFrameEnd = 0;
   mCurVectName = "";
   mTmpMeta = new VMetaDataFMDB();
   mTmpMetaString = new VMetaString();
   mLastFrNumber = 0;
   mLastRunNumber = 0;
   mConditionNames = new VConditionNames();
   mGroupList = 0;
   mTmpGroupInfo = new VGroupInfo();
   mLastGroupInfo = 0;
   mPlayer = 0;
}

//______________________________________________________________________________
VFrameMetaDB::VFrameMetaDB(char* filename, Option_t* mode,char* frfilenames, Option_t* option)
           : VVirtualFrameInfoDB()
{
// Local frame data base constructor
// filename is the name of the database file.
// The mode may be "read" to open a DB, or "create" to build a new one
// If "create" is used, frfilenames contains the path/names of the files to
// include in the database.
// option is either "R" or "S" (recursive search for files or simple)
// see AddFiles().
//
   TString modeS = mode;
   modeS.ToLower();
   
   mPathToDB = "";
   mDBFile = 0;
   mOption = "";
   mIsOpened = 0;
   mMetaTree = 0;
   mConditionTree = new THashList();
   mConditionsIndex = 0;
   mTmpConditions = new VFrCondition*[MAXCONDITIONS];
   memset(mTmpConditions,0,sizeof(VFrCondition*)*MAXCONDITIONS);
   mNConditions = 0;
   mTmpCondIndex = new CondIndex_t[MAXCONDITIONS];
   mHashTable = 0;
   mCurMetaIndex = 0;
   mCurCondTreeIndex = new Int_t[MAXCONDITIONS];
   mCurFrameStart = 0;
   mCurFrameEnd = 0;
   mCurVectName = "";
   mTmpMeta = new VMetaDataFMDB();
   mTmpMetaString = new VMetaString();
   mLastFrNumber = 0;
   mLastRunNumber = 0;
   mConditionNames = new VConditionNames();
   mGroupList = 0;
   mTmpGroupInfo = new VGroupInfo();
   mLastGroupInfo = 0;
   mPlayer = 0;

   if (!modeS.CompareTo("create")) {
      Build(frfilenames, filename, option);
   } else if (!modeS.CompareTo("read") || !modeS.CompareTo("update")) {
      Open(filename, mode);
   }
}

//______________________________________________________________________________
VFrameMetaDB::~VFrameMetaDB()
{
//
// Local frame data base destructor
//

   if (mMetaTree) delete mMetaTree;
   if (mConditionTree) {
      mConditionTree->Delete();
      delete mConditionTree;
   }
   if (mConditionsIndex) delete mConditionsIndex;
   if (mGroupList) delete mGroupList;
   delete mTmpMeta;
   delete mTmpMetaString;
   if (mTmpConditions) {
      for (int i=0;i<MAXCONDITIONS;i++) if (mTmpConditions[i]) delete mTmpConditions[i];
      delete [] mTmpConditions;
   }
   if (mTmpCondIndex) delete [] mTmpCondIndex;
   if (mHashTable) delete mHashTable;
   if (mDBFile) delete mDBFile;
   delete mConditionNames;
   delete [] mCurCondTreeIndex;
   if (mTmpGroupInfo) delete mTmpGroupInfo;
   if (mLastGroupInfo) delete mLastGroupInfo;
   if (mPlayer) delete mPlayer;
}

//______________________________________________________________________________
void VFrameMetaDB::Build(char* pathtofiles, char* filename, Option_t* option)
{
// Builds the frame database
// pathtofiles is the path to the directory containing the frame files
// used to build the DB
// filename is the name of the ROOT file that is the DB. It will be created
// in the current directory

   Int_t nbfiles = 0;
   
// Test if DB is already opened
   if (mIsOpened) {
      Warning("Build","Data base already opened, cannot build");
      return;
   }

// Open a new file to store the database
   if (!Open(filename,"RECREATE")) {
      Warning("Build","Cannot create database file");
      return;
   }
// Define a new tree containing the metadata
   if (mMetaTree) {delete mMetaTree;}
   mMetaTree = new TTree("FrameDBTree","Local DB tree");
   
   mMetaTree->Branch("detector","VMetaDataFMDB",&mTmpMeta,64000,1);
   mMetaTree->Branch("detectorstrings","VMetaString",&mTmpMetaString,64000,0);

// Define a new tree containing the conditions index
// (the condition trees are build "on demand" when needed
   if (mConditionsIndex) delete mConditionsIndex;
   mConditionsIndex = new TTree("ConditionsIndex","Conditions Index");
   
// Define a new tree to hold the group information
   if (mGroupList) delete mGroupList;
   mGroupList = new TTree("GroupList","Group information");
   mGroupList->Branch("groupinfo","VGroupInfo",&mTmpGroupInfo);
   if (mLastGroupInfo) delete mLastGroupInfo;
   mLastGroupInfo = new VGroupInfo();

// Add the files defined by the user
   nbfiles = AddFiles(pathtofiles, option);
   
   mDBFile->Delete("FrameDBTree;1"); // Delete the old keys 
   mDBFile->Delete("ConditionsIndex;1");
   mDBFile->Delete("GroupList;1");
   char* cname = new char[255];
   for (int i=0;i<mConditionNames->GetNCNames();i++) {
      sprintf(cname,"%s;1",mConditionNames->GetConditionName(i));
      mDBFile->Delete(cname);
   }
   delete [] cname;
   
   mDBFile->Write();                 // Rewrite the new keys/headers
      
   if (nbfiles) {
      printf("nCreated database file from %d files n",nbfiles);
   } else {
      printf("n Did not create the database, no input frame filesn");
   }
   
   mDBFile->Close();
   delete mDBFile;  // deletes also tree and mHashTable structures
                    // (these are in the directory corresponding to the file)
   mDBFile = 0;
   mHashTable = 0;  // needed since deleted but not set to 0 by the file deletion
   mConditionNames = 0;
   mMetaTree = 0;   // idem
   mConditionsIndex = 0;   // idem
   mGroupList = 0;   // idem
   mConditionTree->Clear(); // remove the ref. to obsolete trees
   for (int i=0;i<MAXCONDITIONS;i++) {if (mTmpConditions[i]) delete mTmpConditions[i]; mTmpConditions[i]=0;}
   mIsOpened = kFALSE;
   if (nbfiles) Open(filename,"READ");
}

//______________________________________________________________________________
Bool_t VFrameMetaDB::Open(char* pathtoDB, Option_t* openopt)
{
// Open the Frame database "pathtoDB"
   
   TFile* tmpfile;
   TTree* tmptree;
   TTree* tmpcondindex;
   TTree* tmpcond;
   TTree* tmpgrouplist;
   VHashTable* tmphash;
   TBranch* tmpbranch;
   TBranch* tmpbranchstr;
   TObjArray* listofcondindex;
   TBranch* tmpcondindexbranch;
   TBranch* tmpcondbranch;
   TBranch* tmpgroupbranch;
   Int_t i;
   VFrCondition* tmpcondobject;
   VGroupInfo* tmpgroupinfo;
   
   if (mIsOpened) {
      Warning("Open","Data base already opened with file %s",mPathToDB.Data());
      return kFALSE;
   }

// Test and set the option (update or read)   
   mOption = openopt;
   Bool_t update   = mOption.CompareTo("UPDATE", TString::kIgnoreCase)
                    ? kFALSE : kTRUE;
   Bool_t read     = mOption.CompareTo("READ", TString::kIgnoreCase)
                    ? kFALSE : kTRUE;
   Bool_t recreate = mOption.CompareTo("RECREATE", TString::kIgnoreCase)
                    ? kFALSE : kTRUE;
   
   if (!update && !read && !recreate) {
      read = kTRUE;
      mOption = "READ";
   }

// Opens the file in selected mode                       
   if (recreate) {
      tmpfile = new TFile(pathtoDB, mOption.Data(),"Local database");
   } else {
      tmpfile = new TFile(pathtoDB, mOption.Data());
   }

   if (!(tmpfile->IsOpen())) {
      Warning("Open","Cannot open or create database file");
      delete tmpfile;
      mOption = "";
      return kFALSE;
   }
   
   if (recreate) {
// ============== Open a new file to store the database if creation =====
      if (mDBFile) {delete mDBFile;}
      mDBFile = tmpfile;
      mIsOpened = kTRUE;
      if (mHashTable) {delete mHashTable;}
      mHashTable = 0;
      mPathToDB = gSystem->DirName(pathtoDB);
      return kTRUE;
   }
   
   mPathToDB = gSystem->DirName(pathtoDB);
   
// ============== Loads the metadata tree ===============================
   tmptree = (TTree*)(gDirectory->Get("FrameDBTree"));
   if (!tmptree) {
      Warning("Open","No database tree present in this DB file");
      return kFALSE;
   }
   if (mMetaTree) {delete mMetaTree;}
   mMetaTree = tmptree;

   tmpbranch = mMetaTree->GetBranch("detector");
   tmpbranch->SetAddress(&mTmpMeta);
   tmpbranchstr = mMetaTree->GetBranch("detectorstrings");
   tmpbranchstr->SetAddress(&mTmpMetaString);

// ============== Loads the condition names =============================
// Can work without conditions if necessary
   VConditionNames* tmpcondnames = (VConditionNames*)gDirectory->Get("ConditionNames");
   if (mConditionNames) delete mConditionNames;
   if (tmpcondnames) {
      mConditionNames = tmpcondnames;
   } else {
      mConditionNames = new VConditionNames();
   }
   
// ============== Loads the condition index tree ========================
   tmpcondindex = (TTree*)gDirectory->Get("ConditionsIndex");
   if (!tmpcondindex) {
      Warning("Open","No condition index tree present in this DB file");
      return kFALSE;
   }
   if (mConditionsIndex) {delete mConditionsIndex;}
   mConditionsIndex = tmpcondindex;

//   Finds the branches for the conditions index tree
   listofcondindex = mConditionsIndex->GetListOfBranches();
   
//   Builds the various variables
   mNConditions = listofcondindex->GetEntriesFast();

// Loads and sets the conditions index branches
   for (i=0;i<mNConditions;i++) {
      tmpcondindexbranch = (TBranch*)(listofcondindex->UncheckedAt(i));
      tmpcondindexbranch->SetAddress(&mTmpCondIndex[i]);
   }
   if (mNConditions != mConditionNames->GetNCNames()) {
      Warning("Open","Inconsistency, number of conditions not equal to number of condition names");
   }
   
// ============== Loads the group information tree ======================
   tmpgrouplist = (TTree*)gDirectory->Get("GroupList");
   if (!tmpgrouplist) {
      Warning("Open","No group information tree present in this DB file");
      return kFALSE;
   }
   if (mGroupList) {delete mGroupList;}
   mGroupList = tmpgrouplist;
   
   tmpgroupbranch = mGroupList->GetBranch("groupinfo");
   tmpgroupbranch->SetAddress(&mTmpGroupInfo);
   
// Loads the last group information
   tmpgroupinfo = (VGroupInfo*)gDirectory->Get("LastGroupInfo");
   if (!tmpgroupinfo) {
      Warning("Open","No last group information present in this DB file");
      return kFALSE;
   }
   if (mLastGroupInfo) delete mLastGroupInfo;
   mLastGroupInfo = tmpgroupinfo;

// ============== Loads the condition trees =============================
   if (mNConditions>0 && mNConditions == mConditionNames->GetNCNames()) {
      for (i=0;i<MAXCONDITIONS;i++) {if (mTmpConditions[i]) delete mTmpConditions[i]; mTmpConditions[i]=0;}
      for (i=0;i<mNConditions;i++) {
         tmpcond = (TTree*)gDirectory->Get(mConditionNames->GetConditionName(i));
         if (!tmpcond) {
            Warning("Open","No condition %s in this database",mConditionNames->GetConditionName(i));
         }
         mConditionTree->AddLast(tmpcond);
         tmpcondobject = new VFrCondition();
         mTmpConditions[i] = tmpcondobject;
         tmpcondbranch = tmpcond->GetBranch("condition");
         if (tmpcondbranch) {
            tmpcondbranch->SetAddress(&(mTmpConditions[i]));
         } else {
            Warning("Open","No branch for condition %s in this database",mConditionNames->GetConditionName(i));
         }
      }
   } else {
      Warning("Open","No conditions trees loaded");
   }
   
// ============== Loads the hashtable ===================================
   tmphash = (VHashTable*)gDirectory->Get("FileHashTable");
   if (!tmphash) {
      Warning("Open","No file hash table present in this DB file");
      return kFALSE;
   }
   if (mHashTable) {delete mHashTable;}
   mHashTable = tmphash;

   if (mDBFile) {mDBFile->Close(); delete mDBFile;}
   mDBFile = tmpfile;
   mIsOpened = kTRUE;
   return kTRUE;
}

//______________________________________________________________________________
void VFrameMetaDB::Close()
{
// Closes this metadb
   mDBFile->Close();
   delete mDBFile;  // deletes also tree and mHashTable structures
                    // (these are in the directory corresponding to the file)
   mDBFile = 0;
   mHashTable = 0;  // needed since deleted but not set to 0 by the file deletion
   mConditionNames = 0;
   mMetaTree = 0;   // idem
   mConditionsIndex = 0;   // idem
   mGroupList = 0;   // idem
   mConditionTree->Clear(); // remove the ref. to obsolete trees
   for (int i=0;i<MAXCONDITIONS;i++) {if (mTmpConditions[i]) delete mTmpConditions[i]; mTmpConditions[i]=0;}
   mIsOpened = kFALSE;
}

//______________________________________________________________________________
Bool_t VFrameMetaDB::BuildNewCondition(char* name, const char* varnames)
{
// Add a condition to this database. Builds a new condition tree and adds
// a branch in the index tree. If the index tree already has entries, fill
// the newly created branch with 0's for the size of the index tree.
// "name" is the name of the new condition tree.
// The consistency of the structure is maintained so that the same index is
// used in Condition Names, tree list, TmpConditions objects, TmpCondIndex.
// On return, 0 = error, 1 = OK

   TTree* condtree;
   VFrCondition* condobject;
   Int_t i;
   char subbrname[512];

// Test and set the DB opened option (create, update or read)   
   Bool_t read     = mOption.CompareTo("READ", TString::kIgnoreCase)
                    ? kFALSE : kTRUE;
   
// Test if DB is opened in update mode
   if (!mIsOpened || read) {
      Warning("AddCondition","Data base closed or opened in read mode, cannot add condition");
      return 0;
   }

// Test of existence of condition index tree
   if (!mConditionsIndex) {
      Warning("AddCondition","No conditions index, cannot build index");
      return 0;
   }

// Test for max number of conditions reached
   if (mNConditions >= MAXCONDITIONS-1) {
      Warning("AddCondition","Max number of conditions(%d) reached",MAXCONDITIONS);
      return 0;
   }

// cd to the file (just in case)
   TDirectory* olddirectory = gDirectory;
   if(mDBFile) mDBFile->cd();
   
// ================== Build the new condition Tree ==========================

   condtree = new TTree(name,name);
   
   mConditionTree->AddLast(condtree);
   condobject = new VFrCondition();
   mTmpConditions[mNConditions] = condobject;
   condtree->Branch("condition","VFrCondition",&(mTmpConditions[mNConditions]),32000,0);
   printf("Create condition %s, %p, %pn",name,(&(mTmpConditions[mNConditions])),(((TTree*)mConditionTree->FindObject(name))->GetBranch("condition")->GetAddress()));
   
   mNConditions++;
   
   mConditionNames->AddConditionName(name,varnames);

// Make the updated pieces persistent (well, save them...)
   mConditionNames->Write("ConditionNames",kOverwrite);

// ================== Add a branch to the index tree ========================

   mTmpCondIndex[mNConditions-1].first = 0;
   mTmpCondIndex[mNConditions-1].last = 0;

// Name the subbranches "namefirst" and "namelast" to ensure different names
// for each subbranch. If not done, can confuse the tree mechanism.
   strcpy(subbrname,name);
   strcat(subbrname,"first/I:");
   strcat(subbrname,name);
   strcat(subbrname,"last/I");
   TBranch* newindexbranch = mConditionsIndex->Branch(name,&mTmpCondIndex[mNConditions-1],subbrname);
   Int_t nentries = Int_t(mConditionsIndex->GetEntries());

// Fill with 0's the already existing entries of the tree
   for (i=0; i<nentries; i++) newindexbranch->Fill();

// Update the tree header on disk
   mDBFile->Delete("ConditionsIndex;1");
   mConditionsIndex->Write();
   
   olddirectory->cd();
   return 1;
}

//______________________________________________________________________________
Int_t VFrameMetaDB::AddFiles(const char* filenames, Option_t* option)
{
// Add files described by "filenames" in the database
// The options are :
//     "R" means a recursive search will be done. This is the default.
//     "S" a simple search is performed, not looking at directories.
   TString opt = option;
   opt = opt + "P";
   Int_t nbfiles = AddFiles(filenames,"",opt.Data());
   return nbfiles;
}

//______________________________________________________________________________
FrameH* VFrameMetaDB::FrameReadHeader(FrFile* iFile, int frnum)
{
// Reads only the frame header for the frame number
// frnum in the specified file. Builds a frame structure (temporary)
// Builds a frame structure (temporary)
// This routine takes code from the relevant parts of the Framelib.
// (Thanks, Benoit !)

// if no TOC information available, return null
   if (!(iFile->toc)) {
      FrTOCReadFull(iFile);
      if (!(iFile->toc)) return (NULL);
   }
   
// To avoid relocation problems
   iFile->relocation = FR_NO;  /*--- to avoid relloaction problems---*/

// TOC information available but no frame for this number
   if (frnum >=iFile->toc->nFrame || frnum<0) return(NULL);

// the frame has been found in the TOC: direct read
   if(FrTOCSetPos(iFile, iFile->toc->positionH[frnum]) != 0) return (NULL);
   FrameHRead(iFile);
 
   return(iFile->curFrame);   
}

//______________________________________________________________________________
Int_t VFrameMetaDB::AddFiles(const char* filenames, const char* extrapath, Option_t* option)
{
// Add files described by "filenames" in the database
// The options are :
//     "R" means a recursive search will be done. This is the default.
//     "S" a simple search is performed, not looking at directories.
//     if option contains "P" then it is a primary call, not the result
//     of a recursive one
// extrapath is put in front of the filenames, needed in the database

   const char* workingdirB;
   const char* pathtofilesB, * renamesB;
   char* workingdir;
   char* pathtofiles, * renames;
   TRegexp* regexp = 0;
   FrFile* framefile;
   FrTOC* filetoc;
//   FrameH* framecur;
   const char* frfilename;
   char* tmpfilename;
   TString extrapathS, frfilenameS, detectorS;
   Long_t id,size,flags,modtime;
   Int_t nbfiles = 0;
   Int_t nbfilestot = 0;
   Double_t ftimestart, ftimeend, lastftimeend;
   Float_t trigtbefore, trigtafter;
   Int_t lastgroup, iframe;
   Int_t* framegroup;
   Int_t ffirstind, flastind;
   TArrayF condarray;
   TString condnames;
   Int_t condindex, iconditionnumber;
#if FR_VERS<6000
   FrTrigData* curtrig;
   FrTrigData* firsttrig;
#else
   FrEvent* curtrig;
   FrEvent* firsttrig;
#endif
   FrTOCevt* curtrigtoc;

   TString slash="/";
   TString star="*";

   Int_t i;
      
   TString  opt;
   opt = option;
   opt.ToLower();

// Test and set the DB opened option (create, update or read)   
//   Bool_t update   = mOption.CompareTo("UPDATE", TString::kIgnoreCase)
//                    ? kFALSE : kTRUE;
   Bool_t read     = mOption.CompareTo("READ", TString::kIgnoreCase)
                    ? kFALSE : kTRUE;
   Bool_t recreate = mOption.CompareTo("RECREATE", TString::kIgnoreCase)
                    ? kFALSE : kTRUE;
   
// Test if DB is opened in update mode
   if (!mIsOpened || read) {
      Warning("AddFiles","Data base closed or opened in read mode, cannot update");
      return 0;
   }

// Reads the last metadata and set the last group number, last frame end time
   mMetaTree->GetEntry(mMetaTree->GetEntries()-1);
   lastgroup = mTmpMeta->GetGroup();
   lastftimeend = mTmpMeta->GetStartTime().GetTimeD() + mTmpMeta->GetLength();

   workingdirB = gSystem->WorkingDirectory();
   workingdir = new char[strlen(workingdirB)+1];
   strcpy(workingdir,workingdirB);  // need this because the original string is
                                    // handled by the TSystem methods, can change

// Set directory to the one containing the frame files
   renamesB     = gSystem->BaseName(filenames);
   renames      = new char[strlen(renamesB)+3]; // +3 to allow add * if no names 
   strcpy(renames,renamesB);
   pathtofilesB = gSystem->DirName(filenames);
   pathtofiles  = new char[strlen(pathtofilesB)+3]; // +3 to allow replace by ./ in the test below
   strcpy(pathtofiles,pathtofilesB);
   if (!strcmp(renames,filenames)) strcpy(pathtofiles,".");
// Veto . and .. directories if it is not the primary call to AddFiles (recursive)
   if ( (!strcmp(pathtofiles,".") || !strcmp(pathtofiles,"..")) && !opt.Contains("p") ) {
      delete [] workingdir;
      delete [] pathtofiles;
      delete [] renames;
      return 0;
   }
   if (!strlen(renames)) strcpy(renames,"*");
   if (!gSystem->ChangeDirectory(pathtofiles)) {
      Error("AddFiles","Could not open directory %s",pathtofiles);
      delete [] workingdir;
      delete [] pathtofiles;
      delete [] renames;
      return 0;
   }
   
   extrapathS = extrapath; // Init the TString version

// ==== Loop on the files and put them in the database ====

   regexp = 0;
   if (renames && strlen(renames)) regexp = new TRegexp(renames,kTRUE);
   
   void* dirp = gSystem->OpenDirectory("./");
   frfilename = gSystem->GetDirEntry(dirp);

   while(frfilename) {
      Int_t goodfile = 0;
      if (regexp) {
         TString s = frfilename;
         if (s.Index(*regexp) != kNPOS) goodfile = 1;
      } else { goodfile = 1; }
      if (goodfile) {
         gSystem->GetPathInfo(frfilename,&id,&size,&flags,&modtime);

//      Searches frames only in plain files or executable files (windows case !)
         if (flags <= 1) {
            tmpfilename = new char[strlen(frfilename)+1];
            strcpy(tmpfilename,frfilename);
         
            framefile = FrFileINew(tmpfilename);
            filetoc=0;
            if (framefile) {
//           Reads the table of contents of the file for further use
               if (!(framefile->toc)) {
                  filetoc = FrTOCReadFull(framefile);
               }
            }
            if (!filetoc && framefile) {
               printf("Cannot read file %s, it has no table of contentsn",frfilename);
            } else if (framefile && filetoc) {
               nbfiles++;
               frfilenameS = extrapathS + pathtofiles + slash + frfilename;
//               printf("Browsing file %s, size = %dn",frfilename,size);
               framegroup = new Int_t[framefile->toc->nFrame];
//               int iframegroup = 0;
               ftimestart = 1.e20; ftimeend = 0;
               ffirstind = -1; flastind = 0;
//               while ((framecur = FrameReadHeader(framefile,iframegroup))!=0) {
               for (iframe = 0; iframe<framefile->toc->nFrame;iframe++) {
//           Protects against frame start time = 0
                  if (filetoc->GTimeS[iframe] == 0) {
                     framegroup[iframe] = -1;
                     break;
                  }
//           Loads a Frame and saves information in the tree
                  mTmpMetaString->SetFileName(frfilenameS);
                  mTmpMeta->SetRunNumber(filetoc->runs[iframe]);
                  mTmpMeta->SetFrameNumber(filetoc->frame[iframe]);
                  VGPSTime gpsti(filetoc->GTimeS[iframe],filetoc->GTimeN[iframe]); 
                  mTmpMeta->SetStartTime(gpsti);
                  mTmpMeta->SetLength(filetoc->dt[iframe]);
//                  detectorS = filetoc->name;
                  detectorS = "";
                  mTmpMetaString->SetDetector(detectorS);
                  mTmpMetaString->SetState("L");
                  mTmpMeta->SetQuality(1);
                  mTmpMeta->SetTrigger(1);
//            Updates the group information
                  if (fabs(gpsti.GetTimeD() - lastftimeend) > 1e-4) {
                     lastgroup++;
                     mLastGroupInfo->Copy(*mTmpGroupInfo);
                     mGroupList->Fill();   // fill the group tree
                     mLastGroupInfo->Reset();
                     mLastGroupInfo->SetFirstIndex(mMetaTree->GetEntries());
                     mLastGroupInfo->SetLastIndex(mMetaTree->GetEntries()-1);
                     mLastGroupInfo->SetBeginTime(gpsti.GetTimeD());
                  }
                  lastftimeend = gpsti.GetTimeD() + filetoc->dt[iframe];
                  mTmpMeta->SetGroup(lastgroup);
                  mLastGroupInfo->Increment(lastftimeend, filetoc->dt[iframe]);
                  framegroup[iframe] = lastgroup;

//              Fills the metadata tree                  
                  mMetaTree->Fill();
                  
                  if (ffirstind==-1) ffirstind = (Int_t)(mMetaTree->GetEntries()-1);
               
                  Double_t ftimefrs = filetoc->GTimeS[iframe] + 1.e-9 * filetoc->GTimeN[iframe];
                  if (ftimestart > ftimefrs) ftimestart = ftimefrs;
                  Double_t ftimefre = ftimefrs + filetoc->dt[iframe];
                  if (ftimeend < ftimefre) ftimeend = ftimefre;
            
//                  FrameFree(framecur);
               }

//           Saves the triggers as conditions in relevant condition trees

//           First, deletes the old content of the temp standard conditions
//               mTmpStandardCond->Delete();
//           Then adds the triggers
               for (i=0;i<mNConditions;i++) {mTmpCondIndex[i].first=-1; mTmpCondIndex[i].last=-1;}
               curtrigtoc=0;
#if FR_VERS<6000
               if (framefile->toc) curtrigtoc = framefile->toc->trig;
#else
               if (framefile->toc) curtrigtoc = framefile->toc->event;
#endif
               int itrig = 0;
               framefile->error = FR_OK;
               firsttrig=0;
#if FR_VERS<6000
               firsttrig = FrTrigDataReadT(framefile,"*",0,999999999);
#else
               firsttrig = FrEventReadT(framefile,"*",0,999999999,-1e100, 1e100);
#endif
               curtrig = firsttrig;
               while (curtrig) {
//              Find the relevant group by finding the frame in the file
//              that was owning this trigger. To do this, compare the positions
//              in the file of the frames and of the trigger.
                  int iframe = (framefile->toc->nFrame-1)/2; // for 1 frame in file case
                  int iframeup = framefile->toc->nFrame-1;
                  int iframedown = 0;
                  while (iframeup != iframedown) {
                     if (iframeup == iframedown+1) { // to solve rounding pb
                        iframe = iframeup;
                     } else {
                        iframe = (iframeup+iframedown)/2;
                     }
                     if (framefile->toc->positionH[iframe] > curtrigtoc->position[itrig]) {
                        iframeup = iframe-1;
                     } else {
                        iframedown = iframe;
                     }
                  }
                  
//              Protect against null frame start time
                  if (framegroup[iframedown] > 0) {
                     VGPSTime condtime = VGPSTime(curtrig->GTimeS,curtrig->GTimeN);
                     condarray = AnalyzeTriggerString(curtrig->statistics,condnames);
//                 If condition length = 0, set timeBefore and after to match the frame length
                     if (curtrig->timeBefore==0 && curtrig->timeAfter==0) {
                        double frametime = framefile->toc->GTimeS[iframedown]+1e-9*framefile->toc->GTimeN[iframedown];
                        trigtbefore = condtime.GetTimeD() - frametime;
                        trigtafter = frametime + framefile->toc->dt[iframedown] - condtime.GetTimeD();
                     } else {
                        trigtbefore = curtrig->timeBefore;
                        trigtafter = curtrig->timeAfter;
                     }
//                 Add the condition in the relevant tree and update various indices
#if FR_VERS<6000
                     condindex = AddCondition(curtrig->name,condtime, trigtbefore, trigtafter,
                                  curtrig->triggerStatus, curtrig->amplitude,
                                  curtrig->probability, condnames, condarray, framegroup[iframedown]);
#else
                     condindex = AddCondition(curtrig->name,condtime, trigtbefore, trigtafter,
                                  curtrig->eventStatus, curtrig->amplitude,
                                  curtrig->probability, condnames, condarray, framegroup[iframedown]);
#endif
                     iconditionnumber = mConditionNames->IndexOf(curtrig->name);
//                Sets the condition indices
                     if (mTmpCondIndex[iconditionnumber].first==-1) {
                        mTmpCondIndex[iconditionnumber].first = condindex;
                     }
                     mTmpCondIndex[iconditionnumber].last = condindex;
                  }
//            printf("********  condition : index, first,last %d, %d, %dn",iconditionnumber, condindex, mTmpCondIndex[iconditionnumber].first, mTmpCondIndex[iconditionnumber].last);
                  curtrig = curtrig->next;
                  itrig++;
               }

               if (firsttrig) FrEventFree(firsttrig);
//               printf("Loaded frame file %sn",frfilename);
               FrFileIEnd(framefile);
               
               flastind = (Int_t)(mMetaTree->GetEntries()-1);
 
//        For the first file, create the hash table
//        Define a new hash table used for fast access
               if (!mHashTable && recreate) {
                  Double_t filetlength = ftimeend - ftimestart;
//              The length of the hash table is chosen so that the file sits
//              in only one slot.
                  Int_t optimalcol = 5;
                  mHashTable = new VHashTable(10, ftimestart - filetlength*5*optimalcol, ftimeend + filetlength*5*optimalcol, optimalcol);
               }

//           Puts the file into the hash table
               mHashTable->Add(ftimestart,ftimeend, ffirstind, flastind,mConditionsIndex->GetEntries(), framegroup[0], lastgroup);

//           Fills the conditions index for this file
               mConditionsIndex->Fill();
               
               delete [] framegroup;
            }

            delete [] tmpfilename;
            
//      If a directory, search recursively if desired ("R" option)
         } else if ((flags & 2) && opt.Contains("r") && strcmp(renames,".") && strcmp(renames,"..")) {
            frfilenameS = frfilename + slash + star;
            TString p = extrapathS + pathtofiles + slash;
            nbfilestot += AddFiles(frfilenameS.Data(),p.Data(),"R");
         }
      }

//  Get the next file in the directory
      frfilename = gSystem->GetDirEntry(dirp);
   }
   
// Update the file on disk
//   mDBFile->Delete("FileHashTable;1");
   mDBFile->Delete("FrameDBTree;1");
   mDBFile->Delete("ConditionsIndex;1");
   char* cname = new char[255];
   for (int i=0;i<mConditionNames->GetNCNames();i++) {
      sprintf(cname,"%s;1",mConditionNames->GetConditionName(i));
      mDBFile->Delete(cname);
   }
   delete [] cname;
   if (mHashTable) mHashTable->Write("FileHashTable",kOverwrite);
   if (mConditionNames) mConditionNames->Write("ConditionNames",kOverwrite);
   if (mLastGroupInfo) mLastGroupInfo->Write("LastGroupInfo",kOverwrite);

   mDBFile->Write(); // also write the meta-data header in this operation
   
   gSystem->ChangeDirectory(workingdir);
   
   gSystem->FreeDirectory(dirp);
   
   if(nbfiles) printf("nUpdated database file from %d file(s) in %sn\n",nbfiles,pathtofiles);
   nbfilestot += nbfiles;
   
   delete [] workingdir;
   delete [] pathtofiles;
   delete [] renames;
   delete regexp;
   
   return nbfilestot;
}

//______________________________________________________________________________
Int_t VFrameMetaDB::AddCondition(char* name, VGPSTime time, Float_t timebefore, Float_t timeafter,
                                    Bool_t  triggerStatus, Float_t amplitude,
                                    Float_t prob, TString varNames, TArrayF tvars, Int_t group)
{
// Add a defined condition to the database. Fills the corresponding tree,
// and if the condition type (name) doesn't exist, builds a new tree and
// a new index branch.
// return the index of the new entry in the condition tree

   Int_t iconditionnumber;
   TTree* tree;
   
   iconditionnumber = mConditionNames->IndexOf(name);

// In case there is no trigger with this name, build a new condition type
   if (iconditionnumber < 0) {
      BuildNewCondition(name,varNames.Data());
      iconditionnumber = mConditionNames->IndexOf(name);
   }
   
// Update the condition object
//   printf("Write condition %s, %x, group %dn",name,mTmpConditions[iconditionnumber], group);
   mTmpConditions[iconditionnumber]->SetActive(1);
   mTmpConditions[iconditionnumber]->SetTime(time);
   mTmpConditions[iconditionnumber]->SetTimeBefore(timebefore);
   mTmpConditions[iconditionnumber]->SetTimeAfter(timeafter);
   mTmpConditions[iconditionnumber]->SetTriggerStatus(triggerStatus);
   mTmpConditions[iconditionnumber]->SetAmplitude(amplitude);
   mTmpConditions[iconditionnumber]->SetProbability(prob);
   mTmpConditions[iconditionnumber]->SetVarNames(varNames.Data());
   mTmpConditions[iconditionnumber]->SetVar(tvars);
   mTmpConditions[iconditionnumber]->SetGroup(group);
   
// Fills the condition tree
   tree = (TTree*)mConditionTree->FindObject(name);
   tree->Fill();
   
   return (Int_t)tree->GetEntries()-1;
}

//______________________________________________________________________________
TArrayF VFrameMetaDB::AnalyzeTriggerString(char* string, TString& outputnames)
{
// Analyze the inputs or statistics string in predefined format
// used in the FrameLib.
   
   char* onevar, *posequal, *curvar;
   Int_t eofcheck;
   Float_t* resval;
   Int_t resvalindex;
   
   if (string==0) {
      TArrayF nullarray(0);
      return nullarray;
   }
   outputnames="";
   resval = new Float_t[100];
   resvalindex = 0;
   onevar = new char[100];
   curvar = string;
   eofcheck = sscanf(curvar,"%s",onevar);
   while (eofcheck!=EOF) {
      curvar += strlen(onevar);
      while (*curvar==' ') curvar++;
      posequal = strstr(onevar,"=");
      *posequal=0;
      posequal++;
// Fill name and value
      if (outputnames.Length()) outputnames += " ";
      outputnames += onevar;
      sscanf(posequal,"%f",&resval[resvalindex]);
      resvalindex++;
      eofcheck = sscanf(curvar,"%s",onevar);
   }
   
   TArrayF valarray(resvalindex,resval);
   delete onevar;
   delete resval;
   
   return valarray;
}

//______________________________________________________________________________
Double_t VFrameMetaDB::GetStart()
{
// Returns the start time of the first frame in the metadatabase
   Double_t frbegin,frend;
   Int_t index = FindNearestGEIndex(GetDBStart(),frbegin,frend);
   if (index>=0) return frbegin;
   return 0;
}

//______________________________________________________________________________
Double_t VFrameMetaDB::GetEnd()
{
// Returns the end time of the last frame in the metadatabase
   Double_t frend=0;
   Int_t ihash = mHashTable->GetCapacity()-1;
// Search from last to first slot
   while (ihash>=0) {
      TObjArray* filearray = mHashTable->GetFilesInfoDirect(ihash);
      if (filearray) {
         if (filearray->GetSize()) {
//       Search in the list of files for this slot
            for (int ifile=0;ifile<filearray->GetSize();ifile++) {
               VFrFileIndex* fileindex = (VFrFileIndex*)(filearray->At(ifile));
               if (fileindex) {
                  if (frend < fileindex->GetEndTime())
                      frend = fileindex->GetEndTime();
               }
            }
            if (frend>0) return frend;
         }
      }
      ihash--;
   }
   return 0;
}

//______________________________________________________________________________
Int_t VFrameMetaDB::FindIndex(Int_t approxindex, Double_t gpstime)
{
// Finds the index of the frame meta corresponding to time "gpstime"
// in the metadata tree. approxindex is an approximate value of the index.
// (usually the right one !)
// The search is made in the same group of frames (consecutive frames)
   
   Double_t beginf, endf;
   Int_t searchindex;
   Int_t group;
   
   if (approxindex<0) {
      Warning("FindIndex","The approximate index is negative. It shouldn't be.");
      return -1;
   }
   
   searchindex = approxindex;
   mMetaTree->GetEntry(searchindex);
   beginf = mTmpMeta->GetStartTime().GetTimeD();
   endf = beginf + mTmpMeta->GetLength();
   group = mTmpMeta->GetGroup();
//   printf("searching frame index ... group-index=%d-%d, beginf = %20f, endf = %20fn",group,searchindex, beginf,endf);

// The approximate index is the right one
   if (gpstime>=beginf && gpstime<endf) return searchindex;

// If not, run to the right index, forward
   if (gpstime>endf) {
      while (gpstime>=endf) {
         searchindex++;
         mMetaTree->GetEntry(searchindex);
//   printf("searching frame index ... group-index=%d-%dn",mTmpMeta->GetGroup(),searchindex);
         if (mTmpMeta->GetGroup() != group) {
            Warning("FindIndex","Time %20f not in this group",gpstime);
            return -1;
         }
         endf=mTmpMeta->GetStartTime().GetTimeD() + mTmpMeta->GetGroup();
      }
      return searchindex;

// If not, run to the right index, backward
   } else {
      while (gpstime<beginf && searchindex>0) {
         searchindex--;
         mMetaTree->GetEntry(searchindex);
         if (mTmpMeta->GetGroup() != group) {
            Warning("FindIndex","Time %20f not in this group of frames",gpstime);
            return -1;
         }
         beginf=mTmpMeta->GetStartTime().GetTimeD();
      }
      return searchindex;
   }
}

//______________________________________________________________________________
Int_t VFrameMetaDB::FindIndex(Double_t gpstime, Double_t& frbegin, Double_t& frend)
{
// Finds the index of the frame meta corresponding to time "gpstime"
// in the metadata tree
// returns also the begin and end time of the frame

   Int_t imetamin, imetamax, imeta;
   Double_t beginf=0;
   Double_t endf=0;
   TObjArray* searchfiles;
   VGroupInfo* groupInfo;
   Double_t begingr, endgr;
   Int_t approxindex;
   
// ----- Search in the file hash table ------

   searchfiles = mHashTable->GetFilesInfo(gpstime);
   if (!searchfiles) {
      Warning("FindIndex","Requested time not in the database");
      return -1;
   }

// ----- Search the frame in the meta data tree ------
   
// first, switch on only relevant branches (to speed things up)
   mMetaTree->SetBranchStatus("*",0);  // disable all branches
   mMetaTree->SetBranchStatus("mStartTime*",1);  // activate start time
   mMetaTree->SetBranchStatus("mLength",1);  // activate frame length
   mMetaTree->SetBranchStatus("mGroup",1);  // active group number
   VFrFileIndex* fileindex;
   Int_t filenum=searchfiles->GetEntriesFast()-1;
   fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
   Int_t gosearch = 1;
   imeta=-1;
   while (fileindex && gosearch) {

//   Search in the meta data tree      
      imetamin = fileindex->GetFirstMetaIndex();
      imetamax = fileindex->GetLastMetaIndex();
      imeta    = -1;
//    In case there is a fair number of metadata to scan, look if they
//    are consecutive, in which case try to access quickly the right meta
      if (imetamax-imetamin>15) {
       // Loop on all groups that belong to this file
         for (int igroup = fileindex->GetFirstGroup();igroup<fileindex->GetLastGroup()+1;igroup++) {
            Int_t err = mGroupList->GetEntry(igroup);
            if (!err) {
               groupInfo = mLastGroupInfo;
            } else {
               groupInfo = mTmpGroupInfo;
            }
            begingr = groupInfo->GetBeginTime();
            endgr = groupInfo->GetEndTime();
          // If requested time inside a group, must be able to find metadata
            if (gpstime>=begingr && gpstime<endgr) {
               approxindex = groupInfo->ApproximateIndex(gpstime);
               if (approxindex>=0) {
                  imeta = FindIndex(approxindex, gpstime);
                  mMetaTree->GetEntry(imeta);
                  beginf = mTmpMeta->GetStartTime().GetTimeD();
                  endf = beginf + mTmpMeta->GetLength();
                  gosearch = 0;
                  break;
               } else {
                  Warning("FindIndex","Impossible to find index");
                  break;
               }
          // If before the group beginning, store the distance to find the smallest
            }
         }
      } else {
         imeta = imetamin - 1;
         while (imeta<=imetamax && gosearch) {
            imeta++;
            mMetaTree->GetEntry(imeta);
            beginf = mTmpMeta->GetStartTime().GetTimeD();
            endf = beginf + mTmpMeta->GetLength();
            if ( gpstime >= beginf &&  gpstime <= endf) gosearch = 0;
         }
      }
      
      filenum--;
      if (filenum<0) break;
      fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
   }
   
   if (gosearch) {
      Warning("FindIndex","Requested time not in the database");
//   switch on all branches before exit
      mMetaTree->SetBranchStatus("*",1);  // enable all branches
      return -1;
   }
   
   frbegin = beginf;
   frend = endf;
// switch on all branches before exit
   mMetaTree->SetBranchStatus("*",1);  // enable all branches
   return imeta;
}

//______________________________________________________________________________
Int_t VFrameMetaDB::FindNearestGEIndex(Double_t gpstime, VConditionFormula* condf,
                                      Double_t& frbegin, Double_t& frend,
                                      Double_t& cobegin, Double_t& coend,
                                      Int_t& cogroup)
{
// Finds the index of the frame that contains data for time "gpstime"
// or the frame that is the nearest next one and that satisfies the selection
// formula "condf". (GE stands for Greater or Equal)
// The time is a GPS time expressed as a double : seconds.nanoseconds
// If the pointer to condition is null, suppose no condition asked, will return
// the next nearest frame index.

   Double_t gpstimet, frbegint, frendt;
   Int_t index, cok;
   VConditionSetFMDB* condset;
// ----- Search the condition time if needed -------
//        and load the relevant conditions 
   if (condf) {
      condset = new VConditionSetFMDB(this, condf); // Build a temporary condition set
      cok = condset->NearestGESet(gpstime);              // Search and load the next set of conditions
      if (!cok) {delete condset; return -1;}
      
// Search the conditions for a set that matches the selection expression
      while (1) {
         if (condf->EvalInstance(condset)) {
            break;
         }
         if (!condset->NextSet()) {delete condset; return -1;}
      }
      gpstimet = condset->GetIntersectionStart();
         
      index = FindNearestGEIndex(gpstimet, frbegint, frendt);
      
      if (index == -1) {delete condset; return index;}
      frbegin = frbegint;
      frend = frendt;
      cobegin = gpstimet;
      coend = condset->GetIntersectionEnd();
      cogroup = condset->GetGroup();
      delete condset;
      return index;
   }
   return FindNearestGEIndex(gpstime,frbegin,frend);
}

//______________________________________________________________________________
Int_t VFrameMetaDB::FindNearestGEIndex(Double_t gpstime, Double_t& frbegin, Double_t& frend)
{
// Finds the index of the frame that contains data for time "gpstime"
// or the frame that is the nearest next one (GE stands for Greater or Equal)
// The time is a GPS time expressed as a double : seconds.nanoseconds
// the next nearest frame index.
   
   TObjArray* searchfiles;
   Int_t searchhashv;
   Double_t slotbegin, slotend;
   VFrFileIndex* fileindex;
   Int_t imetamin, imetamax, imeta;
   Double_t beginf,endf, beginfok,endfok;
   Int_t nearestimeta;
   Double_t nearestgetime;
   Int_t gosearch;
   VGroupInfo* groupInfo;
   Double_t begingr, endgr;
   Double_t nearBegin, nearBeginTime; //nearest begin time of a group inside a file
   Int_t nearApproxIndex, approxindex;
   
   if (!mIsOpened || !mOption.CompareTo("update", TString::kIgnoreCase)) {
      Warning("FindNearestGEIndex","Data base not opened or in update mode");
      return -1;
   }
   
// ----- Search in the file hash table ------

// first, switch on only relevant branches (to speed things up)
   mMetaTree->SetBranchStatus("*",0);  // disable all branches
   mMetaTree->SetBranchStatus("mStartTime*",1);  // activate start time
   mMetaTree->SetBranchStatus("mLength",1);  // activate frame length
   searchhashv = mHashTable->GetHashValue(gpstime);
   if (searchhashv<0) searchhashv=0;
//  Gets slot begin and end times to protect the search
   slotbegin = mHashTable->GetSlotBegin(searchhashv);
   slotend   = mHashTable->GetSlotEnd(searchhashv);
   
   nearestimeta=-1;
   nearestgetime = 1e20;
   gosearch = 1;
   beginfok=0;
   endfok=0;
// ---- Loop on the relevant slots. May have to search on more than one ----
//      if a condition set
   while (gosearch) {
      searchfiles = mHashTable->GetFilesInfoDirect(searchhashv);
      if (searchfiles) {
         Int_t filenum=searchfiles->GetEntriesFast()-1;
         fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
         
//  ---- Loop on all the files of a given slot ----
         nearBegin = 1e20; //nearest begin time of a group inside a file
         nearBeginTime = 0;
         nearApproxIndex = -1;
         while (fileindex && gosearch) {
//     Check that the time asked is not behind the last frame in this file
            if (fileindex->GetEndTime() > gpstime) {

//     ----- Loop on all the metadata entries corresponding to one file -----      
               imetamin = fileindex->GetFirstMetaIndex();
               imetamax = fileindex->GetLastMetaIndex();
               imeta = imetamin;
               
//     ----- In case there is a fair number of metadata to scan, look if they    -----
//     ----- are consecutive, in which case try to access quickly the right meta -----
//     ----- use the group information to check it                               -----
               if (imetamax-imetamin>15) {
                // Loop on all groups that belong to this file
                  for (int igroup = fileindex->GetFirstGroup();igroup<fileindex->GetLastGroup()+1;igroup++) {
                     Int_t err = mGroupList->GetEntry(igroup);
                     if (!err) {
                        groupInfo = mLastGroupInfo;
                     } else {
                        groupInfo = mTmpGroupInfo;
                     }
                     begingr = groupInfo->GetBeginTime();
                     endgr = groupInfo->GetEndTime();
                   // If requested time inside a group, must be able to find metadata
                     if (gpstime>=begingr && gpstime<endgr) {
                        approxindex = groupInfo->ApproximateIndex(gpstime);
                        if (approxindex>=0) {
                           nearestimeta = FindIndex(approxindex, gpstime);
                           mMetaTree->GetEntry(nearestimeta);
                           beginfok = mTmpMeta->GetStartTime().GetTimeD();
                           endfok = beginfok + mTmpMeta->GetLength();
                           gosearch = 0;
                           break;
                        } else {
                           Warning("FindNearestGEIndex","Impossible to find index");
                           break;
                        }
                   // If before the group beginning, store the distance to find the smallest
                     } else {
                        if ( gpstime<begingr && (begingr - gpstime) < nearBegin
                             && (begingr - gpstime) < nearestgetime
                             && begingr>=slotbegin && begingr<slotend) {
                           nearBegin = begingr - gpstime;
                           nearBeginTime = begingr+1e-4;
                           nearApproxIndex = groupInfo->ApproximateIndex(begingr+1e-4);
                        }
                     }
                  }
                  if (gosearch != 0) {
                // If not found right metadata, search for the closest one
                     if (nearApproxIndex>=0) {
                        nearestimeta = FindIndex(nearApproxIndex, nearBeginTime);
                        mMetaTree->GetEntry(nearestimeta);
                        beginfok = mTmpMeta->GetStartTime().GetTimeD();
                        nearestgetime = beginfok;
                        endfok = beginfok + mTmpMeta->GetLength();
                     } else {
                        Warning("FindNearestGEIndex","Impossible to find index of start of group");
                        break;
                     }
                  }
               } else {

//      ----- If a small number of frames is in the file, do a scan of metadata -----
                  while (imeta<=imetamax && gosearch) {
                     mMetaTree->GetEntry(imeta);
                     beginf = mTmpMeta->GetStartTime().GetTimeD();
                     endf = beginf + mTmpMeta->GetLength();
//                 Have to look only at frames that are in the slot, not outside it
//                 this may happen if files span more than one slot
                     if (endf>slotbegin && beginf<slotend) {
                        if ( gpstime >= beginf &&  gpstime < endf) {
                           gosearch = 0;
                           nearestimeta = imeta;
                           nearestgetime = beginf;
                           beginfok = beginf;
                           endfok = endf;
                        } else if (gpstime < beginf && nearestgetime > beginf) {
                           nearestimeta = imeta;
                           nearestgetime = beginf;
                           beginfok = beginf;
                           endfok = endf;
                        }
                     }
                     imeta++;
                  }
               }
            }
            filenum--;
            if (filenum<0) break;
            fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
         }  // end loop on files of a slot
      }
      if (nearestimeta>=0) gosearch = 0;
      searchhashv++;
      if (searchhashv> mHashTable->GetCapacity()-1 && nearestimeta<0) {
         Warning("FindNearestGEIndex","Trying to access frame outside bounds of the Database");
//      switch on all branches before exit
         mMetaTree->SetBranchStatus("*",1);  // enable all branches
         return -1;
      }
      slotbegin = mHashTable->GetSlotBegin(searchhashv);
      slotend   = mHashTable->GetSlotEnd(searchhashv);
   } // end loop on slots
      
   frbegin = beginfok;
   frend = endfok;
   
// switch on all branches before exit
   mMetaTree->SetBranchStatus("*",1);  // enable all branches
   return nearestimeta;
}   

//______________________________________________________________________________
Int_t VFrameMetaDB::FindNearestLEIndex(Double_t gpstime, Double_t& frbegin, Double_t& frend)
{
// Finds the index of the frame that contains data for time "gpstime"
// or the frame that is the nearest PREVIOUS one (LE stands for Lower or Equal)
// The time is a GPS time expressed as a double : seconds.nanoseconds
// returns the next nearest frame index.
   
   TObjArray* searchfiles;
   Int_t searchhashv;
   Double_t slotbegin, slotend;
   VFrFileIndex* fileindex;
   Int_t imetamin, imetamax, imeta;
   Double_t beginf,endf, beginfok,endfok;
   Int_t nearestimeta;
   Double_t nearestletime;
   Int_t gosearch;
   
   if (!mIsOpened || !mOption.CompareTo("update", TString::kIgnoreCase)) {
      Warning("FindNearestLEIndex","Data base not opened or in update mode");
      return -1;
   }
   
// ----- Search in the file hash table ------

// first, switch on only relevant branches (to speed things up)
   mMetaTree->SetBranchStatus("*",0);  // disable all branches
   mMetaTree->SetBranchStatus("mStartTime*",1);  // activate start time
   mMetaTree->SetBranchStatus("mLength",1);  // activate frame length
   searchhashv = mHashTable->GetHashValue(gpstime);
   if (searchhashv<0) searchhashv=0;
//  Gets slot begin and end times to protect the search
   slotbegin = mHashTable->GetSlotBegin(searchhashv);
   slotend   = mHashTable->GetSlotEnd(searchhashv);
   
   nearestimeta=-1;
   nearestletime = 0.;
   gosearch = 1;
   beginfok=0;
   endfok=0;
// ---- Loop on the relevant slots. May have to search on more than one ----
//      if a condition set
   while (gosearch) {
      searchfiles = mHashTable->GetFilesInfoDirect(searchhashv);
      if (searchfiles) {
         Int_t filenum=searchfiles->GetEntriesFast()-1;
         fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
         
//  ---- Loop on all the files of a given slot ----
         while (fileindex && gosearch) {
//     Check that the time asked is not before the first frame in this file
            if (fileindex->GetStartTime() < gpstime) {

//     ----- Loop on all the metadata entries corresponding to one file -----      
               imetamin = fileindex->GetFirstMetaIndex();
               imetamax = fileindex->GetLastMetaIndex();
               imeta = imetamin;
               while (imeta<=imetamax && gosearch) {
                  mMetaTree->GetEntry(imeta);
                  beginf = mTmpMeta->GetStartTime().GetTimeD();
                  endf = beginf + mTmpMeta->GetLength();
//              Have to look only at frames that are in the slot, not outside it
//              this may happen if files span more than one slot
                  if (endf>slotbegin && endf<slotend) {
                     if ( gpstime >= beginf &&  gpstime < endf) {
                        gosearch = 0;
                        nearestimeta = imeta;
                        nearestletime = beginf;
                        beginfok = beginf;
                        endfok = endf;
                     } else if (gpstime > endf && nearestletime < endf) {
                        nearestimeta = imeta;
                        nearestletime = beginf;
                        beginfok = beginf;
                        endfok = endf;
                     }
                  }
                  imeta++;
               }
            }
            filenum--;
            if (filenum<0) break;
            fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
         }  // end loop on files of a slot
      }
      if (nearestimeta>=0) gosearch = 0;
      searchhashv--;
      if (searchhashv<0 && nearestimeta<0) {
         Warning("FindNearestLEIndex","Trying to access frame outside bounds of the Database");
//      switch on all branches before exit
         mMetaTree->SetBranchStatus("*",1);  // enable all branches
         return -1;
      }
      slotbegin = mHashTable->GetSlotBegin(searchhashv);
      slotend   = mHashTable->GetSlotEnd(searchhashv);
   } // end loop on slots
      
   frbegin = beginfok;
   frend = endfok;
   
// switch on all branches before exit
   mMetaTree->SetBranchStatus("*",1);  // enable all branches
   return nearestimeta;
}   

//______________________________________________________________________________
Int_t VFrameMetaDB::FindNearestGECondIndex(const char* condname, Double_t gpstime, Double_t& condbegin, Double_t& condend)
{
// Finds the index of the condition that contains data for time "gpstime"
// or the condition that is the nearest next one.
// (GE stands for Greater or Equal)
// The time is a GPS time expressed as a double : seconds.nanoseconds
// returns the index searched for.
   
   Int_t conditionnumber = mConditionNames->IndexOf(condname);
   if (conditionnumber<0) return -1;
   
   return FindNearestGECondIndex(conditionnumber, gpstime, condbegin, condend);
}

//______________________________________________________________________________
Int_t VFrameMetaDB::FindNearestGECondIndex(Int_t conditionnumber, Double_t gpstime, Double_t& condbegin, Double_t& condend)
{
// Finds the index of the condition that contains data for time "gpstime"
// or the condition that is the nearest next one.
// (GE stands for Greater or Equal)
// The time is a GPS time expressed as a double : seconds.nanoseconds
// returns the index searched for.

   TObjArray* searchfiles;
   Int_t searchhashv;
   Double_t slotbegin, slotend;
   VFrFileIndex* fileindex;
   Int_t icondmin, icondmax, icond;
   Double_t timec, beginc,endc, begincok,endcok;
   Int_t nearesticond;
   Double_t nearestgetime;
   Int_t gosearch;
   TTree* conditiontree;
   
   if (!mIsOpened || !mOption.CompareTo("update", TString::kIgnoreCase)) {
      Warning("FindNearestGECondIndex","Data base not opened or in update mode");
      return -1;
   }
   
// ----- Get the condition number, tree, and pointer to condition object -----
   
   conditiontree = (TTree*)(mConditionTree->At(conditionnumber));

// In case do not want to process this tree
//
// *********************** BE CAREFUL, I'm not sure it works in split mode ****************
//
   if (conditiontree->GetBranch("condition")->TestBit(kDoNotProcess)) return -1;
   
// ----- Search in the file hash table ------

   searchhashv = mHashTable->GetHashValue(gpstime);
   if (searchhashv<0) searchhashv=0;
//  Gets slot begin and end times to protect the search
   slotbegin = mHashTable->GetSlotBegin(searchhashv);
   slotend   = mHashTable->GetSlotEnd(searchhashv);
   
   nearesticond=-1;
   nearestgetime = 1e20;
   gosearch = 1;
   begincok=0;
   endcok=0;
// ---- Loop on the relevant slots. May have to search in more than one ----
   while (gosearch) {
      searchfiles = mHashTable->GetFilesInfoDirect(searchhashv);
      if (searchfiles) {
         Int_t filenum=searchfiles->GetEntriesFast()-1;
         fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
         
//  ---- Loop on all the files of a given slot ----
         while (fileindex && gosearch) {
//     Check that the time asked is not behind the last frame in this file
            if (fileindex->GetEndTime() > gpstime) {

//     ----- Loop on all the condition entries corresponding to one file -----      
               mConditionsIndex->GetEntry(fileindex->GetConditionsIndex());
               icondmin = mTmpCondIndex[conditionnumber].first;
               icondmax = mTmpCondIndex[conditionnumber].last;
               icond = icondmin;
               while (icond<=icondmax && gosearch) {
                  conditiontree->GetEntry(icond);
                  timec = mTmpConditions[conditionnumber]->GetTime().GetTimeD();
                  beginc = timec - mTmpConditions[conditionnumber]->GetTimeBefore();
                  endc = timec + mTmpConditions[conditionnumber]->GetTimeAfter();
//              Have to look only at conditions that are in the slot, not outside it
//              this may happen if files span more than one slot
                  if (timec>slotbegin && timec<slotend) {
                     if ( gpstime >= beginc &&  gpstime <= endc) {
                        gosearch = 0;
                        nearesticond = icond;
                        nearestgetime = beginc;
                        begincok = beginc;
                        endcok = endc;
                     } else if (gpstime < beginc && nearestgetime > beginc) {
                        nearesticond = icond;
                        nearestgetime = beginc;
                        begincok = beginc;
                        endcok = endc;
                     }
                  }
                  icond++;
               }
            }
            filenum--;
            if (filenum<0) break;
            fileindex = (VFrFileIndex*)(searchfiles->At(filenum));
         }  // end loop on files of a slot
      }
      if (nearesticond>=0) gosearch = 0;
      searchhashv++;
      if (searchhashv> mHashTable->GetCapacity()-1 && nearesticond<0) {
         Warning("FindNearestGECondIndex","Trying to access frame outside bounds of the Database");
         return -1;
      }
      slotbegin = mHashTable->GetSlotBegin(searchhashv);
      slotend   = mHashTable->GetSlotEnd(searchhashv);
   } // end loop on slots
      
   condbegin = begincok;
   condend = endcok;
   
   return nearesticond;
}

//______________________________________________________________________________
Int_t VFrameMetaDB::LoadNearestGECondition(Double_t gpstime, const char* name)
{
// Loads the condition "name" that is nearest next to the time "gpstime"
// The reference is the start time of the condition, i.e. the time of the
// maximum - timeBefore.
// If name = "*", loads all the present conditions. To load only relevant
// conditions, one should set the branches in the condition trees to active
// or inactive state.
// These conditions are loaded into variables internal to the database
// return the index.

   Int_t conditionnumber = mConditionNames->IndexOf(name);
   if (conditionnumber < 0) return -1;
   if (*name=='*') conditionnumber = -2;
   return LoadNearestGECondition(gpstime, conditionnumber);
}

//______________________________________________________________________________
Int_t VFrameMetaDB::LoadNearestGECondition(Double_t gpstime, Int_t conditionnumber)
{
// Loads the condition corresponding to number "conditionnumber",
// that is nearest next to the time "gpstime"
// The reference is the start time of the condition, i.e. the time of the
// maximum - timeBefore.
// If conditionnumber = -2, loads all the present conditions. To load only relevant
// conditions, one should set the branches in the condition trees to active
// or inactive state.
// These conditions are loaded into variables internal to the database
// return the index.
   
   Double_t beginc, endc;
   Int_t icond;
   TTree* conditiontree;
   
   icond=-1;
   if (conditionnumber==-2) {
      for (int i=0; i<mNConditions; i++) {
         conditiontree=(TTree*) mConditionTree->At(i);
         icond = FindNearestGECondIndex(mConditionNames->GetConditionName(i),gpstime, beginc, endc);
         if (icond>=0) conditiontree->GetEntry(icond);
         mCurCondTreeIndex[i]=icond;  // update the conditions tree indices
      }
   } else {
      conditiontree=(TTree*) mConditionTree->At(conditionnumber);
      icond = FindNearestGECondIndex(conditionnumber,gpstime, beginc, endc);
      if (icond>=0) conditiontree->GetEntry(icond);
      mCurCondTreeIndex[conditionnumber] = icond;
   }
   return icond;
}

//______________________________________________________________________________
Int_t VFrameMetaDB::LoadNextCondition(char* name)
{
// Loads the condition named "name" and nearest
// next one to the previously loaded. This method should only be called
// in conjunction with LoadNearestGECondition(). Using LoadNearestGECondition()
// in one function and LoadNextCondition() in another should be avoided in
// order to keep the consistency of the conditions loading.
// The condition is loaded into variables internal to the database
// return the index.

   Int_t conditionnumber = mConditionNames->IndexOf(name);
   if (conditionnumber<0) return -1;
   
   return LoadNextCondition(conditionnumber);
}

//______________________________________________________________________________
Int_t VFrameMetaDB::LoadNextCondition(Int_t conditionnumber)
{
// Loads the condition that is defined by "condition number" and nearest
// next one to the previously loaded. This method should only be called
// in conjunction with LoadNearestGECondition(). Using LoadNearestGECondition()
// in one function and LoadNextCondition() in another should be avoided in
// order to keep the consistency of the conditions loading.
// The condition is loaded into variables internal to the database
// return the index.
   
   Int_t previousgroup;
   Double_t gpstime;
   Int_t icond;
   
   if (mCurCondTreeIndex[conditionnumber] <0) return -1;
   TTree* conditiontree = (TTree*)mConditionTree->At(conditionnumber);
   if (mCurCondTreeIndex[conditionnumber] >= conditiontree->GetEntries()-1) return -1;
   
   gpstime = mTmpConditions[conditionnumber]->GetTime().GetTimeD() + mTmpConditions[conditionnumber]->GetTimeAfter();
   
// If the next entry in the tree corresponds to a condition with the same group
// number, then it is the right one. This is way faster than searching through
// the hash table.
   previousgroup = mTmpConditions[conditionnumber]->GetGroup();
   mCurCondTreeIndex[conditionnumber] ++;
   conditiontree->GetEntry(mCurCondTreeIndex[conditionnumber]);
   
   if (mTmpConditions[conditionnumber]->GetGroup() == previousgroup) return mCurCondTreeIndex[conditionnumber];
   
   icond = LoadNearestGECondition(gpstime+1e-4,conditionnumber);
   return icond;
}


//______________________________________________________________________________
VFrCondition* VFrameMetaDB::GetLoadedCondition(const char* name)
{
// Returns the condition "name" just loaded (have to do a 
// LoadNearestGECondition or LoadNextCondition() before calling this method
   
   Int_t conditionnumber = mConditionNames->IndexOf(name);
   return mTmpConditions[conditionnumber];
}

//______________________________________________________________________________
void VFrameMetaDB::Draw(const char* selexp, const char* selection, Option_t* option, Double_t start, Double_t length)
{
//   Draws expression selexp for conditions defined in the database
//   Builds a TGraph representing selexp over time, vetoed by selection
//
//   selexp is an expression (formula) referencing a combination of conditions
//   Example:
//      selexp = trig.amp   simplest case: draw a plot of amplitude of 
//                                          condition named trig
//             = sqrt(trig.p)            : draw distribution of sqrt(trig.p)
//             = x*y/z                   : where x, y and z are conditions
//                                         defined in the database
//   Note that selexp may contain a selection.
//   example, if selexp= x*(y<0), the value plotted will be x if y<0
//   and will be 0 otherwise.
// 
//   selection is an expression with a combination of the conditions.
//   In a selection all the C++ operators are authorized.
//   The value corresponding to the selection expression is used as a veto 
//   to plot the points. If it is not 0, the point is plotted.
//   The value returned is not relevant, only relevant is
//   (selection==0) -> point skipped or (selection!=0) -> point plotted
//
//   Examples:
//       selection1 = "x<y && sqrt(z)>3.2"
//       selection2 = "(x+y)*(sqrt(z)>3.2"
//   selection1 returns a value = 0 or 1
//   selection2 returns a value  = x+y if sqrt(z)>3.2
//              returns a value  = 0 otherwise.
//   Warning : if there is no selection (selection=""), selexp itself
//             will be taken as selection expression, i.e. only points where
//             selexp != 0 will be plotted
// 
//   option is the drawing option
//       see TGraph::Draw for the list of all drawing options.
// 
//   start is the start time of the first conditions to process
//      (default is beginning of database values)
//   length is the length in time of the data to process (default is all data)
//

   GetPlayer();
   if (mPlayer) {
      mPlayer->Draw(selexp, selection, option, start, length);
      return;
   }
   else {
      Warning("VFrameMetaDB::Draw","Couldn't open a player");
      return;
   }
}

//______________________________________________________________________________
void VFrameMetaDB::Print(Option_t* opt)
{
// Prints information about the database and it's contents
// option :
//     "full" : prints all the database info. VERY LONG. mainly for test
//     "conditions" : prints only conditions names

   TString sopt = opt;
   sopt.ToLower();

   printf("  ____________________________  n");
   printf(" |                            | n");
   printf(" | Frame information database | n");
   printf(" |____________________________| n");

// Prints trigger names if asked for
   if (!sopt.CompareTo("conditions", TString::kIgnoreCase)) {
      printf("nList of conditions present in this databasen");
      printf(  "___________________________________________n\n");
      mConditionNames->Print();
      return;
   }
      
// Gets the first frame
   printf("n  First frame start time (GPS) : %14.4fn",GetStart());
   printf("  =============================================n");
   printf("n  Global start time      (GPS) : %14.4fn",GetDBStart());
   printf("  Global end time        (GPS) : %14.4fn",GetDBEnd());
   if (sopt.Contains("full")) {
      GetDBHash()->Print("full");
      printf("n\n Scan of the Meta tree contents n");
      printf(    " ______________________________n\n");
      mMetaTree->Scan("mRunNumber:mFrameNumber:mGroup:mStartTime.mSec");
   } else {
      GetDBHash()->Print("small");
   }
}

//______________________________________________________________________________
VVirtualMetaDBPlayer *VFrameMetaDB::GetPlayer()
{
   // Load the VMetaDBPlayer (if not already done)
   // Pointer to player is mPlayer

   if (mPlayer) return mPlayer;
   mPlayer = VVirtualMetaDBPlayer::MetaDBPlayer(this);
   return mPlayer;
}

//______________________________________________________________________________
void VFrameMetaDB::GetMetaData(VMetaData* meta, Double_t gpstime)
{
// Retrieve the meta data corresponding to time
   
   Double_t beginf,endf;
   Int_t imeta;

   if (!mIsOpened) {
      Warning("GetMetaData","Data base not opened");
      meta->Clear();
      return;
   }

// Finds the index of the meta in the metadata tree
// returns also the begin and end time of the frame
   imeta = FindIndex(gpstime, beginf, endf);
   
   if (imeta < 0) {
      meta->Clear();
      return;
   }
   
   mCurMetaIndex = imeta;
   mCurFrameStart = beginf;
   mCurFrameEnd = endf;
      
// ---- Get the metadata and transfer it to VMetaData object ----

   mMetaTree->GetEntry(imeta);
   
   meta->SetRun(mTmpMeta->GetRunNumber());
   meta->SetFrame(mTmpMeta->GetFrameNumber());
   meta->SetStartTime(mTmpMeta->GetStartTime().GetTimeD());
   meta->SetLocalStartTime(0);
   meta->SetLength(mTmpMeta->GetLength());
   meta->SetQuality(mTmpMeta->GetQuality());
   meta->SetTrigger(mTmpMeta->GetTrigger());
   meta->SetFileName(mTmpMetaString->GetFileName().Data());
   meta->SetDetector(mTmpMetaString->GetDetector().Data());
   meta->SetState(mTmpMetaString->GetState().Data());
   
   return;
}

//______________________________________________________________________________
void VFrameMetaDB::NextMetaData(VMetaData* meta)
{
// Retrieve the next meta data

   Double_t beginf, endf;
   
   if (!mIsOpened) {
      Warning("NextMetaData","Data base not opened");
      meta->Clear();
      return;
   }
   
// First, search the metadata to see if the next meta is the right one
   if (meta->GetRun() == mTmpMeta->GetRunNumber() &&
       meta->GetFrame() == mTmpMeta->GetFrameNumber() &&
       !strcmp(meta->GetFileName(),mTmpMetaString->GetFileName().Data()) &&
       mCurMetaIndex+1 < mMetaTree->GetEntries()) {
      mMetaTree->GetEntry(mCurMetaIndex+1);
      beginf = mTmpMeta->GetStartTime().GetTimeD();
      endf = beginf + mTmpMeta->GetLength();
      if (beginf >= mCurFrameEnd && beginf < mCurFrameEnd+1e-4) {
         mCurMetaIndex++;
         mCurFrameStart = beginf;
         mCurFrameEnd = endf;
         meta->SetRun(mTmpMeta->GetRunNumber());
         meta->SetFrame(mTmpMeta->GetFrameNumber());
         meta->SetStartTime(mTmpMeta->GetStartTime().GetTimeD());
         meta->SetLocalStartTime(0);
         meta->SetLength(mTmpMeta->GetLength());
         meta->SetQuality(mTmpMeta->GetQuality());
         meta->SetTrigger(mTmpMeta->GetTrigger());
         meta->SetFileName(mTmpMetaString->GetFileName().Data());
         meta->SetDetector(mTmpMetaString->GetDetector().Data());
         meta->SetState(mTmpMetaString->GetState().Data());
         return;
      }
   }
   
   NextMetaData(meta,meta->GetEndTime()+1e-4);
   return;
}

//______________________________________________________________________________
void VFrameMetaDB::PreviousMetaData(VMetaData* meta)
{
// Retrieve the previous meta data

   Double_t beginf, endf;
   Int_t nearestimeta;
   
   if (!mIsOpened) {
      Warning("PreviousMetaData","Data base not opened");
      meta->Clear();
      return;
   }

// First, search the metadata to see if the previous meta is the good one
   if (meta->GetRun() == mTmpMeta->GetRunNumber() &&
       meta->GetFrame() == mTmpMeta->GetFrameNumber() &&
       !strcmp(meta->GetFileName(),mTmpMetaString->GetFileName().Data()) &&
       mCurMetaIndex > 0) {
      mMetaTree->GetEntry(mCurMetaIndex-1);
      beginf = mTmpMeta->GetStartTime().GetTimeD();
      endf = beginf + mTmpMeta->GetLength();
      if (endf <= mCurFrameStart && endf > mCurFrameStart-1e-4) {
         mCurMetaIndex--;
         mCurFrameStart = beginf;
         mCurFrameEnd = endf;
         meta->SetRun(mTmpMeta->GetRunNumber());
         meta->SetFrame(mTmpMeta->GetFrameNumber());
         meta->SetStartTime(mTmpMeta->GetStartTime().GetTimeD());
         meta->SetLocalStartTime(0);
         meta->SetLength(mTmpMeta->GetLength());
         meta->SetQuality(mTmpMeta->GetQuality());
         meta->SetTrigger(mTmpMeta->GetTrigger());
         meta->SetFileName(mTmpMetaString->GetFileName().Data());
         meta->SetDetector(mTmpMetaString->GetDetector().Data());
         meta->SetState(mTmpMetaString->GetState().Data());
         return;
      }
   }

   nearestimeta = FindNearestLEIndex(meta->GetStartTime().GetTimeD()-1e-4, beginf, endf);
   if (nearestimeta==-1) {
      meta->Clear();
      return;
   }

   mCurMetaIndex = nearestimeta;
   mCurFrameStart = beginf;
   mCurFrameEnd = endf;

// ---- Get the metadata and transfer it to VMetaData object ----

   mMetaTree->GetEntry(nearestimeta);
   
   meta->SetRun(mTmpMeta->GetRunNumber());
   meta->SetFrame(mTmpMeta->GetFrameNumber());
   meta->SetStartTime(mTmpMeta->GetStartTime().GetTimeD());
   meta->SetLocalStartTime(0);
   meta->SetLength(mTmpMeta->GetLength());
   meta->SetQuality(mTmpMeta->GetQuality());
   meta->SetTrigger(mTmpMeta->GetTrigger());
   meta->SetFileName(mTmpMetaString->GetFileName().Data());
   meta->SetDetector(mTmpMetaString->GetDetector().Data());
   meta->SetState(mTmpMetaString->GetState().Data());
   return;
}

//______________________________________________________________________________
void VFrameMetaDB::NextMetaData(VMetaData* meta, VConditionSet* condset0)
{
// Retrieve the next meta data with condition set

   Int_t gosearch;
   Int_t condgroup, nextcondgroup;
   Int_t approxindex;
   Double_t nextcostart;
   VGroupInfo* groupinfo;   // needed in case the group is the last one (not yet
                            // recorded in the group info tree)
   VConditionSetFMDB* condset;
      
   if (!mIsOpened) {
      Warning("NextMetaData","Data base not opened");
      meta->Clear();
      return;
   }
   
   if (!condset0) {
      Warning("NextMetaData","No condition set defined");
      meta->Clear();
      return;
   }

// Transform VConditionSet into VConditionSetFMDB
   condset = (VConditionSetFMDB*)condset0;
// First, search the condition trees to see if the next condition
// belongs to the same group as the previous one. If this is the case,
// it is much faster to search the metadata in the same group.
   
   condgroup = condset->GetGroup();
   gosearch = 1;
   while (gosearch) {
//   Jump to the next valid set of conditions
      if (!condset->NextFormSet()) {
         meta->Clear();
         return;
      }
      nextcondgroup = condset->GetGroup();
      if (condgroup == nextcondgroup) {  // if the same group of conditions
         int err = mGroupList->GetEntry(nextcondgroup); // Get info from the group list
         if (!err) {
//         if no group info loaded, means we are looking at the last
//         group info, wich is not yet recorded in the group info tree
            groupinfo = mLastGroupInfo;
         } else {
            groupinfo = mTmpGroupInfo;
         }
//     Get the approximate index of the right frame metadata
         nextcostart = condset->GetIntersectionStart();
         approxindex = groupinfo->ApproximateIndex(nextcostart);
//      Find the right index and return the frame
         mCurMetaIndex = FindIndex(approxindex, nextcostart);
         mMetaTree->GetEntry(mCurMetaIndex);
         mCurFrameStart = mTmpMeta->GetStartTime().GetTimeD();
         mCurFrameEnd = mCurFrameStart + mTmpMeta->GetLength();

// ---- Get the metadata and transfer it to VMetaData object ----

         mMetaTree->GetEntry(mCurMetaIndex);
   
         meta->SetRun(mTmpMeta->GetRunNumber());
         meta->SetFrame(mTmpMeta->GetFrameNumber());
         meta->SetStartTime(mTmpMeta->GetStartTime().GetTimeD());
         meta->SetLocalStartTime(0);
         meta->SetLength(mTmpMeta->GetLength());
         meta->SetQuality(mTmpMeta->GetQuality());
         meta->SetTrigger(mTmpMeta->GetTrigger());
         meta->SetFileName(mTmpMetaString->GetFileName().Data());
         meta->SetDetector(mTmpMetaString->GetDetector().Data());
         meta->SetState(mTmpMetaString->GetState().Data());
         return;
      } else {
         gosearch=0;
      }
   }
   NextMetaData(meta,condset->GetIntersectionStart()+1e-4);
   return;
}

//______________________________________________________________________________
void VFrameMetaDB::NextMetaData(VMetaData* meta, Double_t time, VConditionSet* condset0)
{
// Retrieve the next meta data after time "time" with condition set condset

   Int_t gosearch;
   Int_t condgroup, nextcondgroup;
   Int_t approxindex;
   Double_t nextcostart;
   VGroupInfo* groupinfo;   // needed in case the group is the last one (not yet
                            // recorded in the group info tree)
   VConditionSetFMDB* condset;
   
   
   if (!mIsOpened) {
      Warning("NextMetaData","Data base not opened");
      meta->Clear();
      return;
   }
   
   if (!condset0) {
      NextMetaData(meta,time);
      return;
   }

// Transform VConditionSet into VConditionSetFMDB
   condset = (VConditionSetFMDB*)condset0;
// First, search the condition trees to see if the next condition
// belongs to the same group as the previous one. If this is the case,
// it is much faster to search the metadata in the same group.
   
   condgroup = condset->GetGroup();
   gosearch = 1;
   while (gosearch) {
//   Jump to the next valid set of conditions
      if (!condset->NearestGEFormSet(time)) {
         meta->Clear();
         return;
      }
      nextcondgroup = condset->GetGroup();
      if (condgroup == nextcondgroup) {  // if the same group of conditions
         int err = mGroupList->GetEntry(nextcondgroup); // Get info from the group list
         if (!err) {
//         if no group info loaded, means we are looking at the last
//         group info, wich is not yet recorded in the group info tree
            groupinfo = mLastGroupInfo;
         } else {
            groupinfo = mTmpGroupInfo;
         }
//     Get the approximate index of the right frame metadata
         nextcostart = condset->GetIntersectionStart();
         approxindex = groupinfo->ApproximateIndex(nextcostart);
//      Find the right index and return the frame
         mCurMetaIndex = FindIndex(approxindex, nextcostart);
         mMetaTree->GetEntry(mCurMetaIndex);
         mCurFrameStart = mTmpMeta->GetStartTime().GetTimeD();
         mCurFrameEnd = mCurFrameStart + mTmpMeta->GetLength();

// ---- Get the metadata and transfer it to VMetaData object ----

         mMetaTree->GetEntry(mCurMetaIndex);
   
         meta->SetRun(mTmpMeta->GetRunNumber());
         meta->SetFrame(mTmpMeta->GetFrameNumber());
         meta->SetStartTime(mTmpMeta->GetStartTime().GetTimeD());
         meta->SetLocalStartTime(0);
         meta->SetLength(mTmpMeta->GetLength());
         meta->SetQuality(mTmpMeta->GetQuality());
         meta->SetTrigger(mTmpMeta->GetTrigger());
         meta->SetFileName(mTmpMetaString->GetFileName().Data());
         meta->SetDetector(mTmpMetaString->GetDetector().Data());
         meta->SetState(mTmpMetaString->GetState().Data());
         return;
      } else {
         gosearch=0;
      }
   }
   NextMetaData(meta,condset->GetIntersectionStart()+1e-4);
   return;
}

//______________________________________________________________________________
void VFrameMetaDB::NextMetaData(VMetaData* meta, Double_t gpstime, VConditionFormula* condf)
{
// Retrieve the next meta data with time greater or equal to "time"
// and selection condition
   Double_t beginfok,endfok,begincok, endcok;
   Int_t groupcok;
   Int_t nearestimeta;
   
   if (!mIsOpened) {
      Warning("GetNextMetaData","Data base not opened");
      meta->Clear();
      return;
   }

   nearestimeta = FindNearestGEIndex(gpstime, condf,
                                     beginfok, endfok, begincok,endcok, groupcok);
   if (nearestimeta==-1) {
      meta->Clear();
      return;
   }

   mCurMetaIndex = nearestimeta;
   mCurFrameStart = beginfok;
   mCurFrameEnd = endfok;

// ---- Get the metadata and transfer it to VMetaData object ----

   mMetaTree->GetEntry(nearestimeta);
   
   meta->SetRun(mTmpMeta->GetRunNumber());
   meta->SetFrame(mTmpMeta->GetFrameNumber());
   meta->SetStartTime(mTmpMeta->GetStartTime().GetTimeD());
   meta->SetLocalStartTime(0);
   meta->SetLength(mTmpMeta->GetLength());
   meta->SetQuality(mTmpMeta->GetQuality());
   meta->SetTrigger(mTmpMeta->GetTrigger());
   meta->SetFileName(mTmpMetaString->GetFileName().Data());
   meta->SetDetector(mTmpMetaString->GetDetector().Data());
   meta->SetState(mTmpMetaString->GetState().Data());
   
   return;
}

//______________________________________________________________________________
void VFrameMetaDB::NextMetaData(VMetaData* meta, Double_t gpstime, const char* selection)
{
// Retrieve the next meta data with time greater or equal to "time"
// and selection condition
   VConditionFormula* condf;
   
   if (!selection) {
      NextMetaData(meta, gpstime, (VConditionFormula*)0);
      return;
   }
   
   condf = new VConditionFormula("condf",selection,this);
   NextMetaData(meta,gpstime,condf);
   delete condf;
   return;
}

//______________________________________________________________________________
VConditionSet* VFrameMetaDB::CreateConditionSet(const char* condfs, const char* selfs)
{
// Creates a condition set adapted to this Frame Info DB
   VConditionSetFMDB* cs = new VConditionSetFMDB(this,condfs,selfs);
   return (VConditionSet*)cs;
}


- ROOT page - VEGA page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to , or contact with any questions or problems regarding ROOT or VEGA.