// TEventSample.cxx
// Author: Axel Naumann <mailto:axel@fnal.gov> 10/02/2001
//@(#) 10/02/2001

#include "TFile.h"
#include "TChain.h"
#include "TKey.h"
#include "TRandom.h"
#include "TProcessID.h"
#include "TEventSample.h"
#include "TSeed.h"
#include "TProcessEvent.h"
#include "TSeedList.h"
#include <climits>
#include <iostream>
#include <fstream>


Int_t seed::TEventSample::fNumWarnings=0;
Int_t seed::TEventSample::fNumErrors=0;

//_________________________________________________________________________________________________________________________
//
//      This class manages the data conversion from n-tuple to class objects as well
//  as the data stored in class objects themselves. See the documentation on SEED
// 
//  A short summary: To work with a seed::TEventSample you have to
//  1) write your own seed (deriving from seed::TSeedABC) which fills data from an n-tuple into a class 
//  2) create a seed::TEventSample from an n-tuple calling the seed::TEventSample::Create method using your seed::TSeed's
//  3) load it using the seed::TEventSample::Load method and read its data by means of the seed::TSeedData class
//


ClassImp(seed::TEventSample)

 seed::TEventSample::TEventSample():
    fTreeEvent(NULL),
    fDisableSetEntry(kFALSE),
    fNtupleFileName(NULL),
    fNtupleID(NULL),
    fSeedFileOption("NEW"),
    fSAFName("SeedActivation.ini"),
    fDebug(gDebug>1?gDebug:1),
    fFirstEntry(0),
    fNumEntries(-1),
    fUserParameter(NULL),
    fNtupleTree(NULL),
    fSaveSeedData(kTRUE),
    fProcessEvent(NULL),
    fCrossEventRefs(kFALSE),
    fFileCF(NULL)
{
// default constructor. Should only be called before seed::TEventSample::Create. 
// Otherwise use the static seed::TEventSample::Load which returns a
//  seed::TEventSample*

}

 seed::TEventSample::TEventSample(const seed::TEventSample & es)
{
// copy constructor. May not be used, as seed::TEventSample represents one TTree. 
// Use multiple references to one seed::TEventSample instead.

   Warning("seed::TEventSample::TEventSample(const seed::TEventSample &es)",
        "Copy constructor should not be called!");
   AddWarning();
}


 seed::TEventSample::~TEventSample()
{
// default destructor

   if (fFileCF) delete fFileCF;
   for (std::map < std::string, TClonesArray * >::iterator iMap =
        fMapCA.begin(); iMap != fMapCA.end(); iMap++) {
      if (iMap->second != NULL) {
         iMap->second->Delete();
      }
   };
   if (fDebug>0) {
     std::cout<<"This instances of TEventSample encountered"<<std::endl;
     std::cout<<"   "<<GetNumErrors()<<" errors and"<<std::endl;
     std::cout<<"   "<<GetNumWarnings()<<" warnings."<<std::endl<<std::endl;
   }
   ResetErrorCounter();
}

 Bool_t seed::TEventSample::SetEvent(const Int_t iEventIdx)
{
// Sets the event currently accessible by classes deriving from TSeedABC. 
// Only to be called when reading data, i.e. not during Create.
//
// Returns kFALSE if the event could not be selected.
//
// Parameters
//     iEventIdx:    Index of the event to select (see TTree::GetEntry). 

   if (fDisableSetEntry) {
       std::cout << "WARNING in seed::TEventSample::SetEvent(const Int_t): "
		 << "This method is currently disabled "
		 << "(e.g. because the TEventSample is being created)." << std::endl;
       AddWarning(); 
       return kFALSE;
   }
   if (iEventIdx < 0 || iEventIdx >= GetNEvents()) {
      std::cout << "ERROR in TEventSample::SetEvent: Event index " <<
          iEventIdx << " out of range!" << std::endl;
      AddError();
      return kFALSE;
   }

   if (fTreeEvent) fTreeEvent->GetEntry(iEventIdx);
   else return kFALSE;

   return kTRUE;
}

 TClonesArray * seed::TEventSample::GetClonesArray(const Char_t *strSeed)
{
// returns the address of the TClonesArray corresponding to a given seed / branch
// returns NULL if either the seed is unknown or no events have been read (TClonesArray 
// not yet initialized)
//
// Parameters
//     strSeed: Name of the Seed / branch

   if (fMapCA.find(strSeed) == fMapCA.end())
      return NULL;              // not a known seed
   return (fMapCA[strSeed]);
};


TClonesArray * const* seed::TEventSample::GetCAPtrAddr(const Char_t *strSeed)
{
// Returns the address of the TClonesArray pointer corresponding to a given seed / 
// branch. Returns NULL if either the seed is unknown or no events have been read 
// (TClonesArray not yet initialized)
//
// Parameters
//     strSeed: Name of the Seed / branch

   if (fMapCA.find(strSeed) == fMapCA.end())
      return NULL;              // not a known seed
   return &(fMapCA[strSeed]);
};


 Int_t seed::TEventSample::GetNumberOf(const Char_t *strSeed)
{
// returns the number of entries of a given seed (branch) in the current event
// returns -1 if the seed/branch does not exist (no entry in fMapCA)
// returns -2 if the seed/branch is not activated or not yet read (fPCAArray's entry is NULL)
//
// Parameters
//     strSeed: Name of the Seed / branch

   if (fMapCA.find(strSeed) == fMapCA.end())
      return -1;                // not found
   TClonesArray *pCA = fMapCA[strSeed];
   if (!pCA)
      return -2;                // not init
   return pCA->GetLast() + 1;
}

 Bool_t seed::TEventSample::SetupBranches()
{
// Creates a TClonesArray for each used branch in fTreeEvents and
// enables it via TTree::SetBranchStatus. The user can enable / disable branches
// in the seed activation file
//
// Returns kFALSE is branch setup was not successful

   if (!fTreeEvent) {
      std::cout<<"ERROR in TEventSample::SetupBranches: "
         << "fTreeEvent is not initialized. This should never happen, "
         << "please contact manufacturer."<<std::endl;
      AddError();
      return kFALSE;
   }

   Int_t iNumBranches = fTreeEvent->GetNbranches();

   fTreeEvent->SetBranchStatus("*", 0);
   for (Int_t iBranch = 0; iBranch < iNumBranches; iBranch++) {
      TBranch *pBranch =
          (TBranch *) (*(fTreeEvent->GetListOfBranches()))[iBranch];
      TString strBranch = pBranch->GetName();
      if (TSeedList::GetInstance()->IsSeedEnabled(strBranch)) {
         TClonesArray **pCA =
             CreateCA(TSeedList::GetInstance()->GetSeed(strBranch));
         fTreeEvent->SetBranchStatus(strBranch + "*", 1);
         fTreeEvent->SetBranchAddress(strBranch, pCA);
	 if (fDebug>1)
	   std::cout << "Told seed "<<strBranch<<" to read its branch."
		     << std::endl;
      } else if (fDebug>0)
	  std::cout << "Seed for Branch " << strBranch.Data() 
		    << " not enabled, skipped." << std::endl;
      pBranch->SetAutoDelete(kFALSE);
   };
   return kTRUE;
}

 TClonesArray **seed::TEventSample::CreateCA(seed::TSeedABC * pSeed)
{
// Creates a TClonesArray for the class given by pSeed's seed::TSeedABC::GetClassName 
// Internal method.
//
   std::string strSN = pSeed->GetName();
   if (fMapCA.find(strSN) == fMapCA.end())
      fMapCA[strSN] = new TClonesArray(pSeed->GetClassName());

   return &(fMapCA[strSN]);
};


 Bool_t seed::TEventSample::ParseSeedActivationFile(const Char_t *cSAFName)
{
// With the Seed Activation File (SAF) one can steer which seeds will be
// used in seed::TEventSample::Create() and seed::TEventSample::Load().
// All characters beyond a '#' in a line are ignored. Each word in the file
// outside the comments is assumed to be a seed to be activated.
// If the SAF is not found, all available seeds are activated. If one seed
// given in the SAF is not found (e.g. because it is not #include'd) a 
// warning is issued.
//
// This method can be called directly, superseding seeds activated by a 
// prior call to ParseSeedActivationFile, e.g. from withing 
// seed::TEventSample::Load or seed::TEventSample::Create.
//
// Returns kTRUE if all requested seeds are known
//
// Parameters:
//   cSAFName: Path and name of the seed activation file

   Bool_t bRet=kTRUE;

   // disable all seeds first
   TSeedList::GetInstance()->EnableAllSeeds(kFALSE);

   if (strlen(cSAFName)==0) {
       std::cout << "WARNING in TEventSample::ParseSeedActivationFile: "
		 << "No Seed Activation File given. Enabling all available TSeeds." 
		 << std::endl;
       TSeedList::GetInstance()->EnableAllSeeds();
       AddWarning(); 
       return kTRUE;
   }

   std::ifstream fstrSeed(cSAFName);
   if (fstrSeed.fail()) {
      std::cout << "Warning: TEventSample::ParseSeedActivationFile: Seed Activation File " <<
          cSAFName << " not found. Enabling all available TSeeds." << std::endl;
      TSeedList::GetInstance()->EnableAllSeeds();
      AddWarning(); 
      return kTRUE;
   } else
      while (!fstrSeed.fail()) {
         std::string strSeed;
         fstrSeed >> strSeed;
         if (strSeed.length() > 0 && strSeed.c_str()[0] != '#') {
	   if (!TSeedList::GetInstance()->EnableSeed(strSeed.c_str())) {
               std::cout <<
                   "Warning: TEventSample::ParseSeedActivationFile: Seed for object " <<
                   strSeed.c_str() << " not found. Skipped." << std::endl;
	       AddWarning(); 
	       bRet=kFALSE;
	   }
	 }
         else fstrSeed.ignore(INT_MAX, 'n');	// ignore until end of line
      }
   return bRet;
}

 Bool_t seed::TEventSample::ShowNtuple(const Char_t *strNTupleFileName,
                                    const Char_t *strNTupleID)
{
// Calls TTree::Print for a given ntuple in a given file.
//
// Parameters
//     strNTupleFileName:  name of the file containing the n-tuple.
//     strNTupleID:        name of the n-tuple in the file.
//
   TTree* pNtpl=GetNtupleFromFile(strNTupleFileName, strNTupleID);
   if (pNtpl) pNtpl->Print();
   return (pNtpl!=NULL);
}


 TTree* seed::TEventSample::GetNtupleFromFile(const Char_t *cNtupleFileName, 
					     const Char_t *cNtupleID,
					     Int_t debug)
{
// Extracts the n-tuple from the file and with the key name set by Create
// Internal method.

   TFile *fileNTP = TFile::Open(cNtupleFileName, "READ"); 

   if (fileNTP == NULL) {
      std::cout <<
          "ERROR: TEventSample::GetNtupleFromFile: Severe error trying to open the ntuple input file!"
          << std::endl;
      AddError();
      return NULL;
   }

   if (!fileNTP->IsOpen() || fileNTP->IsZombie()) {
      std::cout <<
          "ERROR: TEventSample::GetNtupleFromFile: Could not open input file '" <<
          cNtupleFileName << "'!" << std::endl;
      AddError(); 
      return NULL;
   }

   if (debug>1)
     std::cout<<"TEventSample::GetNtupleFromFile: Using file '"
	      <<cNtupleFileName<<"' as input file."<<std::endl;

   TKey *pKey=NULL;
   if (!cNtupleID || strlen(cNtupleID)==0)
      if (gDirectory->GetListOfKeys()==NULL){
         std::cout<<"ERROR in TEventSample::GetNtupleFromFile: No n-tuple ID given "
            <<"and no keys in file!"<<std::endl;
	 AddError(); 
	 return NULL;
      } else {
	TIter next(gDirectory->GetListOfKeys());
	TKey* pK;
	while (!pKey && (pK = (TKey*) next()))
	  if (strcmp(pK->GetClassName(),"TTree")==0) {
	    pKey = pK;
	    std::cout<<"TEventSample::GetNtupleFromFile: Selected key '"
		     << pK->GetName() <<"' as input tree."
		     << std::endl;
	  };
	if (!pKey) {
	  std::cout << "ERROR in TEventSample::GetNtupleFromFile: No key in "
		    << "the input file contains an object of type "
		    << "TTree. If you want to read an object of a "
		    << "type derived from TTree you have to specify "
		    << "this object's key name as second parameter "
		    << "for Create." << std::endl;
	  AddError(); 
	  return NULL;
	};
      }
   else {
      pKey = gDirectory->GetKey(cNtupleID);
      if (pKey == NULL) {
         std::cout << "ERROR in TEventSample::GetNtupleFromFile: Could not find entry '" <<
             cNtupleID << "' in input file!" << std::endl;
	 AddError(); 
	 return NULL;
      }
      else if (debug>0)
	std::cout<<"TEventSample::GetNtupleFromFile: Selected key '"
		 <<cNtupleID<<"' as input tree."<<std::endl;
   };

   TObject* pObj = pKey->ReadObj();

   if (!pObj) {
      std::cout << "ERROR in TEventSample::GetNtupleFromFile: Could not load n-tuple "
            << "from file, although its key exists!" << std::endl;
      AddError(); 
      return NULL;
   }

   if (! pObj->InheritsFrom("TTree")) {
      std::cout<<"ERROR in TEventSample::GetNtupleFromFile: Loaded n-tuple key does not "
         <<"reference a TTree (or a class deriving from it) but a "
         << pObj->ClassName() <<". Unable "
         <<"to handle this object as input."<<std::endl;
      AddError(); 
      return NULL;
   }

   return (TTree *) pObj;
}


 TString seed::TEventSample::Ntuple2SeedFileName(const Char_t * strNTupleFileName){
// Given a ntuple file name this method gives a root file name.
// It simply appends "root" to the n-tuple file name - only if the
// ntuple file name already ends on ".root" the resulting filename
// will end on ".seed.root".
// This method is used if SetOutputFileName was not called with a file name 
// before Create is called.

    TString s = strNTupleFileName;
    if (s.Index(".root", 5, s.Length()-5, TString::kExact)!=kNPOS)
	s.Insert(s.Length()-5, ".seed");
    else s+=".root";
    return s;
}


 TFile* seed::TEventSample::CreateOutputFile(){
// Creates the output file for the Create method.
// Internal method
//
// It uses the file name given by SetOutputFileName or generates
// it via Ntuple2SeedFileName. It uses TFile::Open with options
// set by SetOutputFileOption. This method deletes all prior 
// entries of keys with name "EventSample" from the file!

   if (fStrClassFileName.Length()==0)
       fStrClassFileName = Ntuple2SeedFileName(fNtupleFileName);

   TFile *fileCF =
       TFile::Open(fStrClassFileName, fSeedFileOption, "seedTEventSampleFile", 3);

   if (fileCF == NULL) {
      std::cout <<
          "Error: TEventSample::Create: Severe error trying to open the class output file!"
          << std::endl;
      AddError(); 
      return NULL;
   }

   if (!fileCF->IsOpen()) {
      std::cout <<
          "Error: TEventSample::Create: Could not open file '"
	       << fStrClassFileName.Data() <<"' with option '"
	       << fSeedFileOption << "'!" << std::endl;
      AddError(); 
      return NULL;
   }

   fileCF->Delete("EventSample;*");
   fileCF->Delete("EventSampleTree;*");
   return fileCF;
}

 seed::TEventSample * seed::TEventSample::Load(const Char_t *strRootFileName, const Char_t* cSAFName)
{
// ===========================================================================================================
//
//      Loads a seed::TEventSample created by seed::TEventSample::Create from a file.
//
// Opens a file, extracts the TEventSample and accesses data which belongs to activated seeds 
// (as given in the seed activation file, see ParseSeedActivationFile).
//
// Parameters
//     strRootFileName: name of the file containing the seed::TEventSample. Can contain 
//                      wildcards for loading multiple files, see TChain::Add for valid syntax
//     cSAFName:        name of the seed activation file (see ParseSeedActivationFile)
//
// ===========================================================================================================

   if (cSAFName) ParseSeedActivationFile(cSAFName);
   seed::TEventSample* pEventSample = new TEventSample();
   pEventSample->fTreeEvent = new TChain("EventSampleTree",
                           "TChain generated by the seed library");
   ((TChain*)pEventSample->fTreeEvent)->Add(strRootFileName);
   pEventSample->SetupBranches();

   return pEventSample;
}

 seed::TEventSample& seed::TEventSample::AddFile(const Char_t* strRootFileName){
// Adds another file for reading. To be call after Load. Syntax for 
// strRootFileName is the same as for TChain::Add
//
// Parameters
//   strRootFileName: Name of the files to add, for syntax see TChain::Add

    if (fTreeEvent->InheritsFrom("TChain"))
	((TChain*)fTreeEvent)->Add(strRootFileName);
    return *this;
}


 Bool_t seed::TEventSample::AddGlobalObject(const Char_t *cName, TObject * pObj)
{
// Adds an object to the file holding the TEventSample during Create phase.
//
// To be called before Create. The object will not be part of the tree. 
// It is global and thus independent of the current event / entry in the tree. 
// AddGlobalObject creates a new key in the output file, the object will be 
// written when the TEventSample is written (within Create).
//
// Parameters
//   cName: Name under which the object can be accessed with GetGlobalObject
//          (identical with the name of the key created in the output file for 
//          this object).
//   pObj:  Pointer to a TObject to be stored in the output file.

   fMapGlobalObjects[cName] = pObj;
   return true;
}


 TObject *seed::TEventSample::GetGlobalObject(const Char_t *cName) const
{
// Returns an entry in seed::TEventSample's file created by AddGlobalObject.
//
// Parameters
//   cName: Name of the object as given by AddGlobalObject (identical with its key name)

   TObject *pObj = GetCurrentFile()->FindObject(cName);
   if (pObj == NULL) {
      std::cout <<
          "WARNING in TEventSample::GetGlobalObject(const Char_t*): Object named "
          << cName << " not found!" << std::endl;
      AddWarning(); 
   }
   return pObj;
}


 Bool_t seed::TEventSample::Create(const Char_t *cNtupleFileName, const Char_t *cNtupleID){
// ===========================================================================================================
//
// Creates a TEventSample from an ntuple.
//
// See Set-methods for additional initializations of this method. Returns kFALSE if an error occurred.
//
// Parameters
//   cNtupleFileName: name of the file containing the n-tuple to be processed
//   cNtupleID:       optional key name of the n-tuple in the file. If not given (or NULL or ""),
//                    the first key of type TTree in the file is used.
//
// ===========================================================================================================

   fNtupleFileName = cNtupleFileName;
   fNtupleID = cNtupleID;
   Bool_t bChain=(strchr(cNtupleFileName, '*')!=NULL);
   if (bChain) {
       if (!cNtupleID || !strlen(cNtupleID)) {
	   std::cout<<"ERROR in TEventSample::Create: No n-tuple ID given, but"
		    <<" wildcarding used. Need an n-tuple ID to create a chain!"<<std::endl;
	   AddError();
	   fNtupleTree=NULL;
	   return kFALSE;
       } else {
	   fNtupleTree=new TChain(cNtupleID);
	   if (fNtupleTree) ((TChain*)fNtupleTree)->Add(cNtupleFileName);
       }
   } else
     fNtupleTree=GetNtupleFromFile(cNtupleFileName, cNtupleID, fDebug);
   if (!fNtupleTree) return kFALSE;
   Bool_t bReturn=Create(fNtupleTree);
   if (bChain) delete fNtupleTree;
   return bReturn;
}


 Bool_t seed::TEventSample::Create(TTree* pNtupleTree){
// ===========================================================================================================
//
// Creates a TEventSample from an ntuple.
//
// See Set-methods for additional initializations of this method.
//
// Parameters
//   pNtupleTree: pointer to a TTree which will be processed by TEventSample.
//                This pointer can also be a TChain* as TChain derives from 
//                TTree, allowing multiple TTrees to be processed.
//
// ===========================================================================================================


   if (fFileCF) delete fFileCF;

   // remove all CAs
   if (fTreeEvent) delete fTreeEvent;
   for (std::map < std::string, TClonesArray * >::iterator iMap = 
	  fMapCA.begin(); iMap != fMapCA.end(); iMap++) { 
     if (iMap->second != NULL) { 
       iMap->second->Delete(); 
     } 
   }; 
   fMapCA.clear();

   if (fSAFName) ParseSeedActivationFile(fSAFName);

   fFileCF = NULL;
   if (fSaveSeedData) {
       fFileCF = CreateOutputFile();
//       fTreeEvent->SetDirectory(fFileCF);
   };
   fTreeEvent = new TTree("EventSampleTree",
                           "TEventSample generated by the seed library");

   seed::TSeedList *pDFL = seed::TSeedList::GetInstance();
   if (pDFL == 0)
      return kFALSE;

   fNtupleTree = pNtupleTree;
   TSingleEntryTree seTree(*fNtupleTree, fUserParameter, &fMapUserParameters);
   seTree.SetDebug(fDebug);

   fTreeEvent->Reset();

   pDFL->StartFillPhase(this, &seTree, fTreeEvent);

   fNtupleTree->SetNotify(pDFL);
   TSeedList::GetInstance()->Notify();

   if (fFirstEntry != 0 && fDebug>0) 
     std::cout << "Skipping the first "<< fFirstEntry << " ntuple entries..." 
	       << std::endl;

   seTree.SetEntry(fFirstEntry); // to trigger TTree::Notify, TSeedABC::Init
   if (strlen(seTree.GetBranchesRead())){
       if (fDebug>1) {
	   std::cout<<"Disableing all branches in input tree."<<std::endl;
	   std::cout<<"TSingleEntryTree reports branches "
		    <<seTree.GetBranchesRead()<<" are requested by seeds. Enableing them:"<<std::endl;
       }
       fNtupleTree->SetBranchStatus("*",0);
       TBranch* pB;
       TIter nextB(fNtupleTree->GetListOfBranches());
       while((pB=(TBranch*)nextB()))
	   if (seTree.IsBranchRead(pB->GetName())) {
	       // can't go via pB in case of fNtupleTree being a TChain
	       fNtupleTree->SetBranchStatus(pB->GetName(),1);
	       if (fDebug>1) 
		   std::cout<<" - Re-enableing branch '"<<pB->GetName()<<"' in input tree."<<std::endl;
	   }
   }
   
   UInt_t iRefObjects=0;
   Bool_t bSaveAnyData=fSaveSeedData;
   Bool_t bGetEntrySuccess=kTRUE;
   Int_t iEntry = fFirstEntry;

   while(bGetEntrySuccess) {
      if (!fCrossEventRefs) iRefObjects=TProcessID::GetObjectCount();

      bGetEntrySuccess=(seTree.SetEntry(iEntry)>0);
      if (bGetEntrySuccess){

	pDFL->FillSeeds(iEntry-fFirstEntry);

	if (fProcessEvent != NULL) {
	  fDisableSetEntry = kTRUE;
	  fProcessEvent->Process(this, iEntry-fFirstEntry);
	  fDisableSetEntry = kFALSE;
	}

	if (fSaveSeedData) fTreeEvent->Fill();
	bSaveAnyData|=fSaveSeedData;

	if (!fCrossEventRefs) TProcessID::SetObjectCount(iRefObjects);

	if ((iEntry +1 - fFirstEntry) % 100 == 0 && fDebug>0 || fDebug>2)
	  std::
	  cout << "Processed entry " << iEntry+1-fFirstEntry 
	       << std::endl;
      }; // if bGetEntrySuccess
      iEntry++;
   }

   pDFL->GetNumberOfFilledObjects();
   pDFL->EndFillPhase();


   if (fDebug>0){
       std::cout <<"TEventSample::Create generated the following tree:" 
		 << std::endl;
       fTreeEvent->Print();
   };

   if (bSaveAnyData) {
       fFileCF->cd();

       Write("EventSample");
       fTreeEvent->Write("EventSampleTree");

       for (std::map < std::string, TObject * >::iterator iGOMap =
		fMapGlobalObjects.begin(); iGOMap != fMapGlobalObjects.end();
	    iGOMap++)
	   iGOMap->second->Write(iGOMap->first.c_str());
   }

   return kTRUE;
}


/********** Initialization methods for Create ***********/

 seed::TEventSample& seed::TEventSample::SetSeedActivationFile(const Char_t *cSAF){
// Sets the file to be parsed by ParseSeedActivationFile
    fSAFName = cSAF;
    if (fTreeEvent) { 
      // reading mode
      ParseSeedActivationFile(cSAF);
      SetupBranches(); // update enabled branches
    }
    return *this;
}

 seed::TEventSample& seed::TEventSample::SetOutputFileName(const Char_t *cSeedFileName){
// Sets the file name of the seed data (=output) file. Set the TFile
// option (new / append / recreate) by SetOutputFileOption.
//
// Parameters
//   cSeedFileName: Name of the file, see TFile::Open for available syntax

   fStrClassFileName = cSeedFileName;
   return *this;
}

 seed::TEventSample& seed::TEventSample::SetOutputFileOption(const Char_t *cOption){
// Sets the TFile::Open options (new / append / recreate) for the 
// seed data (=output) file.
//
// Parameters
//   cOption: Options, see TFile::Open

   TString strOpt = cOption;
   strOpt.ToUpper();
   if (!(strOpt == "NEW" || strOpt == "RECREATE" || strOpt == "UPDATE")) {
      std::cout <<
          "ERROR: TEventSample::SetOutputFileOption: " << fSeedFileOption 
		<<" is an unknown option for root file creation!"
		<< std::endl;
      AddError(); 
   }
   else fSeedFileOption = cOption;
   return *this;
}


 seed::TEventSample& seed::TEventSample::SetDebug(const Int_t iDebugLevel){
// Set the debug level for TEventSample. The higher the value, the more 
// debug information will be printed out (0 = off). If the value set by 
// this method would be lower than the global ROOT gDebug level, ROOT's
// gDebug level is assumed. Defaults to 1.
//
// Debug output for the different debug levels: 
// 0: No output, only the used seeds are printed
// 1: 0 + number and type of objects created, Print of resulting tree
// 2: 0+1 + trace of actions taken once for each conversion
// 3: 0+1+2 + trace of actions taken once for each entry
// 4: 0+1+2+3 + trace of actions taken once for each new object
//
// Parameters
//    iDebugLevel: level for debug information output.
//

    fDebug = (iDebugLevel<gDebug?gDebug:iDebugLevel);
    return *this;
}

 seed::TEventSample& seed::TEventSample::SetAuthor(const Char_t *cAuthor){
// Sets the author entry in this TEventSample's seed::TEventSampleInfo
// Parameters
//    cAuthor:  string to be passed to seed::TEventSampleInfo::SetAuthor

    fEsInfo.SetAuthor(cAuthor);
    return *this;
}

 seed::TEventSample& seed::TEventSample::SetFirstEntry(const Int_t iFirstEntry){
// Sets the index of the first entry in the n-tuple to be converted by Create
// Default value: 0
// Parameters
//    iFirstEntry: First entry in n-tuple to be converted by Create

    fFirstEntry = iFirstEntry;
    return *this;
}

 seed::TEventSample& seed::TEventSample::SetNEvents(const Int_t iNumEntries){
// Sets the number of entries in the n-tuple file to be converted by Create
// Forwarded to SetNumEntries.
// "-1" means "all". Default value: -1
// Parameters
//    iNumEntries: Number of entries in n-tuple file to be converted by 
//                 Create, "-1" means "all"
    return SetNumEntries(iNumEntries);
}

 seed::TEventSample& seed::TEventSample::SetNumEntries(const Int_t iNumEntries){
// Sets the number of entries in the n-tuple file to be converted by Create
// "-1" means "all". Default value: -1
// Parameters
//    iNumEntries: Number of entries in n-tuple file to be converted by 
//                 Create, "-1" means "all"

    fNumEntries = iNumEntries;
    return *this;
}

 seed::TEventSample& seed::TEventSample::SetUserParameter(void* pUserParameter){
// Sets the global "user parameter". It can be retrieved via
// seed::TSingleEntryTree::GetUserParameter(const Char_t*), which is
// accessible e.g. from within seed::TSeedABC::FillSeedData
// Parameters
//    pUserParameter: something that the use wants to have passed to seeds

    fUserParameter = pUserParameter;
    return *this;
}

 seed::TEventSample& seed::TEventSample::SetUserParameter(
    const Char_t* strSeed, void* pUserParameter){
// Sets the "user parameter" for a given seed. It can be retrieved via
// seed::TSingleEntryTree::GetUserParameter(const Char_t*), which is
// accessible e.g. from within seed::TSeedABC::FillSeedData
// Parameters
//    strSeed:        name of the seed
//    pUserParameter: something that the use wants to have passed to seeds
    fMapUserParameters[strSeed]=pUserParameter;
    return *this;
}

 seed::TEventSample& seed::TEventSample::SetSaveOutput(Bool_t bSave){
// If kTRUE (default), the output generated by Create will be saved to 
// file given by SetOutputFile.
//
// Parameters
//   bSave: kTRUE if output is to be saved.

    fSaveSeedData = bSave;
    return *this;
}


 seed::TEventSample& seed::TEventSample::SetCrossEventRefs(Bool_t bCER){
    fCrossEventRefs=bCER;
    return *this;
}


 seed::TEventSample& seed::TEventSample::SetProcessEvent(seed::TProcessEventABC *pProcessEvent){
// Sets the class deriving from seed::TProcessEventABC which will be used
// for on-the-fly processing of the generated seed data. This class has to
// be provided by the user, implementing the seed::TProcessEventABC::Process
// method. This method is called after each event that has been processed by
// Create allowing access to the generated seed data via seed::TSeedDataABC 
// derived classes (as defined by MAKE_SEED, see seed::TSeedABC).
//
// Parameters
//   pProcessEvent: Pointer to a TProcessEventABC derived class

    fProcessEvent = pProcessEvent;
    return *this;
}

 Bool_t seed::TEventSample::ReadSettings(const Char_t *cSettingsFile){
// Loads the settings from a text file to which it was saved by a prior
// call to SaveSettings. These settings will be used for the next Create 
// call.
//
// Parameters
//   cSettingsFile: name of the file storing settings for Create

    static Char_t cSeedFileOption[100];
    static Char_t cSAF[1024];

    std::ifstream fstr(cSettingsFile);
    if (fstr.fail()) {
	std::cout << "Warning in TEventSample::SaveSettings: "
		  << "Could not open input file '" 
		  << cSettingsFile << "'." << std::endl;
	AddWarning(); 
	return kFALSE;
    };
    while (!fstr.fail()) {
	std::string word;
	fstr >> word;
	if (word.length() > 0 && word.c_str()[0] != '#') {
	    if (word.find("SeedFileOption")==0) {
		fstr >> word;
		if (word==":") fstr>>word;
		if (word.find(":")==0) word=word.substr(1);
		strcpy((Char_t*) &cSeedFileOption, word.c_str());
		fSeedFileOption=(Char_t*) &cSeedFileOption;
		std::cout << "SeedFileOption set to '" << fSeedFileOption 
			  <<"'"<<std::endl;
	    }
	    else if (word.find("SeedActivationFile")==0 
		     || word.find("SAF")==0) {
		fstr >> word;
		if (word==":") fstr>>word;
		if (word.find(":")==0) word=word.substr(1);
		strcpy((Char_t*) &cSAF, word.c_str());
		fSAFName=(Char_t*) &cSAF;
		std::cout << "SeedActivationFile set to '" << fSAFName 
			  <<"'"<<std::endl;
	    }
	    else if (word.find("Debug")==0) {
		fstr >> word;
		if (word==":") fstr>>word;
		if (word.find(":")==0) word=word.substr(1);
		fDebug=atoi(word.c_str());
		std::cout << "Debug set to " << fDebug 
			  <<std::endl;
	    }
	    else if (word.find("FirstEntry")==0) {
		fstr >> word;
		if (word==":") fstr>>word;
		if (word.find(":")==0) word=word.substr(1);
		fFirstEntry=atoi(word.c_str());
		std::cout << "FirstEntry set to " << fDebug 
			  <<std::endl;
	    }
	    else if (word.find("NumEntries")==0) {
		fstr >> word;
		if (word==":") fstr>>word;
		if (word.find(":")==0) word=word.substr(1);
		fNumEntries=atoi(word.c_str());
		std::cout << "NumEntries set to " << fDebug 
			  <<std::endl;
	    }
	    else if (word.find("SaveSeedData")==0) {
		fstr >> word;
		if (word==":") fstr>>word;
		if (word.find(":")==0) word=word.substr(1);
		std::string WORD=word;
		if (WORD.find("TRUE")!=std::string::npos
		    || WORD.find("true")!=std::string::npos)
		    fSaveSeedData=kTRUE;
		else if (WORD.find("FALSE")!=std::string::npos
		    || WORD.find("false")!=std::string::npos)
		    fSaveSeedData=kFALSE;
		else fNumEntries=atoi(word.c_str());
		std::cout << "NumEntries set to " << (fNumEntries?"kTRUE":"kFALSE")
			  <<std::endl;
	    }
	    else if (word.find("CrossEventRefs")==0) {
		fstr >> word;
		if (word==":") fstr>>word;
		if (word.find(":")==0) word=word.substr(1);
		std::string WORD=word;
		if (WORD.find("TRUE")!=std::string::npos
		    || WORD.find("true")!=std::string::npos)
		    fCrossEventRefs=kTRUE;
		else if (WORD.find("FALSE")!=std::string::npos
		    || WORD.find("false")!=std::string::npos)
		    fCrossEventRefs=kFALSE;
		else fNumEntries=atoi(word.c_str());
		std::cout << "CrossEventRefs set to " << (fCrossEventRefs?"kTRUE":"kFALSE")
			  <<std::endl;
	    }
		 
	} 
	else fstr.ignore(INT_MAX, 'n');	// ignore until end of line
    };
 
    return kTRUE;
}

 Bool_t seed::TEventSample::SaveSettings(const Char_t *cSettingsFile){
// Saves all settings set via the seed::TEventSample::Set___ methods 
// to a file. These settings can be re-used by ReadSettings.
// Settings that are stored are:
//
//   fSeedFileOption (see SetOutoutFileOption)
//   fSAFName (see SetSeedActivationFile)
//   fDebug (see SetDebug)
//   fFirstEntry (see SetFirstEntry)
//   fNumEntries (see SetNumEntries)
//   fSaveSeedData (see SetSaveOutput)
//
// Parameters
//   cSettingsFile: name of the file in which settings should be stored

    
    std::ofstream fstr(cSettingsFile);
    if (fstr.fail()) {
	std::cout << "Warning in TEventSample::SaveSettings: "
		  << "Could not open output file '" 
		  << cSettingsFile << "'." << std::endl;
	AddWarning(); 
	return kFALSE;
    };
    fstr<<"# "; // to comment first = title line
    fstr<<"--- TEventSample initialization settings ---"<<std::endl;
    fstr<<" SeedFileOption: " << fSeedFileOption << std::endl;
    fstr<< " SeedActivationFile: " << fSAFName << std::endl;
    fstr<< " Debug: " << fDebug << std::endl;
    fstr<< " FirstEntry: " << fFirstEntry << std::endl;
    fstr<< " NumEntries: " << fNumEntries << std::endl;
    fstr<< " SaveSeedData: " << (fSaveSeedData?"kTRUE":"kFALSE") << std::endl;
    fstr<< " CrossEventRefs: " << (fCrossEventRefs?"kTRUE":"kFALSE") << std::endl;


    return kTRUE;
}

 seed::TEventSample& seed::TEventSample::PrintSettings(){
// Prints current settings for Create as set by 
// seed::TEventSample::Set___ (or their default values).
// These settings will be used in the next call of the Create method.

    std::cout<<"--- TEventSample initialization settings ---"<<std::endl;
    std::cout<<" SeedFileOption: " << fSeedFileOption << std::endl;
    std::cout<< " SeedActivationFile: " << fSAFName << std::endl;
    std::cout<< " Debug: " << fDebug << std::endl;
    std::cout<< " FirstEntry: " << fFirstEntry << std::endl;
    std::cout<< " NumEntries: " << fNumEntries << std::endl;
    std::cout<< " SaveSeedData: " << (fSaveSeedData?"kTRUE":"kFALSE") << std::endl;
    std::cout<< " CrossEventRefs: " << (fCrossEventRefs?"kTRUE":"kFALSE") << std::endl;

    return *this;
}


 Bool_t seed::TEventSample::MakeSeed(const Char_t *cNtupleFileName, 
				    const Char_t *cNtupleID, 
				    const Char_t *cBranch,
				    const Char_t *cSeedName,
				    const Char_t *cDataClass) {
// Create a seed source and header file nor a given ntuple.
//
// Comments in the form '[[[ TEXT ]]]' will be created in the source to 
// show code that needs to be adopted. The created code will not compile 
// before these changes are made. The number of changes necessary varies 
// depending on the information (number of valid parameters) passed to 
// MakeSeed (only two changes in case all parameters are given).
// 
// Parameters
//    cNtupleFileName,
//    cNtupleID:   from the file cNtupleFileName, load the ntuple with key 
//                 name cNtupleID (Default for cNtupleID: NULL: load the 
//                 TTree in the file. See GetNtupleFromFile.) All leaves 
//                 of this tree will be available to the seed.
//    cBranch:     only leaves in this branch will be available to the seed 
//                 (Default: NULL: all branches in ntuple)
//    cSeedName:   name of the seed that will be created. It reflects both
//                 class name and file name. (Default: "TMySeed")
//    cDataClass:  name of the class where the ntuple data should be
//                 transferred to (data class). (Default: NULL: create 
//                 comments where to change the created skeleton)
//

    TTree* pNtpl=GetNtupleFromFile(cNtupleFileName, cNtupleID);
    if (pNtpl) return MakeSeed(pNtpl, cBranch, cSeedName, cDataClass);
    else return kFALSE;

}
 Bool_t seed::TEventSample::MakeSeed(TTree* pNtupleTree,
				    const Char_t *cBranch,
				    const Char_t *cSeedName,
				    const Char_t *cDataClass) {
// Create a seed source and header file nor a given ntuple.
//
// Comments in the form '[[[ TEXT ]]]' will be created in the source to 
// show code that needs to be adopted. The created code will not compile 
// before these changes are made. The number of changes necessary varies 
// depending on the information (number of valid parameters) passed to 
// MakeSeed (only two changes in case all parameters are given).
// 
// Parameters
//    pNtupleTree: if given, all leaves of this ntuple will be available 
//                 to the seed (Default: NULL: generate a skeleton 
//                 independent of leaves)
//    cBranch:     only leaves in this branch will be available to the seed 
//                 (Default: NULL: all branches in ntuple pNtupleTree)
//    cSeedName:   name of the seed that will be created. It reflects both
//                 class name and file name. (Default: "TMySeed")
//    cDataClass:  name of the class where the ntuple data should be
//                 transferred to (data class). (Default: NULL: create 
//                 comments where to change the created skeleton)
//

    if (!pNtupleTree && cBranch) {
	std::cout<<"WARNING in TEventSample::MakeSeed: "
		 <<"Branch requested but no ntuple given, can't parse "
		 <<"content of branch without an ntuple. Will create "
		 <<"empty seed template instead."<<std::endl;
	AddWarning(); 
    }


    TString strSeedName;
    if (cSeedName) strSeedName=cSeedName;
    else strSeedName="TMySeed";

    std::ofstream fsHeader(strSeedName+".h");
    if (fsHeader.fail()) {
	std::cout<<"ERROR in TEventSample::MakeSeed: "
		 <<"failed to open header output file '"
		 <<strSeedName<<".h' . Maybe the file "
		 <<"already exists or you don't have write permission. "
		 <<std::endl;
	AddError(); 
	return kFALSE;
    }

    std::ofstream fsSource(strSeedName+".cxx");
    if (fsSource.fail()) {
	std::cout<<"ERROR in TEventSample::MakeSeed: "
		 <<"failed to open source output file '"
		 <<strSeedName<<".cxx'. Maybe the file "
		 <<"already exists or you don't have write permission. "
		 <<std::endl;
	AddError(); 
	return kFALSE;
    }


    // create ifdef include precompiler statement using a unique ID
    Char_t cArr[20];
    TRandom rnd;
    rnd.SetSeed(0);

    for (Int_t iChar=0; iChar<19; iChar++)
	cArr[iChar]=rnd.Integer(26)+65;
    cArr[19]=0;

    TDatime datime;
    
    fsHeader<<"#ifndef _INCLUDE__"<<cArr<<std::endl
	    <<"#define _INCLUDE__"<<cArr<<std::endl
	    <<std::endl
	    <<"#include "TSeed.h""<<std::endl
	    <<"#include [[[ include file for "
	    << (cDataClass?cDataClass:"your data class")<<" ]]]"<<std::endl
	    <<std::endl
	    <<"// Seed generated by TEventSample::MakeSeed"<<std::endl
	    <<"// on "<<datime.AsSQLString()<<std::endl;
    if (pNtupleTree)
	fsHeader<<"// for tree "<<pNtupleTree->GetName()<<std::endl;
    if (cBranch)
	fsHeader<<"// and only for branch "<<cBranch<<std::endl;
	    
    fsHeader<<"class "<<strSeedName<<": public seed::TSeed< "
	    <<(cDataClass?cDataClass:"[[[ your data class ]]]")
	    <<" > {"<<std::endl
	    <<" public: "<<std::endl
	    <<"  "<<strSeedName<<"(seed::TEventSample* pES=NULL): "<<std::endl
	    <<"      seed::TSeed< "
	    <<(cDataClass?cDataClass:"[[[ your data class ]]]")
	    <<" > (""<<strSeedName<<"", pES) {}"<<std::endl
	    <<"  virtual ~"<<strSeedName<<"(){}"<<std::endl
	    <<"  Bool_t Init(seed::TSingleEntryTree& tree);"<<std::endl
	    <<"  Bool_t FillSeedData(seed::TSingleEntryTree &tree, "
	    <<"const Int_t iEventNo);"<<std::endl
	    <<std::endl
	    <<" private:"<<std::endl
	    <<"// data members storing ntuple data of the current event"<<std::endl
	    <<"// the comments are for your information and not needed by Seed"<<std::endl
	    <<"// you can remove any member you do not need, as long as you "<<std::endl
	    <<"// also remove the corresponding Transfer request in the source."<<std::endl
	    <<std::endl;

    fsSource<<"#include ""<<strSeedName<<".h""<<std::endl
	    <<std::endl
	    <<"Bool_t "<<strSeedName<<"::Init(seed::TSingleEntryTree& tree) {"<<std::endl
	    <<"// request data transfer from ntuple to members"<<std::endl
	    <<std::endl
	    <<"  Bool_t bRet=kTRUE;"<<std::endl;
		

    Bool_t bGeneric = (!pNtupleTree);
    if (!bGeneric) {
	if (cBranch) {
	    TBranch *pB=pNtupleTree->GetBranch(cBranch);
	    if (!pB) {
		std::cout<<"WARNING in TEventSample::MakeSeed: "
			 <<"Branch requested not found in ntuple, can't parse "
			 <<"content of branch. Will create Seed for"
			 <<"the complete ntuple instead."<<std::endl;
		AddWarning(); 
		cBranch=NULL;
	    } else 
		MakeSeed_Branch(fsHeader, fsSource, pB);
	}

	if (!cBranch) {
	    TObjArray *branches=pNtupleTree->GetListOfBranches();

	    if (branches) {
		TIter nextB(branches);
		TBranch* pB;
		while ((pB=(TBranch*)nextB())) {
		    MakeSeed_Branch(fsHeader, fsSource, pB);
		};
	    } // if valid branches
	} // if !cBranch
	
    } // if !bGeneric

    /* can't use else, as maybe branches were not found and we want
       a template although pNtupleTree was specified */
    if (bGeneric) {
	fsHeader<<" [[[ Put data members here                                            ]]] "<<std::endl
		<<" [[[ One member for each ntuple leaf you want read out                ]]] "<<std::endl
		<<" [[[ Call TEventSample::MakeSeed with an ntuple to generate this part ]]] "<<std::endl
		<<std::endl;

	fsSource<<" [[[ Put tree.Transfer calls here                                       ]]] "<<std::endl
		<<" [[[ They request members to be updated with ntuple data for each event ]]] "<<std::endl
		<<" [[[ Call TEventSample::MakeSeed with an ntuple to generate this part   ]]] "<<std::endl
		<<std::endl;
    } // if bGeneric

    fsHeader<<"}; "<<std::endl
	    <<std::endl
	    <<" // needed to register this seed with the framework"<<std::endl
	    <<" namespace { static "<<strSeedName<<" _global_static_"<<strSeedName<<"; } "<<std::endl
	    <<std::endl
	    <<"#endif "<<std::endl
	    <<std::endl;

    fsSource<<"  return bRet;"<<std::endl
	    <<"} "<<std::endl
	    <<std::endl
	    <<"Bool_t "<<strSeedName<<"::FillSeedData(seed::TSingleEntryTree &tree, "
	    <<"const Int_t iEventNo) {"<<std::endl
	    <<"// create objects ";
    if (cDataClass) fsSource<<"of type "<<cDataClass<<" ";
    fsSource<<"by calling 'NewEntry()' "<<std::endl
	    <<"// and initialize them using the members that are defined in "<<std::endl
	    <<"// the header and filled in Init."<<std::endl
	    <<std::endl;
    if (cDataClass) fsSource<<"// Example: "<<std::endl
			    <<"  "<<cDataClass<<"* pEntry = NewEntry();"<<std::endl
			    <<"  pEntry->Set(...);"<<std::endl
			    <<std::endl;
    fsSource<<"  return kTRUE;"<<std::endl
	    <<"} "<<std::endl
	    <<std::endl;

    std::cout<<"Created Seed "<<strSeedName<<" in files "<<strSeedName
	     <<".h and "<<strSeedName<<".cxx"<<std::endl
	     <<std::endl;

    return kTRUE;
}

 TFile* seed::TEventSample::GetCurrentFile() const {
    if (fTreeEvent->InheritsFrom("TChain"))
	return ((TChain*)fTreeEvent)->GetFile();
    else 
	if (fTreeEvent->GetDirectory())
	    return fTreeEvent->GetDirectory()->GetFile();
	else return NULL;
};

 Bool_t seed::TEventSample::MakeSeed_Branch(
    std::ofstream &fsHeader, std::ofstream &fsSource, 
    TBranch* pB) {
// internal method, used by MakeSeed
// creates all entries in fsHeader and fsSource for 
// all leafs and branches for current branch

    TObjArray* pLeaves=pB->GetListOfLeaves();
    if (pLeaves && pLeaves->GetEntriesFast()) {
    
	if (pLeaves->GetEntriesFast()>1){
	    fsSource<<std::endl;
	    fsHeader<<"  // branch "<<pB->GetName()<<std::endl;
	}

	if (pLeaves->GetEntriesFast()>1)
	    fsSource<<"  bRet&= tree.SetBranch(""<<pB->GetName()<<"");"<<std::endl;

	TIter nextL(pLeaves);
	TLeaf* pL;
	while ((pL=(TLeaf*)nextL()))
	    MakeSeed_Leaf(fsHeader, fsSource, pL, 
			  pLeaves->GetEntriesFast());
    } // if there are leaves

    TObjArray *pBranches=pB->GetListOfBranches();
    if (pBranches) {
	TIter nextb(pBranches);
	TBranch* pIB;
	while ((pIB=(TBranch*)nextb())) 
	    MakeSeed_Branch(fsHeader, fsSource, pIB);
    }

    if (pLeaves && pLeaves->GetEntriesFast()>1){
	// top branch
	fsSource<<std::endl;
	fsHeader<<std::endl;
    };
    return kTRUE;
}

 Bool_t seed::TEventSample::MakeSeed_Leaf(
    std::ofstream &fsHeader, std::ofstream &fsSource, 
    TLeaf* pL, Int_t iNumLeaves) {

    TString strLName;
    strLName+=pL->GetName();
    if (pL->GetBranch() 
	&& ! strLName.Contains(pL->GetBranch()->GetName()))
	strLName.Prepend(pL->GetBranch()->GetName());
    strLName.ReplaceAll('.','_');
    if (strLName.Data()[0]>='a' && strLName.Data()[0]<='z') 
	strLName.Replace(0,1,strLName.Data()[0]+64);
    strLName.Prepend('f');

    TString strType(pL->GetTypeName());

    TString strSize;
    Int_t iCountVal;
    TLeaf* pLC=pL->GetLeafCounter(iCountVal);
    // here are the cases:
    // leaf; -> pLC==NULL, iCountVal==1;
    // leaf[12]; -> pLC==NULL, iCountVal==12;
    // leaf[otherleaf]; -> pLC==&otherleaf; iCountVal==1
    // leaf[12][otherleaf]; -> pLC==&otherleaf; iCountVal==12

    if (pLC || iCountVal>1) strSize="[";
    if (pLC) strSize+=pLC->GetName();
    else if (iCountVal>1) strSize+=iCountVal;
    if (pLC || iCountVal>1) strSize+="]";

    // this string is == strLName, expect for leaf[12][otherleaf]:
    // to get a * as argument for Transfer we give leaf[0].
    TString strLRefName=strLName;
    Int_t iSize=1;

    // now modify the type in case we have an array
    if (pLC || iCountVal>1) {
	iSize*=(pLC?pLC->GetMaximum():iCountVal);
	strLName+="[";
	strLName+=iSize;
	strLName+="]";
	strLRefName+="[0]";
    };
    // again, in case we have a 2dim array (fixed second length)
    if (pLC && iCountVal>1) {
	iSize*=iCountVal;
	strLName+="[";
	strLName+=iCountVal;
	strLName+="]";
	strLRefName+="[0]";
    };

    // assume max len = strlen("Double_t ") == 9
    strType.Append(' ', 10-strType.Length());
    fsHeader<<strType;
    fsHeader<<"  "<<strLName<<"; ";
    if (strSize.Length()) fsHeader<<"// "<<strSize;
    fsHeader<<std::endl;

    fsSource<<"  bRet&= tree.Transfer("<<strLRefName<<", ""<<pL->GetName();
    if (iNumLeaves==1) {
	fsSource<<"", "";
	if (pL->GetBranch())
	    fsSource<<pL->GetBranch()->GetName();
	else fsSource<<"[[BRANCHNAME]]";
    };
    fsSource<<"", "<<iSize<<");"<<std::endl;
    return kTRUE;
}

 Bool_t seed::TEventSample::EnableSeed(const Char_t* cSeed, Bool_t bEnable){
// enables / disables seeds.
// Disableing even works while processing input, it removes 
// already existing output by the seed from the output tree

    if (!cSeed) return kFALSE;
    seed::TSeedList::GetInstance()->EnableSeed(cSeed, bEnable);
    // if we already have a tree (which is at least slightly filled) then
    // copy only the part of the tree that will be filled by seeds
    if (fTreeEvent && !bEnable && fTreeEvent->GetEntries()>0){
	fTreeEvent->SetBranchStatus("*",1);
	TString strBranch(cSeed);
	strBranch+="*";
	fTreeEvent->SetBranchStatus(strBranch,0);
	TTree* pTemp=fTreeEvent->CloneTree();
	delete fTreeEvent;
	fTreeEvent=pTemp;
    }
    return kTRUE;
}

 void seed::TEventSample::AddWarning() { fNumWarnings++; } 
 void seed::TEventSample::AddError() { fNumErrors++; } 
 Int_t seed::TEventSample::GetNumWarnings() { return fNumWarnings; } 
 Int_t seed::TEventSample::GetNumErrors() { return fNumErrors; } 
 void seed::TEventSample::ResetErrorCounter() { fNumWarnings = fNumErrors = 0; } 
 


ROOT 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 ROOT support, or contact the developers with any questions or problems regarding ROOT.