// @(#)root/treeplayer:$Name:  $:$Id: TSelector.cxx,v 1.14 2003/12/19 09:31:52 brun Exp $
// Author: Rene Brun   05/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// A TSelector object is used by the TTree::Draw, TTree::Scan,            //
//  TTree::Loop, TTree::Process to navigate in a TTree and make           //
//  selections.                                                           //
//                                                                        //
//  The following members functions are called by the TTree functions.    //
//    Init:        Attach a new TTree during the loop                     //
//    Begin:       called everytime a loop on the tree(s) starts.         //
//                 a convenient place to create your histograms.          //
//                                                                        //
//    Notify():    This function is called at the first entry of a new    //
//                 tree in a chain.                                       //
//    ProcessCut:  called at the beginning of each entry to return a flag //
//                 true if the entry must be analyzed.                    //
//    ProcessFill: called in the entry loop for all entries accepted      //
//                 by Select.                                             //
//    Terminate:   called at the end of a loop on a TTree.                //
//                 a convenient place to draw/fit your histograms.        //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TSystem.h"
#include "TTree.h"
#include "THashList.h"
#include "TError.h"
#include "TSelectorCint.h"
#include "Api.h"

ClassImp(TSelector)

//______________________________________________________________________________
TSelector::TSelector() : TObject()
{
   // Default selector ctor.

   fStatus = 0;
   fObject = 0;
   fInput  = 0;
   fOutput = new THashList;
   fOutput->SetOwner();
}

//______________________________________________________________________________
TSelector::~TSelector()
{
   // Selector destructor.

   delete fOutput;
}


//______________________________________________________________________________
TSelector *TSelector::GetSelector(const char *filename)
{
//   The code in filename is loaded (interpreted or compiled , see below)
//   filename must contain a valid class implementation derived from TSelector,
//   where TSelector has the following member functions:
//
//     void TSelector::Init(TTree *t). Called every time a new TTree is attached.
//     void TSelector::Begin(). This function is called before looping on the
//          events in the Tree. The user can create his histograms in this function.
//
//     Bool_t TSelector::Notify(). This function is called at the first entry
//          of a new file in a chain.
//
//     Bool_t TSelector::Process(Int_t entry). This function is called
//          to process an event. It is the user's responsability to read
//          the corresponding entry in memory (may be just a partial read).
//          Once the entry is in memory one can apply a selection and if the
//          event is selected histograms can be filled. Processing stops
//          when this function returns kFALSE. This function combines the
//          next two functions in one, avoiding to have to maintain state
//          in the class to communicate between these two funtions.
//          See WARNING below about entry.
//          This method is used by PROOF.
//     Bool_t TSelector::ProcessCut(Int_t entry). This function is called
//          before processing entry. It is the user's responsability to read
//          the corresponding entry in memory (may be just a partial read).
//          The function returns kTRUE if the entry must be processed,
//          kFALSE otherwise. See WARNING below about entry.
//     void TSelector::ProcessFill(Int_t entry). This function is called for
//          all selected events. User fills histograms in this function.
//           See WARNING below about entry.
//     void TSelector::Terminate(). This function is called at the end of
//          the loop on all events.
//
//   WARNING when a selector is used with a TChain: 
//    in the Process, ProcessCut, ProcessFill function, you must use
//    the pointer to the current Tree to call GetEntry(entry).
//    entry is always the local entry number in the current tree.
//    Assuming that fChain is the pointer to the TChain being processed,
//    use fChain->GetTree()->GetEntry(entry);
//
//   If filename is of the form file.C, the file will be interpreted.
//   If filename is of the form file.C++, the file file.C will be compiled
//      and dynamically loaded. The corresponding binary file and shared
//      library will be deleted at the end of the function.
//   If filename is of the form file.C+, the file file.C will be compiled
//      and dynamically loaded. At next call, if file.C is older than file.o
//      and file.so, the file.C is not compiled, only file.so is loaded.
//
//   The static function returns a pointer to a TSelector object

   // If the filename does not contain "." assume class is compiled in
   char localname[256];
   Bool_t fromFile = kFALSE;
   if ( strchr(filename, '.') != 0 ) {

      //Interpret/compile filename via CINT
      sprintf(localname,".L %s",filename);
      gROOT->ProcessLine(localname);
      fromFile = kTRUE;
   }

   //loop on all classes known to CINT to find the class on filename
   //that derives from TSelector
   const char *basename = gSystem->BaseName(filename);
   if (basename==0) {
      ::Error("TSelector::GetSelector","Unable to determine the classname for file %s",filename);
      return 0;
   }
   strcpy(localname,basename);
   Bool_t  isCompiled = !fromFile || strchr(localname,'+') != 0 ;
   char *dot        = strchr(localname,'.');
   if (dot) dot[0] = 0;

   G__ClassInfo cl;
   Bool_t OK = kFALSE;
   while (cl.Next()) {
      if (strcmp(cl.Name(),localname)) continue;
      if (cl.IsBase("TSelector")) OK = kTRUE;
      break;
   }
   if (!OK) {
      if ( fromFile ) {
         ::Error("TSelector::GetSelector",
         "file %s does not have a valid class deriving from TSelector",filename);
      } else {
         ::Error("TSelector::GetSelector",
         "class %s does not exist or does not derive from TSelector",filename);
      }
      return 0;
   }

   // we can now create an instance of the class
   TSelector *selector = (TSelector*)cl.New();
   if (!selector || isCompiled) return selector;
   //interpreted selector: cannot be used as such
   //create a fake selector
   TSelectorCint *select = new TSelectorCint();
   select->Build(selector,&cl);

   return select;
}

