// @(#)root/treeplayer:$Name:  $:$Id: TTreeFormula.cxx,v 1.148 2004/06/17 17:37:10 brun Exp $
// Author: Rene Brun   19/01/96

/*************************************************************************
 * 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.             *
 *************************************************************************/

#include "TROOT.h"
#include "TTreeFormula.h"
#include "TTree.h"
#include "TBranch.h"
#include "TBranchObject.h"
#include "TFunction.h"
#include "TLeafC.h"
#include "TLeafObject.h"
#include "TDataMember.h"
#include "TMethodCall.h"
#include "TCutG.h"
#include "TRandom.h"
#include "TInterpreter.h"
#include "TDataType.h"
#include "TStreamerInfo.h"
#include "TStreamerElement.h"
#include "TBranchElement.h"
#include "TLeafElement.h"
#include "TArrayI.h"
#include "TAxis.h"
#include "TError.h"
#include "TVirtualCollectionProxy.h"

#include "TTreeFormulaManager.h"
#include "TFormLeafInfo.h"

#include <stdio.h>
#include <math.h>
#ifdef R__SOLARIS
#include <typeinfo>
#endif

const Int_t kMaxLen     = 512;
R__EXTERN TTree *gTree;



ClassImp(TTreeFormula)

//______________________________________________________________________________
//
// TTreeFormula now relies on a variety of TFormLeafInfo classes to handle the
// reading of the information.  Here is the list of theses classes:
//   TFormLeafInfo
//   TFormLeafInfoDirect
//   TFormLeafInfoNumerical
//   TFormLeafInfoClones
//   TFormLeafInfoCollection
//   TFormLeafInfoPointer
//   TFormLeafInfoMethod
//   TFormLeafInfoMultiVarDim
//   TFormLeafInfoMultiVarDimDirect
//   TFormLeafInfoCast
//
// The following method are available from the TFormLeafInfo interface:
//
//  AddOffset(Int_t offset, TStreamerElement* element)
//  GetCounterValue(TLeaf* leaf) : return the size of the array pointed to.
//  GetObjectAddress(TLeafElement* leaf) : Returns the the location of the object pointed to.
//  GetMultiplicity() : Returns info on the variability of the number of elements
//  GetNdata(TLeaf* leaf) : Returns the number of elements
//  GetNdata() : Used by GetNdata(TLeaf* leaf)
//  GetValue(TLeaf *leaf, Int_t instance = 0) : Return the value
//  GetValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value
//  GetLocalValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value of 'this' LeafInfo
//  IsString()
//  ReadValue(char *where, Int_t instance = 0) : Internal function to interpret the location 'where'
//  Update() : react to the possible loading of a shared library.
//
//


//______________________________________________________________________________
//
// This class is a small helper class to help in keeping track of the array
// dimensions encountered in the analysis of the expression.
class DimensionInfo : public TObject {
public:
  Int_t fCode;  // Location of the leaf in TTreeFormula::fCode
  Int_t fOper;  // Location of the Operation using the leaf in TTreeFormula::fOper
  Int_t fSize;
  TFormLeafInfoMultiVarDim* fMultiDim;
  DimensionInfo(Int_t code, Int_t oper, Int_t size, TFormLeafInfoMultiVarDim* multiDim)
    : fCode(code), fOper(oper), fSize(size), fMultiDim(multiDim) {};
  ~DimensionInfo() {};
};

//______________________________________________________________________________
//
//     A TreeFormula is used to pass a selection expression
//     to the Tree drawing routine. See TTree::Draw
//
//  A TreeFormula can contain any arithmetic expression including
//  standard operators and mathematical functions separated by operators.
//  Examples of valid expression:
//          "x<y && sqrt(z)>3.2"
//

//______________________________________________________________________________
TTreeFormula::TTreeFormula(): TFormula()
{
//*-*-*-*-*-*-*-*-*-*-*Tree Formula default constructor*-*-*-*-*-*-*-*-*-*
//*-*                  ================================

   fTree       = 0;
   fLookupType = 0;
   fNindex     = 0;
   fNcodes     = 0;
   fAxis       = 0;
   fHasCast    = 0;
   fManager    = 0;

   Int_t j,k;
   for (j=0; j<kMAXCODES; j++) {
      fNdimensions[j] = 0;
      fCodes[j] = 0;
      fNdata[j] = 1;
      fHasMultipleVarDim[j] = kFALSE;
      for (k = 0; k<kMAXFORMDIM; k++) {
         fIndexes[j][k] = -1;
         fCumulSizes[j][k] = 1;
         fVarIndexes[j][k] = 0;
      }
   }
}

//______________________________________________________________________________
TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree)
  :TFormula()
{
//*-*-*-*-*-*-*-*-*-*-*Normal Tree Formula constructor*-*-*-*-*-*-*-*-*-*-*
//*-*                  ===============================
//

   fTree         = tree;
   fNindex       = kMAXFOUND;
   fLookupType   = new Int_t[fNindex];
   fNcodes       = 0;
   fMultiplicity = 0;
   fAxis         = 0;
   fHasCast      = 0;
   Int_t i,j,k;
   fManager      = new TTreeFormulaManager;
   fManager->Add(this);

   for (j=0; j<kMAXCODES; j++) {
      fNdimensions[j] = 0;
      fLookupType[j] = kDirect;
      fCodes[j] = 0;
      fNdata[j] = 1;
      fHasMultipleVarDim[j] = kFALSE;
      for (k = 0; k<kMAXFORMDIM; k++) {
         fIndexes[j][k] = -1;
         fCumulSizes[j][k] = 1;
         fVarIndexes[j][k] = 0;
      }
   }

   fDimensionSetup = new TList;

   if (Compile(expression)) {fTree = 0; fNdim = 0; return; }

   if (fNcodes >= kMAXFOUND) {
      Warning("TTreeFormula","Too many items in expression:%s",expression);
      fNcodes = kMAXFOUND;
   }
   SetName(name);

   for (i=0;i<fNoper;i++) {

      if (GetAction(i)==kDefinedString) {
         Int_t string_code = GetActionParam(i); 
         TLeaf *leafc = (TLeaf*)fLeaves.UncheckedAt(string_code);
         if (!leafc) continue;

         // We have a string used as a string

         // This dormant portion of code would be used if (when?) we allow the histogramming
         // of the integral content (as opposed to the string content) of strings
         // held in a variable size container delimited by a null (as opposed to
         // a fixed size container or variable size container whose size is controlled
         // by a variable).  In GetNdata, we will then use strlen to grab the current length.
         //fCumulSizes[i][fNdimensions[i]-1] = 1;
         //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
         //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);

         if (fNcodes == 1) {
            // If the string is by itself, then it can safely be histogrammed as
            // in a string based axis.  To histogram the number inside the string
            // just make part of a useless expression (for example: mystring+0)
            SetBit(kIsCharacter);
         }
         continue;
      }
   }
   if (fNoper==1 && GetAction(0)==kAliasString) {
      TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
      Assert(subform);
      if (subform->TestBit(kIsCharacter)) SetBit(kIsCharacter);
   } else if (fNoper==2 && GetAction(0)==kAlternateString) {
      TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
      Assert(subform);
      if (subform->TestBit(kIsCharacter)) SetBit(kIsCharacter);
   }

   fManager->Sync(); 

   // Let's verify the indexes and dies if we need to.
   Int_t k0,k1;
   for(k0 = 0; k0 < fNcodes; k0++) {
      for(k1 = 0; k1 < fNdimensions[k0]; k1++ ) {
         // fprintf(stderr,"Saw %d dim %d and index %d\n",k1, fFixedSizes[k0][k1], fIndexes[k0][k1]);
         if ( fIndexes[k0][k1]>=0 && fFixedSizes[k0][k1]>=0
              && fIndexes[k0][k1]>=fFixedSizes[k0][k1]) {
            Error("TTreeFormula",
                  "Index %d for dimension #%d in %s is too high (max is %d)",
                  fIndexes[k0][k1],k1+1, expression,fFixedSizes[k0][k1]-1);
            fTree = 0; fNdim = 0; return;
         }
      }
   }


}

//______________________________________________________________________________
TTreeFormula::~TTreeFormula()
{
//*-*-*-*-*-*-*-*-*-*-*Tree Formula default destructor*-*-*-*-*-*-*-*-*-*-*
//*-*                  =================================

   if (fManager) {
      fManager->Remove(this);
      if (fManager->fFormulas.GetLast()<0) {
         delete fManager;
         fManager = 0;
      }
   }
   fLeafNames.Delete();
   fDataMembers.Delete();
   //TCutG objects should not be deleted from fMethods
   TList temp;
   TIter next(&fMethods);
   TObject *obj;
   while ((obj=next())) {
      if (obj->InheritsFrom("TCutG")) temp.Add(obj);
   }
   TIter next2(&temp);
   while ((obj=next2())) {
      fMethods.Remove(obj);
   }
   fMethods.Delete();
   fAliases.Delete();
   if (fLookupType) delete [] fLookupType;
   for (int j=0; j<fNcodes; j++) {
      for (int k = 0; k<fNdimensions[j]; k++) {
         if (fVarIndexes[j][k]) delete fVarIndexes[j][k];
         fVarIndexes[j][k] = 0;
      }
   }
   if (fDimensionSetup) {
     fDimensionSetup->Delete();
     delete fDimensionSetup;
   }
}

//______________________________________________________________________________
void TTreeFormula::DefineDimensions(Int_t code, Int_t size,
                                    TFormLeafInfoMultiVarDim * info,
                                    Int_t& virt_dim) {
   // This method is used internally to decode the dimensions of the variables

   if (info) {
      fManager->EnableMultiVarDims();
      if (fIndexes[code][info->fDim]<0) {
         info->fVirtDim = virt_dim;
         fManager->AddVarDims(virt_dim); // if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
      }
   }

   Int_t vsize = 0;

   if (fIndexes[code][fNdimensions[code]]==-2) {
      TTreeFormula *indexvar = fVarIndexes[code][fNdimensions[code]];
      // ASSERT(indexvar!=0);
      Int_t index_multiplicity = indexvar->GetMultiplicity();
      switch (index_multiplicity) {
         case -1:
         case  0:
         case  2:
            vsize = indexvar->GetNdata();
            break;
         case  1:
            vsize = -1;
            break;
      };
   } else vsize = size;

   fCumulSizes[code][fNdimensions[code]] = size;

   if ( fIndexes[code][fNdimensions[code]] < 0 ) {
      fManager->UpdateUsedSize(virt_dim, vsize);
   }

   fNdimensions[code] ++;

}

//______________________________________________________________________________
Int_t TTreeFormula::RegisterDimensions(const char *info, Int_t code) {
  // This method is used internally to decode the dimensions of the variables

   // We assume that there are NO white spaces in the info string
   const char * current;
   Int_t size, scanindex, vardim;

   current = info;
   vardim = 0;
   // the next value could be before the string but
   // that's okay because the next operation is ++
   // (this is to avoid (?) a if statement at the end of the
   // loop)
   if (current[0] != '[') current--;
   while (current) {
      current++;
      scanindex = sscanf(current,"%d",&size);
      // if scanindex is 0 then we have a name index thus a variable
      // array (or TClonesArray!).

      if (scanindex==0) size = -1;

      vardim += RegisterDimensions(code, size);

      if (fNdimensions[code] >= kMAXFORMDIM) {
         // NOTE: test that fNdimensions[code] is NOT too big!!

         break;
      }
      current = (char*)strstr( current, "[" );
   }
   return vardim;
}


//______________________________________________________________________________
Int_t TTreeFormula::RegisterDimensions(Int_t code, Int_t size, TFormLeafInfoMultiVarDim * multidim) {
   // This method stores the dimension information for later usage.

   DimensionInfo * info = new DimensionInfo(code,fNoper,size,multidim);
   fDimensionSetup->Add(info);
   fCumulSizes[code][fNdimensions[code]] = size;
   fNdimensions[code] ++;
   return (size==-1) ? 1 : 0;
}

//______________________________________________________________________________
Int_t TTreeFormula::RegisterDimensions(Int_t code, TFormLeafInfo *leafinfo) {
   // This method is used internally to decode the dimensions of the variables

   Int_t ndim, size, current, vardim;

   const TStreamerElement * elem = leafinfo->fElement;

   TFormLeafInfoMultiVarDim * multi = dynamic_cast<TFormLeafInfoMultiVarDim * >(leafinfo);
   if (multi) {
      // With have a second variable dimensions
      fManager->EnableMultiVarDims();
      multi->fDim = fNdimensions[code];
      return RegisterDimensions(code, -1, multi);
   }
   if (elem->IsA() == TStreamerBasicPointer::Class()) {

      ndim = 1;
      size = -1;

      TStreamerBasicPointer *array = (TStreamerBasicPointer*)elem;
      TClass * cl = leafinfo->fClass;
      Int_t offset;
      TStreamerElement* counter = cl->GetStreamerInfo()->GetStreamerElement(array->GetCountName(),offset);
      leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter);

   } else if (elem->GetClassPointer() == TClonesArray::Class() ) {

      ndim = 1;
      size = -1;

      TClass * ClonesClass = TClonesArray::Class();
      Int_t c_offset;
      TStreamerElement *counter = ClonesClass->GetStreamerInfo()->GetStreamerElement("fLast",c_offset);
      leafinfo->fCounter = new TFormLeafInfo(ClonesClass,c_offset,counter);

   } else if (elem->GetClassPointer() && elem->GetClassPointer()->GetCollectionProxy() ) {

      ndim = 1;
      size = -1;
      
      Assert( typeid(*leafinfo) == typeid(TFormLeafInfoCollection) );

   } else if (elem->GetArrayDim()>0) {

      ndim = elem->GetArrayDim();
      size = elem->GetMaxIndex(0);

   } else if ( elem->GetNewType()== TStreamerInfo::kCharStar) {

      // When we implement being able to read the length from
      // strlen, we will have:
      // ndim = 1;
      // size = -1;
      // until then we more or so die:
      ndim = 1;
      size = 1; //NOTE: changed from 0

   } else return 0;

   current = 0;
   vardim = 0;
   do {
      vardim += RegisterDimensions(code, size);

      if (fNdimensions[code] >= kMAXFORMDIM) {
         // NOTE: test that fNdimensions[code] is NOT too big!!

         break;
      }
      current++;
      size = elem->GetMaxIndex(current);
   } while (current<ndim);

   return vardim;
}

//______________________________________________________________________________
Int_t TTreeFormula::RegisterDimensions(Int_t code, TBranchElement *branch) {
   // This method is used internally to decode the dimensions of the variables

   TBranchElement * leafcount2 = branch->GetBranchCount2();
   if (leafcount2) {
      // With have a second variable dimensions
      TBranchElement *leafcount = dynamic_cast<TBranchElement*>(branch->GetBranchCount());

      Assert(leafcount); // The function should only be called on a functional TBranchElement object

      fManager->EnableMultiVarDims();
      TFormLeafInfoMultiVarDim * info = new TFormLeafInfoMultiVarDimDirect();
      fDataMembers.AddAtAndExpand(info, code);
      fHasMultipleVarDim[code] = kTRUE;

      info->fCounter = new TFormLeafInfoDirect(leafcount);
      info->fCounter2 = new TFormLeafInfoDirect(leafcount2);
      info->fDim = fNdimensions[code];
      //if (fIndexes[code][info->fDim]<0) {
      //  info->fVirtDim = virt_dim;
      //  if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
      //}
      return RegisterDimensions(code, -1, info);
   }
   return 0;
}

//______________________________________________________________________________
Int_t TTreeFormula::RegisterDimensions(Int_t code, TLeaf *leaf) {
   // This method is used internally to decode the dimensions of the variables

   Int_t numberOfVarDim = 0;

   // Let see if we can understand the structure of this branch.
   // Usually we have: leafname[fixed_array] leaftitle[var_array]\type
   // (with fixed_array that can be a multi-dimension array.
   const char *tname = leaf->GetTitle();
   char *leaf_dim = (char*)strstr( tname, "[" );

   const char *bname = leaf->GetBranch()->GetName();
   char *branch_dim = (char*)strstr(bname,"[");
   if (branch_dim) branch_dim++; // skip the '['

   if (leaf_dim) {
      leaf_dim++; // skip the '['
      if (!branch_dim || strncmp(branch_dim,leaf_dim,strlen(branch_dim))) {
         // then both are NOT the same so do the leaf title first:
         numberOfVarDim += RegisterDimensions( leaf_dim, code);
      }
   }
   if (branch_dim) {
      // then both are NOT same so do the branch name next:
      numberOfVarDim += RegisterDimensions( branch_dim, code);
   }
   
   if (leaf->IsA() == TLeafElement::Class()) {
      TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
      if (branch->GetBranchCount2()) {

         if (!branch->GetBranchCount()) {
            Warning("DefinedVariable",
                    "Noticed an incorrect in-memory TBranchElement object (%s).\nIt has a BranchCount2 but no BranchCount!\nThe result might be incorrect!",
                    branch->GetName());
            return numberOfVarDim;
         }

         // Switch from old direct style to using a TLeafInfo
         if (fLookupType[code] == kDataMember)
            Warning("DefinedVariable",
                    "Already in kDataMember mode when handling multiple variable dimensions");
         fLookupType[code] = kDataMember;
         
         // Feed the information into the Dimensions system
         numberOfVarDim += RegisterDimensions( code, branch);
         
      }
   }
   return numberOfVarDim;
}

//______________________________________________________________________________
Int_t TTreeFormula::DefinedVariable(TString &name, Int_t &action)
{
//*-*-*-*-*-*Check if name is in the list of Tree/Branch leaves*-*-*-*-*
//*-*        ==================================================
//
//   This member function redefines the function in TFormula
//   If a leaf has a name corresponding to the argument name, then
//   returns a new code.
//   A TTreeFormula may contain more than one variable.
//   For each variable referenced, the pointers to the corresponding
//   branch and leaf is stored in the object arrays fBranches and fLeaves.
//
//   name can be :
//      - Leaf_Name (simple variable or data member of a ClonesArray)
//      - Branch_Name.Leaf_Name
//      - Branch_Name.Method_Name
//      - Leaf_Name[index]
//      - Branch_Name.Leaf_Name[index]
//      - Branch_Name.Leaf_Name[index1]
//      - Branch_Name.Leaf_Name[][index2]
//      - Branch_Name.Leaf_Name[index1][index2]
//   New additions:
//      - Branch_Name.Leaf_Name[OtherLeaf_Name]
//      - Branch_Name.Datamember_Name
//      - '.' can be replaced by '->'
//   and
//      - Branch_Name[index1].Leaf_Name[index2]
//      - Leaf_name[index].Action().OtherAction(param)
//      - Leaf_name[index].Action()[val].OtherAction(param)
//
//   The expected returns values are
//     -2 :  the name has been recognized but won't be usable
//     -1 :  the name has not been recognized
//    >=0 :  the name has been recognized, return the internal code for this name.
//

   
   action = kDefinedVariable;
   if (!fTree) return -1;
   // Later on we will need to read one entry, let's make sure
   // it is a real entry.
   Int_t readentry = fTree->GetReadEntry();
   if (readentry==-1) readentry=0;
   fNpar = 0;
   Int_t nchname = name.Length();
   if (nchname > kMaxLen) return -1;
   Int_t i,k;
   Int_t numberOfVarDim = 0;

   const char *cname = name.Data();

   char    first[kMaxLen];  first[0] = '\0';
   char   second[kMaxLen]; second[0] = '\0';
   char    right[kMaxLen];  right[0] = '\0';
   char     dims[kMaxLen];   dims[0] = '\0';
   char     work[kMaxLen];   work[0] = '\0';
   char  scratch[kMaxLen];
   char scratch2[kMaxLen];
   char *current;

   TLeaf *leaf=0, *tmp_leaf=0;
   TBranch *branch=0, *tmp_branch=0;

   Bool_t final = kFALSE;

   UInt_t paran_level = 0;
   TObjArray castqueue;

   if (strcmp(cname,"Entry$")==0) {
      Int_t code = fNcodes++;
      fCodes[code] = 0;
      fLookupType[code] = kIndexOfEntry;
      return code;
   }
   if (strcmp(cname,"Entries$")==0) {
      Int_t code = fNcodes++;
      fCodes[code] = 0;
      fLookupType[code] = kEntries;
      return code;
   }
   if (strcmp(cname,"Iteration$")==0) {
      Int_t code = fNcodes++;
      fCodes[code] = 0;
      fLookupType[code] = kIteration;
      return code;
   }
   if (strcmp(cname,"Length$")==0) {
      Int_t code = fNcodes++;
      fCodes[code] = 0;
      fLookupType[code] = kLength;
      return code;
   }
   static const char *altfunc = "Alt$(";
   if (   strncmp(cname,altfunc,strlen(altfunc))==0
       && cname[strlen(cname)-1]==')'
       ) {
      TString full = cname;
      TString part1;
      TString part2;
      int paran = 0;
      int instr = 0;
      int brack = 0;
      for(unsigned int i=strlen(altfunc);i<strlen(cname);++i) {
         switch (cname[i]) {
            case '(': paran++; break;
            case ')': paran--; break;
            case '"': instr = instr ? 0 : 1; break;
            case '[': brack++; break;
            case ']': brack--; break;
         };
         if (cname[i]==',' && paran==0 && instr==0 && brack==0) {
            part1 = full( strlen(altfunc), i-strlen(altfunc) );
            part2 = full( i+1, full.Length() -1 - (i+1) );
            break; // out of the for loop
         }
      }
      if (part1.Length() && part2.Length()) {
         TTreeFormula *primary = new TTreeFormula("primary",part1,fTree);
         TTreeFormula *alternate = new TTreeFormula("alternate",part2,fTree);
//          TFormula *alt = new TFormula("alt",part2);

         if (alternate->GetManager()->GetMultiplicity() != 0 ) {
            Error("DefinedVariable","The 2nd arguments in %s can not be an array (%s,%d)!",
                  name.Data(),alternate->GetTitle(),alternate->GetManager()->GetMultiplicity());
            return -1;
         }
         
         // Should check whether we have strings.

         short isstring = 0;
         if (primary->IsString()) {
            if (!alternate->IsString()) {
               Error("DefinedVariable","The 2nd arguments in %s has to return the same type as the 1st argument (string)!",
                     name.Data());
               return -1;
            }
            isstring = 1;
         } else if (alternate->IsString()) {
            Error("DefinedVariable","The 2nd arguments in %s has to return the same type as the 1st argument (numerical type)!",
                  name.Data());
            return -1;
         }
         
         fAliases.AddAtAndExpand(primary,fNoper);
         fExpr[fNoper] = "";
         SetAction(fNoper, (Int_t)kAlternate + isstring, 0 );
         ++fNoper;
         
         fAliases.AddAtAndExpand(alternate,fNoper);
         action = (Int_t)kAlias + isstring;
         return 0;
      }
   }

   for (i=0, current = &(work[0]); i<=nchname && !final;i++ ) {
      // We will treated the terminator as a token.
      *current++ = cname[i];

      if (cname[i] == ')') {
         if (paran_level==0) {
            Error("DefinedVariable","Unmatched paranthesis in %s",name.Data());
            return -1;
         }
         // Let's see if work is a classname.
         *(--current) = 0;
         TString cast_name = gInterpreter->TypeName(work);
         TClass *cast_cl = gROOT->GetClass(cast_name);
         if (cast_cl) {
            // We must have a cast
            castqueue.AddAtAndExpand(cast_cl,paran_level);
            current = &(work[0]);
            *current = 0;
            //            Warning("DefinedVariable","Found cast to %s",cast_name.Data());
            paran_level--;
            continue;
         } else if (gROOT->GetType(cast_name)) {
            // We reset work
            current = &(work[0]);
            *current = 0;
            Warning("DefinedVariable",
                    "Casting to primary types like \"%s\" is not supported yet",cast_name.Data());
            paran_level--;
            continue;
         }
         // if it is not a cast, we just ignore the closing paranthesis.
         paran_level--;
      }
      if (cname[i] == '(') {
         if (current==work+1) {
            // If the expression starts with a paranthesis, we are likely
            // to have a cast operator inside.
            paran_level++;
            current--;
            continue;
         }
         // Right now we do not allow nested paranthesis
         i++;
         while( cname[i]!=')' && cname[i] ) {
            *current++ = cname[i++];
         }
         *current++ = cname[i++];
         *current='\0';
         char *params = strchr(work,'(');
         if (params) {
            *params = 0; params++;
         } else params = (char *) ")";

         if (branch && !leaf) {
            // We have a branch but not a leaf.  We are likely to have found
            // the top of splitted branch.
            if (BranchHasMethod(0,branch,work,params,readentry)) {
               //fprintf(stderr,"Does have a method %s for %s.\n",work,branch->GetName());
            }
         }

         // What we have so far might be a member function of one of the
         // leaves that are not splitted (for example "GetNtrack" for the Event class).
         TIter next (fTree->GetIteratorOnAllLeaves());
         TLeaf *leafcur;
         while (!leaf && (leafcur = (TLeaf*)next())) {
            if (BranchHasMethod(leafcur,leafcur->GetBranch(),work,params,readentry)) {
               //fprintf(stderr,"Does have a method %s for %s found in leafcur %s.\n",work,leafcur->GetBranch()->GetName(),leafcur->GetName());
               leaf = leafcur;
            }
         }
         if (!leaf) {
            // This actually not really any error, we probably received something
            // like "abs(some_val)", let TFormula decompose it first.
            return -1;
         }
         //         if (!leaf->InheritsFrom("TLeafObject") ) {
         // If the leaf that we found so far is not a TLeafObject then there is
            // nothing we would be able to do.
         //   Error("DefinedVariable","Need a TLeafObject to call a function!");
         // return -1;
         //}
         // We need to recover the info not used.
         strcpy(right,work);
         strcat(right,"(");
         strcat(right,params);
         final = kTRUE;

         // we reset work
         current = &(work[0]);
         *current = 0;
         break;
      }
      if (cname[i] == '.' || cname[i] == '[' || cname[i] == '\0' ) {
         // A delimiter happened let's see if what we have seen
         // so far does point to a leaf.

         *current = '\0';
         if (!leaf && !branch) {
            // So far, we have not found a matching leaf or branch.
            strcpy(first,work);

            branch = fTree->FindBranch(first);
            leaf = fTree->FindLeaf(first);

            // Now look with the delimiter removed (we looked with it first
            // because a dot is allowed at the end of some branches).
            if (cname[i]) first[strlen(first)-1]='\0';
            if (!branch) branch = fTree->FindBranch(first);
            if (!leaf) leaf = fTree->FindLeaf(first);

            if (branch && cname[i] != 0) {
               // Since we found a branch and there is more information in the name,
               // we do NOT look at the 'IsOnTerminalBranch' status of the leaf
               // we found ... yet!

               if (leaf==0) {
                  // Note we do not know (yet?) what (if anything) to do
                  // for a TBranchObject branch.
                  if (branch->InheritsFrom(TBranchElement::Class()) ) {
                     Int_t type = ((TBranchElement*)branch)->GetType();
                     if ( type == 3 || type ==4) {
                        // We have a Collection branch.
                        leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
                     }
                  }
               }

               // we reset work
               current = &(work[0]);
               *current = 0;
            } else if (leaf || branch) {
               if (leaf && branch) {
                  // We found both a leaf and branch matching the request name
                  // let's see which one is the proper one to use! (On annoying case
                  // is that where the same name is repeated ( varname.varname )

                  // We always give priority to the branch
                  // leaf = 0;
               }
               if (leaf && leaf->IsOnTerminalBranch()) {
                  // This is a non-object leaf, it should NOT be specified more except for
                  // dimensions.
                  final = kTRUE;
               }
               // we reset work
               current = &(work[0]);
               *current = 0;
            } else {
               // What we have so far might be a data member of one of the
               // leaves that are not splitted (for example "fNtrack" for the Event class.
               TLeaf *leafcur = GetLeafWithDatamember(first,work,readentry);
               if (leafcur) {
                  leaf = leafcur;
                  branch = leaf->GetBranch();
                  if (leaf->IsOnTerminalBranch()) {
                     final = kTRUE;
                     strcpy(right,first);
                     //We need to put the delimiter back!
                     if (cname[i]=='.') strcat(right,".");

                     // We reset work
                     current = &(work[0]);
                     *current = 0;
                  };
               } else if (cname[i] == '.') {
                  // If we have a branch that match a name preceded by a dot
                  // then we assume we are trying to drill down the branch
                  // Let look if one of the top level branch has a branch with the name
                  // we are looking for.
                  TBranch *branchcur;
                  TIter next( fTree->GetListOfBranches() );
                  while(!branch && (branchcur=(TBranch*)next()) ) {
                     branch = branchcur->FindBranch(first);
                  }
                  if (branch) {
                     // We reset work
                     current = &(work[0]);
                     *current = 0;
                  }
               }
            }
         } else {  // correspond to if (leaf || branch)
            if (final) {
               Error("DefinedVariable", "Unexpected control flow!");
               return -1;
            }

            // No dot is allowed in subbranches and leaves, so
            // we always remove it in the present case.
            if (cname[i]) work[strlen(work)-1] = '\0';
            sprintf(scratch,"%s.%s",first,work);
            sprintf(scratch2,"%s.%s.%s",first,second,work);



            // First look for the current 'word' in the list of
            // leaf of the
            if (branch) {
               tmp_leaf = branch->FindLeaf(work);
               if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch);
               if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch2);
            }
            if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
               // This is a non-object leaf, it should NOT be specified more except for
               // dimensions.
               final = kTRUE;
            }

            if (branch) {
               tmp_branch = branch->FindBranch(work);
               if (!tmp_branch) tmp_branch = branch->FindBranch(scratch);
               if (!tmp_branch) tmp_branch = branch->FindBranch(scratch2);
            }
            if (tmp_branch) {
               branch=tmp_branch;

               // NOTE: Should we look for a leaf within here?
               if (!final) {
                  tmp_leaf = branch->FindLeaf(work);
                  if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch);
                  if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch2);
                  if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
                     // This is a non-object leaf, it should NOT be specified
                     // more except for dimensions.
                     final = kTRUE;
                     leaf = tmp_leaf;
                  }
               }
            }
            if (tmp_leaf) {
               // Something was found.
               if (second[0]) strcat(second,".");
               strcat(second,work);
               leaf = tmp_leaf;

               // we reset work
               current = &(work[0]);
               *current = 0;
            } else {
               //We need to put the delimiter back!
               if (strlen(work)) work[strlen(work)] = cname[i];
               else --current;
            }
         }
      }
      if (cname[i] == '[') {
         int bracket = i;
         int bracket_level = 1;
         int j;
         for (j=++i; j<nchname && (bracket_level>0 || cname[j]=='['); j++, i++) {
            if (cname[j]=='[')
               bracket_level++;
            else if (cname[j]==']')
               bracket_level--;
         }
         if (bracket_level != 0) {
            //Error("DefinedVariable","Bracket unbalanced");
            return -1;
         }
         strncat(dims,&cname[bracket],j-bracket);
         if (current!=work) *(--current) = '\0'; // remove bracket.
         --i;
         if (current == &(work[0])) { // leaf!=0 && branch!=0) {
            // If we have already sucessfully analyzed the left part of the name
            // we need to skip the dots that may be adjacent to the closing bracket
            while (cname[i+1]=='.') i++;
         }
      }
   }
   // Copy the left over for later use.
   if (strlen(work)) {
      strcat(right,work);
   }
   if (i<nchname) {
      if (strlen(right) && right[strlen(right)-1]!='.' && cname[i]!='.') {
         // In some cases we remove a little to fast the period, we added
         // it back if we need.  It is assumed that 'right' and the rest of
         // the name was cut by a delimiter, so this should be safe.
         strcat(right,".");
      }
      strcat(right,&cname[i]);
   }

   if (!final && branch) { 
      if (!leaf) {
         leaf = (TLeaf*)branch->GetListOfLeaves()->UncheckedAt(0);
         if (!leaf) return -1;
      }
      final = leaf->IsOnTerminalBranch();
   }

   if (!leaf) {
      // Check for an alias.
      const char *aliasValue = fTree->GetAlias(work);
      if (aliasValue) {
         TTreeFormula *subform = new TTreeFormula(work,aliasValue,fTree); 
            
         fManager->Add(subform);
         fAliases.AddAtAndExpand(subform,fNoper);
         
         if (subform->IsString()) {
            action = kAliasString;
            return 0;
         } else {
            action = kAlias;
            return 0;
         }
      }
   }

   if (leaf) { // We found a Leaf.

      if (leaf->GetBranch() && leaf->GetBranch()->TestBit(kDoNotProcess)) {
         Error("DefinedVariable","the branch \"%s\" has to be enabled to be used",leaf->GetBranch()->GetName());
         return -2;
      }

      // Save the information

      Int_t code = fNcodes++;

      // We need to move all dimensions information from 'right'
      // to dims so that they are ALL processed here.

      Int_t rightlen = strlen(right);
      for(i=0,k=0; i<rightlen; i++, k++) {
         if (right[i] == '[') {
            int bracket = i;
            int bracket_level = 1;
            int j;
            for (j=++i; j<rightlen && (bracket_level>0 || right[j]=='['); j++, i++) {
               if (right[j]=='[') bracket_level++;
               else if (right[j]==']') bracket_level--;
            }
            if (bracket_level != 0) {
               //Error("DefinedVariable","Bracket unbalanced");
               return -1;
            }
            strncat(dims,&right[bracket],j-bracket);
            k += j-bracket;
         }
         if (i!=k) right[i] = right[k];
      }
      right[i]='\0';

      // If needed will now parse the indexes specified for
      // arrays.
      if (dims[0]) {
         current = &( dims[0] );
         Int_t dim = 0;
         char varindex[kMaxLen];
         Int_t index;
         Int_t scanindex ;
         while (current) {
            current++;
            if (current[0] == ']') {
               fIndexes[code][dim] = -1; // Loop over all elements;
            } else {
               scanindex = sscanf(current,"%d",&index);
               if (scanindex) {
                  fIndexes[code][dim] = index;
               } else {
                  fIndexes[code][dim] = -2; // Index is calculated via a variable.
                  strcpy(varindex,current);
                  char *end = varindex;
                  for(char bracket_level = 0;*end!=0;end++) {
                    if (*end=='[') bracket_level++;
                    if (bracket_level==0 && *end==']') break;
                    if (*end==']') bracket_level--;
                  }
                  if (end != 0) {
                     *end = '\0';
                     fVarIndexes[code][dim] = new TTreeFormula("index_var",
                                                                  varindex,
                                                                  fTree);
                     current += strlen(varindex)+1; // move to the end of the index array
                  }
               }
            }
            dim ++;
            if (dim >= kMAXFORMDIM) {
               // NOTE: test that dim this is NOT too big!!
               break;
            }
            current = (char*)strstr( current, "[" );
         }
      }

      // Make a check to prevent problem with some corrupted files (missing TStreamerInfo).
      if (leaf->IsA()==TLeafElement::Class()) {
         TBranchElement *br = ((TBranchElement*)leaf->GetBranch());

         if ( br->GetInfo() == 0 ) {
            Error("DefinedVariable","Missing StreamerInfo for %s.  We will be unable to read!",
                  name.Data());
            return -2;
         }
         TBranchElement *mom = (TBranchElement*)br->GetMother();
         if (mom!=br) {
            if (mom->GetInfo()==0) {
               Error("DefinedVariable","Missing StreamerInfo for %s.  We will be unable to read!",
                     mom->GetName());
               return -2;
            }
            if (mom->GetType()<0 && mom->GetAddress()==0) {
               Error("DefinedVariable","Address not set when the type of the branch is negatif for for %s.  We will be unable to read!",
                     mom->GetName());
               return -2;
            }
         }
      }


      // We need to record the location in the list of leaves because
      // the tree might actually be a chain and in that case the leaf will
      // change from tree to tree!.

      // Let's reconstruct the name of the leaf, including the possible friend alias
      TTree *realtree = fTree->GetTree();
      const char* alias = 0;
      if (realtree) alias = realtree->GetFriendAlias(leaf->GetBranch()->GetTree());
      if (alias) sprintf(scratch,"%s.%s",alias,leaf->GetName());
      else strcpy(scratch,leaf->GetName());

      TTree *tleaf = leaf->GetBranch()->GetTree();
      fCodes[code] = tleaf->GetListOfLeaves()->IndexOf(leaf);
      TNamed *named = new TNamed(scratch,leaf->GetBranch()->GetName());
      fLeafNames.AddAtAndExpand(named,code);
      fLeaves.AddAtAndExpand(leaf,code);

      // Analyze the content of 'right'

      // Try to find out the class (if any) of the object in the leaf.
      TClass * cl = 0;
      TFormLeafInfo *maininfo = 0;
      TFormLeafInfo *previnfo = 0;

      if (leaf->InheritsFrom("TLeafObject") ) {
         TBranchObject *bobj = (TBranchObject*)leaf->GetBranch();
         cl = gROOT->GetClass(bobj->GetClassName());
         if (strlen(right)==0) strcpy(right,work);
      } else if (leaf->InheritsFrom("TLeafElement")) {
         TBranchElement *BranchEl = (TBranchElement *)leaf->GetBranch();
         TStreamerInfo *info = BranchEl->GetInfo();
         TStreamerElement *element = 0;
         Int_t type = BranchEl->GetStreamerType();
         switch(type) {
            case TStreamerInfo::kObject:
            case TStreamerInfo::kTString:
            case TStreamerInfo::kTNamed:
            case TStreamerInfo::kTObject:
            case TStreamerInfo::kAny:
            case TStreamerInfo::kAnyP:
            case TStreamerInfo::kAnyp:
            case TStreamerInfo::kSTL:
            case TStreamerInfo::kSTLp:
            case TStreamerInfo::kObjectp:
            case TStreamerInfo::kObjectP: {
              element = (TStreamerElement *)info->GetElems()[BranchEl->GetID()];
              if (element) cl = element->GetClassPointer();
            }
            break;
            case TStreamerInfo::kOffsetL + TStreamerInfo::kSTL:
            case TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp:
            case TStreamerInfo::kOffsetL + TStreamerInfo::kAny:
            case TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp:
            case TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP:
            case TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp:
            case TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP:
            case TStreamerInfo::kOffsetL + TStreamerInfo::kObject:  {
              element = (TStreamerElement *)info->GetElems()[BranchEl->GetID()];
              if (element){
                 cl = element->GetClassPointer();
              }
            }
            break;
            case -1: {
              cl = info->GetClass();
            }
            break;
         }

         // If we got a class object, we need to verify whether it is on a
         // split TClonesArray sub branch.
         if (cl && BranchEl->GetBranchCount()) {
            if (BranchEl->GetType()==31) {
               // This is inside a TClonesArray.
               
               if (!element) {
                  Warning("DefineVariable","Missing TStreamerElement in object in TClonesArray section");
                  return -2;
               }
               TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, element, kTRUE);
               
               // The following code was commmented out because in THIS case
               // the dimension are actually handled by parsing the title and name of the leaf
               // and branch (see a little further)
               // The dimension needs to be handled!
               // numberOfVarDim += RegisterDimensions(code,clonesinfo);
               
               maininfo = clonesinfo;
               
               // We skip some cases because we can assume we have an object.
               Int_t offset;
               info->GetStreamerElement(element->GetName(),offset);
               if (type == TStreamerInfo::kObjectp ||
                   type == TStreamerInfo::kObjectP ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP ||
                   type == TStreamerInfo::kSTLp ||
                   type == TStreamerInfo::kAnyp ||
                   type == TStreamerInfo::kAnyP ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP) {
                  previnfo = new TFormLeafInfoPointer(cl,offset+BranchEl->GetOffset(),element);
               } else {
                  previnfo = new TFormLeafInfo(cl,offset+BranchEl->GetOffset(),element);
               }
               maininfo->fNext = previnfo;

            } else if (BranchEl->GetType()==41) {

               // This is inside a Collection
               
               if (!element) {
                  Warning("DefineVariable","Missing TStreamerElement in object in Collection section");
                  return -2;
               }
               TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(cl, 0, element, kTRUE);
               
                // The following code was commmented out because in THIS case
               // the dimension are actually handled by parsing the title and name of the leaf
               // and branch (see a little further)
               // The dimension needs to be handled!
               // numberOfVarDim += RegisterDimensions(code,clonesinfo);
               
               maininfo = collectioninfo;
               
               // We skip some cases because we can assume we have an object.
               Int_t offset;
               info->GetStreamerElement(element->GetName(),offset);
               if (type == TStreamerInfo::kObjectp ||
                   type == TStreamerInfo::kObjectP ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP ||
                   type == TStreamerInfo::kSTLp ||
                   type == TStreamerInfo::kAnyp ||
                   type == TStreamerInfo::kAnyP ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp ||
                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP) {
                  previnfo = new TFormLeafInfoPointer(cl,offset+BranchEl->GetOffset(),element);
               } else {
                  previnfo = new TFormLeafInfo(cl,offset+BranchEl->GetOffset(),element);
               }
               maininfo->fNext = previnfo;              

            }

         } else if (BranchEl->GetType()==3) {
            
            TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, kTRUE);
            // The dimension needs to be handled!
            numberOfVarDim += RegisterDimensions(code,clonesinfo);

            maininfo = clonesinfo;
            previnfo = maininfo;

         } else if (BranchEl->GetType()==4) {
            
            TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE);
            // The dimension needs to be handled!
            numberOfVarDim += RegisterDimensions(code,collectioninfo);

            maininfo = collectioninfo;
            previnfo = maininfo;

         } else if (strlen(right)==0 && cl && element && !element->IsaPointer() && final) {

            if (element->GetClassPointer() && element->GetClassPointer()->GetCollectionProxy() 
                && element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==0
                && element->GetClassPointer()->GetCollectionProxy()->GetType()>0) {
               
               TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(cl,BranchEl->GetOffset(),element);

               // The dimension needs to be handled!
               numberOfVarDim += RegisterDimensions(code,collectioninfo);

               collectioninfo->fNext = new TFormLeafInfoNumerical(element->GetClassPointer()->GetCollectionProxy()->GetType());

               maininfo = collectioninfo;
               previnfo = maininfo->fNext;

            } else {
           
               maininfo = new TFormLeafInfoDirect(BranchEl); 
               previnfo = maininfo;

            }

         }
      }
      
      // Treat the dimension information in the leaf name, title and 2nd branch count
      numberOfVarDim += RegisterDimensions(code,leaf);

      if (cl) {
         Int_t offset;
         Int_t nchname = strlen(right);
         TFormLeafInfo *leafinfo = 0;
         TStreamerElement* element = 0;

         // Let see if the leaf was attempted to be casted.
         // Since there would have been something like
         // ((cast_class*)leafname)->....  we need to use
         // paran_level+2
         // Also we disable this functionality in case of TClonesArray
         // because it is not yet allowed to have 'inheritance' (or virtuality)
         // in play in a TClonesArray.
         TClass * casted = (TClass*) castqueue.At(paran_level+2);
         if (casted && cl != TClonesArray::Class()) {
            if ( ! casted->InheritsFrom(cl) ) {
               Error("DefinedVariable","%s does not inherit from %s.  Casting not possible!",
                     casted->GetName(),cl->GetName());
               return -2;
            }
            leafinfo = new TFormLeafInfoCast(cl,casted);
            fHasCast = kTRUE;
            if (maininfo==0) {
               maininfo = leafinfo;
            }
            if (previnfo==0) {
               previnfo = leafinfo;
            } else {
               previnfo->fNext = leafinfo;
               previnfo = leafinfo;
            }
            leafinfo = 0;

            cl = casted;
            castqueue.AddAt(0,paran_level);
         }

         for (i=0, current = &(work[0]); i<=nchname;i++ ) {
            // We will treated the terminator as a token.
            if (right[i] == '(') {
               // Right now we do not allow nested paranthesis
               do {
                  *current++ = right[i++];
               } while(right[i]!=')' && right[i]);
               *current++ = right[i++];
               *current='\0';
               char *params = strchr(work,'(');
               if (params) {
                  *params = 0; params++;
               } else params = (char *) ")";
               if (cl==0) {
                  Error("DefinedVariable","Can not call '%s' with a class",work);
                  return -1;
               }
               if (cl->GetClassInfo()==0 && !cl->GetCollectionProxy()) {
                  Error("DefinedVariable","Class probably unavailable:%s",cl->GetName());
                  return -2;
               }
               if (cl == TClonesArray::Class()) {
                  // We are NEVER interested in the ClonesArray object but only
                  // in its contents.
                  // We need to retrieve the class of its content.

                  TBranch *branch = leaf->GetBranch();
                  branch->GetEntry(readentry);
                  TClonesArray * clones;
                  if (previnfo) clones = (TClonesArray*)previnfo->GetLocalValuePointer(leaf,0);
                  else {
                     if (branch==((TBranchElement*)branch)->GetMother()
                         || !leaf->IsOnTerminalBranch() ) {
                        TClass *mother_cl;
                        if (leaf->IsA()==TLeafObject::Class()) {
                           // in this case mother_cl is not really used
                           mother_cl = cl;
                        } else {
                           mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
                        }

                        TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0, kTRUE);
                        // The dimension needs to be handled!
                        numberOfVarDim += RegisterDimensions(code,clonesinfo);

                        previnfo = clonesinfo;
                        maininfo = clonesinfo;

                        clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
                        //clones = *(TClonesArray**)((TBranchElement*)branch)->GetAdress();
                     } else {
                        TClass *mother_cl;
                        if (leaf->IsA()==TLeafObject::Class()) {
                           // in this case mother_cl is not really used
                           mother_cl = cl;
                        } else {
                           mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
                        }

                        TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
                        // The dimension needs to be handled!
                        numberOfVarDim += RegisterDimensions(code,clonesinfo);

                        previnfo = clonesinfo;
                        maininfo = clonesinfo;

                        clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
                     }
                  }
                  TClass * inside_cl = clones->GetClass();
                  if (1 || inside_cl) cl = inside_cl;

               } else if (cl && cl->GetCollectionProxy() ) {

                  // We are NEVER (for now!) interested in the ClonesArray object but only
                  // in its contents.
                  // We need to retrieve the class of its content.
                  
                  if (previnfo==0) {
                     
                     if (branch==((TBranchElement*)branch)->GetMother()
                         || !leaf->IsOnTerminalBranch() ) {

                        TClass *mother_cl;
                        if (leaf->IsA()==TLeafObject::Class()) {
                           // in this case mother_cl is not really used
                           mother_cl = cl;
                        } else {
                           mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
                        }
                        
                        TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0,cl,kTRUE);
                        // The dimension needs to be handled!
                        numberOfVarDim += RegisterDimensions(code,collectioninfo);

                        previnfo = collectioninfo;
                        maininfo = collectioninfo;

                     } else {

                        TClass *mother_cl;
                        if (leaf->IsA()==TLeafObject::Class()) {
                           // in this case mother_cl is not really used
                           mother_cl = cl;
                        } else {
                           mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
                        }

                        TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0, cl);
                        // The dimension needs to be handled!
                        numberOfVarDim += RegisterDimensions(code,collectioninfo);

                        previnfo = collectioninfo;
                        maininfo = collectioninfo;

                     }

                  }

                  TClass * inside_cl = cl->GetCollectionProxy()->GetValueClass();
                  if (inside_cl) cl = inside_cl;
                  else if (cl->GetCollectionProxy()->GetType()>0) {
                     Warning("DefinedVariable","Can not call method on content of %s in %s\n",
                             cl->GetName(),name.Data());
                  }

               }

               TMethodCall *method;
               if (cl->GetClassInfo()==0) {
                  Error("DefinedVariable","Can not call method %s on class without dictionary (%s)!",
                        right,cl->GetName());
                  return -2;
               }
               method = new TMethodCall(cl, work, params);
               if (!method->GetMethod()) {
                  Error("DefinedVariable","Unknown method:%s",right);
                  return -1;
               }
               switch(method->ReturnType()) {
                  case TMethodCall::kLong:
                        leafinfo = new TFormLeafInfoMethod(cl,method);
                        cl = 0;
                        break;
                  case TMethodCall::kDouble:
                        leafinfo = new TFormLeafInfoMethod(cl,method);
                        cl = 0;
                        break;
                  case TMethodCall::kString:
                        leafinfo = new TFormLeafInfoMethod(cl,method);
                        // 1 will be replaced by -1 when we know how to use strlen
                        numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
                        cl = 0;
                        break;
                  case TMethodCall::kOther:
                       {TString return_type = gInterpreter->TypeName(method->GetMethod()->GetReturnTypeName());
                       leafinfo = new TFormLeafInfoMethod(cl,method);
                       if (return_type != "void") {
                          cl = gROOT->GetClass(return_type.Data());
                       } else {
                          cl = 0;
                       }
                      };    break;
                  default:
                  Error("DefineVariable","Method %s from %s has an impossible return type %d",
                        work,cl->GetName(),method->ReturnType());
                  return -2;
               }
               if (maininfo==0) {
                  maininfo = leafinfo;
               }
               if (previnfo==0) {
                  previnfo = leafinfo;
               } else {
                  previnfo->fNext = leafinfo;
                  previnfo = leafinfo;
               }
               leafinfo = 0;
               current = &(work[0]);
               *current = 0;
               continue;
            } else if (right[i] == ')') {
               // We should have the end of a cast operator.  Let's introduce a TFormLeafCast
               // in the chain.
               TClass * casted = (TClass*) castqueue.At(--paran_level);
               if (casted) {
                  leafinfo = new TFormLeafInfoCast(cl,casted);
                  fHasCast = kTRUE;

                  if (maininfo==0) {
                     maininfo = leafinfo;
                  }
                  if (previnfo==0) {
                     previnfo = leafinfo;
                  } else {
                     previnfo->fNext = leafinfo;
                     previnfo = leafinfo;
                  }
                  leafinfo = 0;
                  current = &(work[0]);
                  *current = 0;

                  cl = casted;
                  continue;

               }
            } else if (i > 0 && (right[i] == '.' || right[i] == '[' || right[i] == '\0') ) {
               // A delimiter happened let's see if what we have seen
               // so far does point to a data member.
               *current = '\0';

               // skip it all if there is nothing to look at
               if (strlen(work)==0) continue;

               Bool_t mustderef = kFALSE;
               if (cl == TClonesArray::Class()) {
                  // We are NEVER interested in the ClonesArray object but only
                  // in its contents.
                  // We need to retrieve the class of its content.

                  TBranch *branch = leaf->GetBranch();
                  branch->GetEntry(readentry);
                  TClonesArray * clones;
                  if (maininfo) clones = (TClonesArray*)maininfo->GetLocalValuePointer(leaf,0);
                  else {
                     // we have a unsplit TClonesArray leaves
                     // or we did not yet match any of the sub-branches!
                    
                     TClass *mother_cl;
                     if (leaf->IsA()==TLeafObject::Class()) {
                        // in this case mother_cl is not really used
                        mother_cl = cl;
                     } else {
                        mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
                     }

                     TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
                     // The dimension needs to be handled!
                     numberOfVarDim += RegisterDimensions(code,clonesinfo);

                     mustderef = kTRUE;
                     previnfo = clonesinfo;
                     maininfo = clonesinfo;

                     if (branch->GetListOfBranches()->GetLast()>=0) {
                        if (branch->IsA() != TBranchElement::Class()) {
                           Error("DefinedVariable","Unimplemented usage of ClonesArray");
                           return -2;
                        }
                        //branch = ((TBranchElement*)branch)->GetMother();
                        clones = (TClonesArray*)((TBranchElement*)branch)->GetObject();
                     } else 
                        clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
                  }
                  // NOTE clones can be zero!
                  TClass * inside_cl = clones->GetClass();
                  if (1 || inside_cl) cl = inside_cl;
                  // if inside_cl is nul ... we have a problem of inconsistency :(
                  if (0 && strlen(work)==0) {
                     // However in this case we have NO content :(
                     // so let get the number of objects
                     //strcpy(work,"fLast");
                  }
               } else if (cl && cl->GetCollectionProxy() ) {

                  // We are NEVER interested in the Collection object but only
                  // in its contents.
                  // We need to retrieve the class of its content.

                  TBranch *branch = leaf->GetBranch();
                  branch->GetEntry(readentry);
                  
                  if (maininfo==0) {

                     // we have a unsplit Collection leaves
                     // or we did not yet match any of the sub-branches!
                    
                     TClass *mother_cl;
                     if (leaf->IsA()==TLeafObject::Class()) {
                        // in this case mother_cl is not really used
                        mother_cl = cl;
                     } else {
                        mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
                     }

                     TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0, cl);
                     // The dimension needs to be handled!
                     numberOfVarDim += RegisterDimensions(code,collectioninfo);

                     mustderef = kTRUE;
                     previnfo = collectioninfo;
                     maininfo = collectioninfo;

                  }

                  TClass * inside_cl = cl->GetCollectionProxy()->GetValueClass();

                  if (!inside_cl && cl->GetCollectionProxy()->GetType() > 0) {
                     Warning("DefinedVariable","No data member in content of %s in %s\n",
                             cl->GetName(),name.Data());
                  }
                  if (1 || inside_cl) cl = inside_cl;
                  // if inside_cl is nul ... we have a problem of inconsistency :(
               }

               if (!cl) { 
                  Warning("DefinedVariable","Missing class for %s!",name.Data());
               } else {
                  element = cl->GetStreamerInfo()->GetStreamerElement(work,offset);
               }

               if (!element) {
                  // We allow for looking for a data member inside a class inside
                  // a TClonesArray without mentioning the TClonesArrays variable name
                  TIter next( cl->GetStreamerInfo()->GetElements() );
                  TStreamerElement * curelem;
                  while ((curelem = (TStreamerElement*)next())) {
                     if (curelem->GetClassPointer() ==  TClonesArray::Class()) {
                        Int_t clones_offset;
                        cl->GetStreamerInfo()->GetStreamerElement(curelem->GetName(),clones_offset);
                        TFormLeafInfo* clonesinfo = new TFormLeafInfo(cl, clones_offset, curelem);
                        TClonesArray * clones;
                        leaf->GetBranch()->GetEntry(readentry);

                        if (previnfo) {
                           previnfo->fNext = clonesinfo;
                           clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
                           previnfo->fNext = 0;
                        } else {
                           clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
                        }

                        TClass *sub_cl = clones->GetClass();
                        element = sub_cl->GetStreamerInfo()->GetStreamerElement(work,offset);
                        delete clonesinfo;

                        if (element) {
                           leafinfo = new TFormLeafInfoClones(cl,clones_offset,curelem);
                           numberOfVarDim += RegisterDimensions(code,leafinfo);
                           if (maininfo==0) maininfo = leafinfo;
                           if (previnfo==0) previnfo = leafinfo;
                           else {
                              previnfo->fNext = leafinfo;
                              previnfo = leafinfo;
                           }
                           leafinfo = 0;
                           cl = sub_cl;
                           break;
                        }
                     } else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {

                        Int_t coll_offset;
                        cl->GetStreamerInfo()->GetStreamerElement(curelem->GetName(),coll_offset);

                        TClass *sub_cl = curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
                        if (sub_cl) element = sub_cl->GetStreamerInfo()->GetStreamerElement(work,offset);

                        if (element) {
                           leafinfo = new TFormLeafInfoCollection(cl,coll_offset,curelem);
                           numberOfVarDim += RegisterDimensions(code,leafinfo);
                           if (maininfo==0) maininfo = leafinfo;
                           if (previnfo==0) previnfo = leafinfo;
                           else {
                              previnfo->fNext = leafinfo;
                              previnfo = leafinfo;
                           }
                           leafinfo = 0;
                           cl = sub_cl;
                           break;
                        }
                     }
                  }

               }

               if (element) {
                  Int_t type = element->GetNewType();
                  if (type<60) {
                     // This is a basic type ...
                     if (numberOfVarDim>=1 && type>40) {
                        // We have a variable array within a variable array!
                        leafinfo = new TFormLeafInfoMultiVarDim(cl,offset,element,maininfo);
                        // fDataMembers.AddAtAndExpand(leafinfo,code);
                        fHasMultipleVarDim[code] = kTRUE;
                     } else {
                        if (leafinfo) {
                           // leafinfo->fOffset += offset;
                           leafinfo->AddOffset(offset,element);
                        } else {
                           leafinfo = new TFormLeafInfo(cl,offset,element);
                        }
                     }
                  } else if (type == TStreamerInfo::kObjectp ||
                             type == TStreamerInfo::kObjectP ||
                             type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp ||
                             type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP ||
                             type == TStreamerInfo::kSTLp ||
                             type == TStreamerInfo::kAnyp ||
                             type == TStreamerInfo::kAnyP ||
                             type == TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp ||
                             type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp ||
                             type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP) {

                     // this is a pointer to be followed.

                     if (element->GetClassPointer() ==  TClonesArray::Class()) {

                        leafinfo = new TFormLeafInfoClones(cl,offset,element);
                        mustderef = kTRUE;

                     } else if (element->GetClassPointer() && element->GetClassPointer()->GetCollectionProxy()) {

                        leafinfo = new TFormLeafInfoCollection(cl,offset,element);
                        mustderef = kTRUE;
                        if (element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==0) {
                           leafinfo->fNext = new TFormLeafInfoNumerical(element->GetClassPointer()->GetCollectionProxy()->GetType());
                        }
                     } else {
                        leafinfo = new TFormLeafInfoPointer(cl,offset,element);
                        mustderef = kTRUE;
                     }
                  } else if (type == TStreamerInfo::kAny ||
                             type == TStreamerInfo::kSTL ||
                             type == TStreamerInfo::kObject ||
                             type == TStreamerInfo::kTString  ||
                             type == TStreamerInfo::kTNamed  ||
                             type == TStreamerInfo::kTObject ) {

                     // this is an embedded object. We can increase the offset.
                     if (leafinfo) {
                        // leafinfo->fOffset += offset;
                        leafinfo->AddOffset(offset,element);
                     } else {
                         if (element->GetClassPointer() ==  TClonesArray::Class()) {
                            leafinfo = new TFormLeafInfoClones(cl,offset,element);
                            mustderef = kTRUE;
                         } else if (element->GetClassPointer()->GetCollectionProxy()) {
                            leafinfo = new TFormLeafInfoCollection(cl,offset,element);
                            mustderef = kTRUE;
                            if (element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==0) {
                               leafinfo->fNext = new TFormLeafInfoNumerical(element->GetClassPointer()->GetCollectionProxy()->GetType());
                            }
                         } else {
                            leafinfo = new TFormLeafInfo(cl,offset,element);
                         }
                     }
                  } else if (type == TStreamerInfo::kOffsetL + TStreamerInfo::kAny ||
                             type == TStreamerInfo::kOffsetL + TStreamerInfo::kSTL ||
                             type == TStreamerInfo::kOffsetL + TStreamerInfo::kObject) {
                     // This is an embedded array of objects. We can not increase the offset.
                     
                     leafinfo = new TFormLeafInfo(cl,offset,element);
                     mustderef = kTRUE;

                  } else if (type == TStreamerInfo::kBase ||
                             type == TStreamerInfo::kStreamer ||
                             type == TStreamerInfo::kStreamLoop ) {
                     // Unsupported case.
                     Error("DefinedVariable","%s is a datamember of %s BUT is not yet of a supported type (%d)",
                           right,cl->GetName(),type);
                     return -2;
                  } else {
                     // Unknown and Unsupported case.
                     Error("DefinedVariable","%s is a datamember of %s BUT is not of a supported type (%d)",
                           right,cl->GetName(),type);
                     return -2;
                  }
               } else {
                  Error("DefinedVariable","%s is not a datamember of %s",work,cl->GetName());
                  return -1;
               }

               numberOfVarDim += RegisterDimensions(code,leafinfo);
               if (maininfo==0) {
                  maininfo = leafinfo;
               }
               if (previnfo==0) {
                  previnfo = leafinfo;
               } else if (previnfo!=leafinfo) {
                  previnfo->fNext = leafinfo;
                  previnfo = leafinfo;
               }
               if (previnfo->fNext) previnfo = previnfo->fNext;

               if (mustderef) leafinfo = 0;
               if (right[i]!='\0') {
                  cl = element->GetClassPointer();
               }
               current = &(work[0]);
               *current = 0;

               if (right[i] == '[') {
                 int bracket = i;
                 int bracket_level = 1;
                 int j;
                 for (j=++i; j<nchname && (bracket_level>0 || right[j]=='['); j++, i++) {
                   if (right[j]=='[')
                     bracket_level++;
                   else if (right[j]==']')
                     bracket_level--;
                 }
                 if (bracket_level != 0) {
                   //Error("DefinedVariable","Bracket unbalanced");
                   return -1;
                 }
                 strncat(dims,&right[bracket],j-bracket);
                 if (current!=work) *(--current) = '\0'; // remove bracket.
                 --i;
               }
            } else
               *current++ = right[i];
         }
         if (maininfo) {
            fDataMembers.AddAtAndExpand(maininfo,code);
            fLookupType[code] = kDataMember;
         }
      }

      if (strlen(work)!=0) {
         // We have something left to analyze.  Let's make this an error case!
         return -1;
      }

      if (IsLeafString(code)) {
         if (fLookupType[code]==kDirect && leaf->InheritsFrom("TLeafElement")) {
            TBranchElement * br = (TBranchElement*)leaf->GetBranch();
            if (br->GetType()==31) {
               // sub branch of a TClonesArray
               TStreamerInfo *info = br->GetInfo();
               TClass* cl = info->GetClass();
               TStreamerElement *element = (TStreamerElement *)info->GetElems()[br->GetID()];
               TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, element, kTRUE);
               Int_t offset;
               info->GetStreamerElement(element->GetName(),offset);
               clonesinfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
               fDataMembers.AddAtAndExpand(clonesinfo,code);
               fLookupType[code]=kDataMember;

            } else if (br->GetType()==41) {
               // sub branch of a Collection

               TStreamerInfo *info = br->GetInfo();
               TClass* cl = info->GetClass();
               TStreamerElement *element = (TStreamerElement *)info->GetElems()[br->GetID()];
               TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(cl, 0, element, kTRUE);
               Int_t offset;
               info->GetStreamerElement(element->GetName(),offset);
               collectioninfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
               fDataMembers.AddAtAndExpand(collectioninfo,code);
               fLookupType[code]=kDataMember;

            } else {
               fDataMembers.AddAtAndExpand(new TFormLeafInfoDirect(br),code);
               fLookupType[code]=kDataMember;
            }
         }
         action = kDefinedString;
         return code;
      }
      return code;
   }

//*-*- May be a graphical cut ?
   TCutG *gcut = (TCutG*)gROOT->GetListOfSpecials()->FindObject(name.Data());
   if (gcut) {
      if (gcut->GetObjectX()) {
         if(!gcut->GetObjectX()->InheritsFrom(TTreeFormula::Class())) {
            delete gcut->GetObjectX(); gcut->SetObjectX(0);
         }
      }
      if (gcut->GetObjectY()) {
         if(!gcut->GetObjectY()->InheritsFrom(TTreeFormula::Class())) {
            delete gcut->GetObjectY(); gcut->SetObjectY(0);
         }
      }

      Int_t code = fNcodes;

      if (strlen(gcut->GetVarX()) && strlen(gcut->GetVarY()) ) {

         TTreeFormula *fx = new TTreeFormula("f_x",gcut->GetVarX(),fTree);
         gcut->SetObjectX(fx);

         TTreeFormula *fy = new TTreeFormula("f_y",gcut->GetVarY(),fTree);
         gcut->SetObjectY(fy);

         fCodes[code] = -2;

      } else if (strlen(gcut->GetVarX())) {

         // Let's build the equivalent formula:
         // min(gcut->X) <= VarX <= max(gcut->Y)
         Double_t min = 0;
         Double_t max = 0;
         Int_t n = gcut->GetN();
         Double_t *x = gcut->GetX();
         min = max = x[0];
         for(Int_t i2 = 1; i2<n; i2++) {
           if (x[i2] < min) min = x[i2];
           if (x[i2] > max) max = x[i2];
         }
         TString formula = "(";
         formula += min;
         formula += "<=";
         formula += gcut->GetVarX();
         formula += " && ";
         formula += gcut->GetVarX();
         formula += "<=";
         formula += max;
         formula += ")";

         TTreeFormula *fx = new TTreeFormula("f_x",formula.Data(),fTree);
         gcut->SetObjectX(fx);

         fCodes[code] = -1;

      } else {

         Error("DefinedVariable","Found a TCutG without leaf information (%s)",
               gcut->GetName());
         return -1;

      }

      fMethods.AddAtAndExpand(gcut,code);
      fNcodes++;
      fLookupType[code] = -1;
      return code;
   }
   return -1;
}

TLeaf* TTreeFormula::GetLeafWithDatamember(const char* topchoice,
                                           const char* nextchoice,
                                           UInt_t readentry) const {

   // Return the leaf (if any) which contains an object containing
   // a data member which has the name provided in the arguments.

   TClass * cl = 0;
   TIter next (fTree->GetIteratorOnAllLeaves());
   TFormLeafInfo* clonesinfo = 0;
   TLeaf *leafcur;
   while ((leafcur = (TLeaf*)next())) {
      // The following code is used somewhere else, we need to factor it out.

      // Here since we are interested in data member, we want to consider only
      // 'terminal' branch and leaf.
      if (leafcur->InheritsFrom("TLeafObject") &&
          leafcur->GetBranch()->GetListOfBranches()->Last()==0) {
         TLeafObject *lobj = (TLeafObject*)leafcur;
         cl = lobj->GetClass();
      } else if (leafcur->InheritsFrom("TLeafElement") && leafcur->IsOnTerminalBranch()) {
         TLeafElement * lElem = (TLeafElement*) leafcur;
         if (lElem->IsOnTerminalBranch()) {
            TBranchElement *BranchEl = (TBranchElement *)leafcur->GetBranch();
            Int_t type = BranchEl->GetStreamerType();
            if (type==-1) {
               cl =  BranchEl->GetInfo()->GetClass();
            } else if (type>60) {
               // Case of an object data member.  Here we allow for the
               // variable name to be ommitted.  Eg, for Event.root with split
               // level 1 or above  Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
               TStreamerElement* element = (TStreamerElement*)
                  BranchEl->GetInfo()->GetElems()[BranchEl->GetID()];
               if (element) cl = element->GetClassPointer();
               else cl = 0;
            }
         }

      }
      if (clonesinfo) { delete clonesinfo; clonesinfo = 0; }
      if (cl ==  TClonesArray::Class()) {
         // We have a unsplit TClonesArray leaves
         // In this case we assume that cl is the class in which the TClonesArray
         // belongs.
         leafcur->GetBranch()->GetEntry(readentry);
         TClonesArray * clones;

         TBranch *branch = leafcur->GetBranch();
         if  (   branch->IsA()==TBranchElement::Class()
                 && ((TBranchElement*)branch)->GetType()==31) {

            // We have an unsplit TClonesArray as part of a split TClonesArray!

            // Let's not dig any further.  If the user really wants a data member
            // inside the nested TClonesArray, it has to specify it explicitly.

            continue;

         } else {
            clonesinfo = new TFormLeafInfoClones(cl, 0);
            clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leafcur,0);
         }
         if (clones) cl = clones->GetClass();
      } else if (cl && cl->GetCollectionProxy()) {
         
         // We have a unsplit Collection leaves
         // In this case we assume that cl is the class in which the TClonesArray
         // belongs.

         TBranch *branch = leafcur->GetBranch();
         if  (   branch->IsA()==TBranchElement::Class()
                 && ((TBranchElement*)branch)->GetType()==41) {

            // We have an unsplit Collection as part of a split Collection!

            // Let's not dig any further.  If the user really wants a data member
            // inside the nested Collection, it has to specify it explicitly.

            continue;

         } else {
            clonesinfo = new TFormLeafInfoCollection(cl, 0);
         }
         cl = cl->GetCollectionProxy()->GetValueClass();
      }
      if (cl) {
         // Now that we have the class, let's check if the topchoice is of its datamember
         // or if the nextchoice is a datamember of one of its datamember.
         Int_t offset;
         TStreamerInfo* info =  cl->GetStreamerInfo();
         TStreamerElement* element = info?info->GetStreamerElement(topchoice,offset):0;
         if (!element) {
            TIter next( cl->GetStreamerInfo()->GetElements() );
            TStreamerElement * curelem;
            while ((curelem = (TStreamerElement*)next())) {

               if (curelem->GetClassPointer() ==  TClonesArray::Class()) {
                  // In case of a TClonesArray we need to load the data and read the
                  // clonesArray object before being able to look into the class inside.
                  // We need to do that because we are never interested in the TClonesArray
                  // itself but only in the object inside.
                  TBranch *branch = leafcur->GetBranch();
                  TFormLeafInfo *leafinfo = 0;
                  if (clonesinfo) { 
                     leafinfo = clonesinfo; 
                  } else if (branch->IsA()==TBranchElement::Class()
                             && ((TBranchElement*)branch)->GetType()==31) {
                     // Case of a sub branch of a TClonesArray
                     TBranchElement *BranchEl = (TBranchElement*)branch;
                     TStreamerInfo *info = BranchEl->GetInfo();
                     TClass * mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
                     TStreamerElement *element =
                        (TStreamerElement *)info->GetElems()[BranchEl->GetID()];
                     leafinfo = new TFormLeafInfoClones(mother_cl, 0, element, kTRUE);
                  }

                  Int_t clones_offset;
                  cl->GetStreamerInfo()->GetStreamerElement(curelem->GetName(),clones_offset);
                  TFormLeafInfo* sub_clonesinfo = new TFormLeafInfo(cl, clones_offset, curelem);
                  if (leafinfo) 
                     if (leafinfo->fNext) leafinfo->fNext->fNext = sub_clonesinfo;
                     else leafinfo->fNext = sub_clonesinfo;
                  else leafinfo = sub_clonesinfo;

                  branch->GetEntry(readentry);

                  TClonesArray * clones = (TClonesArray*)leafinfo->GetValuePointer(leafcur,0);

                  delete leafinfo; clonesinfo = 0;
                  // If TClonesArray object does not exist we have no information, so let go
                  // on.  This is a weakish test since the TClonesArray object might exist in
                  // the next entry ... In other word, we ONLY rely on the information available
                  // in entry #0.
                  if (!clones) continue;
                  TClass *sub_cl = clones->GetClass();

                  // Now that we finally have the inside class, let's query it.
                  element = sub_cl->GetStreamerInfo()->GetStreamerElement(nextchoice,offset);
                  if (element) break;
               } // if clones array
               else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {

                  TClass *sub_cl = curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();

                 // Now that we finally have the inside class, let's query it.
                  if (sub_cl) element = sub_cl->GetStreamerInfo()->GetStreamerElement(nextchoice,offset);
                  if (element) break;                  

               }
            } // loop on elements
         }
         if (element) break;
         else cl = 0;
      }
   }
   delete clonesinfo;
   if (cl) {
      return leafcur;
   } else {
      return 0;
   }

}

Bool_t TTreeFormula::BranchHasMethod(TLeaf* leafcur,
                                     TBranch * branch,
                                     const char* method,
                                     const char* params,
                                     UInt_t readentry) const {
   // Return the leaf (if any) of the tree with contains an object of a class
   // having a method which has the name provided in the argument.

   TClass *cl = 0;
   TLeafObject* lobj = 0;

   // Since the user does not want this branch to be loaded anyway, we just
   // skip it.  This prevents us from warning the user that the method might
   // be on a disable branch.  However, and more usefully, this allows the
   // user to avoid error messages from branches that can not be currently
   // read without warnings/errors.
   if (branch->TestBit(kDoNotProcess)) return kFALSE;

   // The following code is used somewhere else, we need to factor it out.
   if (branch->InheritsFrom(TBranchObject::Class()) ) {

      lobj = (TLeafObject*)branch->GetListOfLeaves()->At(0);
      cl = lobj->GetClass();

   } else if (branch->InheritsFrom(TBranchElement::Class()) ) {
      TBranchElement *branchEl = (TBranchElement *)branch;
      Int_t type = branchEl->GetStreamerType();
      if (type==-1) {
         cl =  branchEl->GetInfo()->GetClass();
      } else if (type>60) {
         // Case of an object data member.  Here we allow for the
         // variable name to be ommitted.  Eg, for Event.root with split
         // level 1 or above  Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
         TStreamerElement* element = (TStreamerElement*)
            branchEl->GetInfo()->GetElems()[branchEl->GetID()];
         if (element) cl = element->GetClassPointer();
         else cl = 0;
         
         if (cl==TClonesArray::Class() && branchEl->GetType() == 31 ) {
            // we have a TClonesArray inside a split TClonesArray,

            // Let's not dig any further.  If the user really wants a data member
            // inside the nested TClonesArray, it has to specify it explicitly.

            cl = 0;
         }
         // NOTE do we need code for Collection here?
      }
   }
   if (cl == TClonesArray::Class()) {
      // We might be try to call a method of the top class inside a
      // TClonesArray.
      // Since the leaf was not terminal, we might have a splitted or
      // unsplitted and/or top leaf/branch.
      TClonesArray * clones = 0;
      TBranch *branchcur = branch;
      branchcur->GetEntry(readentry);
      if (branch->InheritsFrom(TBranchObject::Class()) ) {
         clones = (TClonesArray*)(lobj->GetObject());
      } else if (branch->InheritsFrom(TBranchElement::Class()) ) {
         // We do not know exactly where the leaf of the TClonesArray is
         // in the hierachy but we still need to get the correct class
         // holder.
         if (branchcur==((TBranchElement*)branchcur)->GetMother()
             || !leafcur || (!leafcur->IsOnTerminalBranch()) ) {
            clones = *(TClonesArray**)((TBranchElement*)branchcur)->GetAddress();
         }
         if (clones==0) {
            TBranch *branchcur = branch;
            branchcur->GetEntry(readentry);
            TClass * mother_cl;
            mother_cl = ((TBranchElement*)branchcur)->GetInfo()->GetClass();

            TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
            // if (!leafcur) { leafcur = (TLeaf*)branch->GetListOfLeaves()->At(0); }
            clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leafcur,0);
            // cl = clones->GetClass();
            delete clonesinfo;
         }
      }
      cl = clones->GetClass();
   } else if (cl && cl->GetCollectionProxy()) {
      cl = cl->GetCollectionProxy()->GetValueClass();
   }
   if (cl && cl->GetClassInfo() && cl->GetMethodAllAny(method)) {
      // Let's try to see if the function we found belongs to the current
      // class.  Note that this implementation currently can not work if
      // one the argument is another leaf or data member of the object.
      // (Anyway we do NOT support this case).
      TMethodCall *methodcall = new TMethodCall(cl, method, params);
      if (methodcall->GetMethod()) {
         // We have a method that works.
         // We will use it.
         return kTRUE;
      }
      delete methodcall;
   }
   cl = 0;
   return kFALSE;
}

Int_t TTreeFormula::GetRealInstance(Int_t instance, Int_t codeindex) {

      // Now let calculate what physical instance we really need.
      // Some redundant code is used to speed up the cases where
      // they are no dimensions.
      // We know that instance is less that fCumulUsedSize[0] so
      // we can skip the modulo when virt_dim is 0.
      Int_t real_instance = 0;
      Int_t virt_dim;
      Int_t max_dim = fNdimensions[codeindex];
      if ( max_dim ) {
         virt_dim = 0;
         max_dim--;

         if (!fManager->fMultiVarDim) {
            if (fIndexes[codeindex][0]>=0) {
               real_instance = fIndexes[codeindex][0] * fCumulSizes[codeindex][1];
            } else {
               Int_t local_index;
               local_index = ( instance / fManager->fCumulUsedSizes[virt_dim+1]);
               if (fIndexes[codeindex][0]==-2) {
                  // NOTE: Should we check that this is a valid index?
                  local_index = (Int_t)fVarIndexes[codeindex][0]->EvalInstance(local_index);
               }
               real_instance = local_index * fCumulSizes[codeindex][1];
               virt_dim ++;
            }
         } else {
            // NOTE: We assume that ONLY the first dimension of a leaf can have a variable
            // size AND contain the index for the size of yet another sub-dimension.
            // I.e. a variable size array inside a variable size array can only have its
            // size vary with the VERY FIRST physical dimension of the leaf.
            // Thus once the index of the first dimension is found, all other dimensions
            // are fixed!

            // NOTE: We could unroll some of this loops to avoid a few tests.
            TFormLeafInfo * info = 0;
            if (fHasMultipleVarDim[codeindex]) {
               info = (TFormLeafInfo *)(fDataMembers.At(codeindex));
               // if (info && info->GetVarDim()==-1) info = 0;
            }
            Int_t local_index;

            switch (fIndexes[codeindex][0]) {
            case -2:
               local_index = (Int_t)fVarIndexes[codeindex][0]->EvalInstance(instance);
               if (local_index<0) {
                  Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
                        fVarIndexes[codeindex][0]->GetTitle(),
                        local_index,
                        GetTitle());
                  local_index = 0;
               }
               break;
            case -1: {
                  local_index = 0;
                  Int_t virt_accum = 0;
                  do {
                     virt_accum += fManager->fCumulUsedVarDims->At(local_index);
                     local_index++;
                  } while( instance >= virt_accum );
                  local_index--;
                  instance -= (virt_accum - fManager->fCumulUsedVarDims->At(local_index));
                  virt_dim ++;
               }
               break;
            default:
               local_index = fIndexes[codeindex][0];
            }

            // Inform the (appropriate) MultiVarLeafInfo that the clones array index is
            // local_index.

            if (fManager->fVarDims[kMAXFORMDIM]) {
               fManager->fCumulUsedSizes[kMAXFORMDIM] = fManager->fVarDims[kMAXFORMDIM]->At(local_index);
            } else {
               fManager->fCumulUsedSizes[kMAXFORMDIM] = fManager->fUsedSizes[kMAXFORMDIM];
            }
            for(Int_t d = kMAXFORMDIM-1; d>0; d--) {
               if (fManager->fVarDims[d]) {
                  fManager->fCumulUsedSizes[d] = fManager->fCumulUsedSizes[d+1] * fManager->fVarDims[d]->At(local_index);
               } else {
                  fManager->fCumulUsedSizes[d] = fManager->fCumulUsedSizes[d+1] * fManager->fUsedSizes[d];
               }
            }
            if (info) {
               // When we have multiple variable dimensions, the LeafInfo only expect
               // the instance after the primary index has been set.
               info->SetPrimaryIndex(local_index);
               real_instance = 0;

               // Let's update fCumulSizes for the rest of the code.
               Int_t vdim = info->GetVarDim();
               fCumulSizes[codeindex][vdim] =  info->GetSize(local_index)
                                              *fCumulSizes[codeindex][vdim+1];
               for(Int_t k=vdim -1; k>0; k++) {
                  fCumulSizes[codeindex][k] = fCumulSizes[codeindex][k+1]*fFixedSizes[codeindex][k];
               }
            } else {
               real_instance = local_index * fCumulSizes[codeindex][1];
            }
         }
         if (max_dim>0) {
            for (Int_t dim = 1; dim < max_dim; dim++) {
               if (fIndexes[codeindex][dim]>=0) {
                  real_instance += fIndexes[codeindex][dim] * fCumulSizes[codeindex][dim+1];
               } else {
                  Int_t local_index;
                  if (virt_dim && fManager->fCumulUsedSizes[virt_dim]>1) {
                     local_index = ( ( instance % fManager->fCumulUsedSizes[virt_dim] )
                                     / fManager->fCumulUsedSizes[virt_dim+1]);
                  } else {
                     local_index = ( instance / fManager->fCumulUsedSizes[virt_dim+1]);
                  }
                  if (fIndexes[codeindex][dim]==-2) {
                     // NOTE: Should we check that this is a valid index?
                     local_index = (Int_t)fVarIndexes[codeindex][dim]->EvalInstance(local_index);
                     if (local_index<0 ||
                         local_index>=(fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1])) {
                       Error("EvalInstance","Index %s is out of bound (%d/%d) in formula %s",
                             fVarIndexes[codeindex][dim]->GetTitle(),
                             local_index,
                             (fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1]),
                             GetTitle());
                       local_index = (fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1])-1;
                     }
                  }
                  real_instance += local_index * fCumulSizes[codeindex][dim+1];
                  virt_dim ++;
               }
            }
            if (fIndexes[codeindex][max_dim]>=0) {
               real_instance += fIndexes[codeindex][max_dim];
            } else {
               Int_t local_index;
               if (virt_dim && fManager->fCumulUsedSizes[virt_dim]>1) {
                  local_index = instance % fManager->fCumulUsedSizes[virt_dim];
               } else {
                  local_index = instance;
               }
               if (fIndexes[codeindex][max_dim]==-2) {
                  local_index = (Int_t)fVarIndexes[codeindex][max_dim]->EvalInstance(local_index);
                  if (local_index<0 ||
                         local_index>=fCumulSizes[codeindex][max_dim]) {
                     Error("EvalInstance","Index %s is of out bound (%d/%d) in formula %s",
                           fVarIndexes[codeindex][max_dim]->GetTitle(),
                           local_index,
                           fCumulSizes[codeindex][max_dim],
                           GetTitle());
                     local_index = fCumulSizes[codeindex][max_dim]-1;
                  }
               }
               real_instance += local_index;
            }
         } // if (max_dim-1>0)
      } // if (max_dim)

      return real_instance;
}

//______________________________________________________________________________
TClass* TTreeFormula::EvalClass() const
{
//*-*-*-*-*-*-*-*-*-*-*Evaluate the class of this treeformula*-*-*-*-*-*-*-*-*-*
//*-*                  ======================================
//
//  If the 'value' of this formula is a simple pointer to an object,
//  this function returns the TClass corresponding to its type.

   if (fNoper != 1 || fNcodes <=0 ) return 0;

   TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
   switch(fLookupType[0]) {
      case kDirect: {
         if (leaf->IsA()==TLeafObject::Class()) {
            return ((TLeafObject*)leaf)->GetClass();
         } else if ( leaf->IsA()==TLeafElement::Class()) {
            TBranchElement * branch = (TBranchElement*)((TLeafElement*)leaf)->GetBranch();
            TStreamerInfo * info = branch->GetInfo();
            Int_t id = branch->GetID();
            if (id>=0) {
               if (info==0 || info->GetElems()==0) {
                  // we probably do not have a way to know the class of the object.
                  return 0;
               }
               TStreamerElement* elem = (TStreamerElement*)info->GetElems()[id];
               if (elem==0) {
                  // we probably do not have a way to know the class of the object.
                  return 0;
               } else {
                  return gROOT->GetClass( elem->GetTypeName() );
               }
            } else return gROOT->GetClass( branch->GetClassName() );
         } else {
            return 0;
         }
      }
      case kMethod: return 0; // kMethod is deprecated so let's no waste time implementing this.
      case kDataMember: {
         TObject *obj = fDataMembers.UncheckedAt(0);
         if (!obj) return 0;
         return ((TFormLeafInfo*)obj)->GetClass();
      }
      default: return 0;
   }


}

//______________________________________________________________________________
void* TTreeFormula::EvalObject(int instance)
{
//*-*-*-*-*-*-*-*-*-*-*Evaluate this treeformula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =========================
//
//  Return the address of the object pointed to by the formula.
//  Return 0 if the formula is not a single object
//  The object type can be retrieved using by call EvalClass();

   if (fNoper != 1 || fNcodes <=0 ) return 0;
   

   switch (fLookupType[0]) {
      case kIndexOfEntry: 
      case kEntries:      
      case kLength:       
      case kIteration:    
        return 0;
   }

   TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);

   Int_t real_instance = GetRealInstance(instance,0);

   if (!instance) leaf->GetBranch()->GetEntry(leaf->GetBranch()->GetTree()->GetReadEntry());
   else if (real_instance>fNdata[0]) return 0;
   if (fAxis) {
      return 0;
   }
   switch(fLookupType[0]) {
      case kDirect: {
        if (real_instance) {
          Warning("EvalObject","Not yet implement for kDirect and arrays (for %s).\nPlease contact the developers",GetName());
        }
        return leaf->GetValuePointer();
      }
      case kMethod: return GetValuePointerFromMethod(0,leaf);
      case kDataMember: return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValuePointer(leaf,real_instance);
      default: return 0;
   }


}


//______________________________________________________________________________
const char* TTreeFormula::EvalStringInstance(Int_t instance)
{
   const Int_t kMAXSTRINGFOUND = 10;
   const char *stringStack[kMAXSTRINGFOUND];

   if (fNoper==1 && fNcodes>0 && IsString()) {
      TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);

      Int_t real_instance = GetRealInstance(instance,0);

      if (!instance) leaf->GetBranch()->GetEntry(leaf->GetBranch()->GetTree()->GetReadEntry());
      else if (real_instance>fNdata[0]) return 0;

      if (fLookupType[0]==kDirect) {
         return (char*)leaf->GetValuePointer();
      } else {
         return  (char*)GetLeafInfo(0)->GetValuePointer(leaf,0);
      }
   }

   EvalInstance(instance,stringStack);

   return stringStack[0];
}

#define TT_EVAL_INIT                                                                            \
   TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);                                                \
                                                                                                \
   const Int_t real_instance = GetRealInstance(instance,0);                                     \
                                                                                                \
   /* Since the only operation in this formula is reading this branch,                          \
      we are guaranteed that this function is first called with instance==0 and                 \
      hence we are guaranteed that the branch is always properly read */                        \
   if (!instance) leaf->GetBranch()->GetEntry(leaf->GetBranch()->GetTree()->GetReadEntry());    \
   else if (real_instance>fNdata[0]) return 0;                                                  \
                                                                                                \
   if (fAxis) {                                                                                 \
      char * label;                                                                             \
      /* This portion is a duplicate (for speed reason) of the code                             \
         located  in the main for loop at "a tree string" (and in EvalStringInstance) */        \
      if (fLookupType[0]==kDirect) {                                                            \
         label = (char*)leaf->GetValuePointer();                                                \
      } else {                                                                                  \
         label = (char*)GetLeafInfo(0)->GetValuePointer(leaf,0);                                \
      }                                                                                         \
      Int_t bin = fAxis->FindBin(label);                                                        \
      return bin-0.5;                                                                           \
   } 

#define TT_EVAL_INIT_LOOP                                                                       \
   TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(code);                                             \
                                                                                                \
   /* Now let calculate what physical instance we really need.  */                              \
   const Int_t real_instance = GetRealInstance(instance,code);                                  \
                                                                                                \
   if (!instance) leaf->GetBranch()->GetEntry(leaf->GetBranch()->GetTree()->GetReadEntry());    \
   else {                                                                                       \
      /* In the cases where we are behind (i.e. right of) a potential boolean optimization      \
         this tree variable reading may have not been executed with instance==0 which would     \
         result in the branch being potentially not read in. */                                 \
      if (haveSeenBooleanOptimization) {                                                        \
         TBranch *br = leaf->GetBranch();                                                       \
         Int_t treeEntry = br->GetTree()->GetReadEntry();                                       \
         if (br->GetReadEntry() != treeEntry) br->GetEntry( treeEntry );                        \
      }                                                                                         \
      if (real_instance>fNdata[code]) return 0;                                                 \
   }
                
//______________________________________________________________________________
Double_t TTreeFormula::EvalInstance(Int_t instance, const char *stringStackArg[])
{
//*-*-*-*-*-*-*-*-*-*-*Evaluate this treeformula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =========================
//

// Note that the redundance and structure in this code is tailored to improve
// efficiencies.


   if (fNoper == 1 && fNcodes > 0) {

      switch (fLookupType[0]) {
         case kDirect:     { 
            TT_EVAL_INIT;
            Double_t result = leaf->GetValue(real_instance); 
            return result;
         }
         case kMethod:     { TT_EVAL_INIT; return GetValueFromMethod(0,leaf);  }
         case kDataMember: { TT_EVAL_INIT; return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValue(leaf,real_instance); }
         case kIndexOfEntry: return fTree->GetReadEntry();
         case kEntries:      return fTree->GetEntries();
         case kLength:       return fManager->fNdata;
         case kIteration:    return instance;
          
         case -1: break; 
      }
      switch (fCodes[0]) {
         case -2: {
            TCutG *gcut = (TCutG*)fMethods.At(0);
            TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
            TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
            Double_t xcut = fx->EvalInstance(instance);
            Double_t ycut = fy->EvalInstance(instance);
            return gcut->IsInside(xcut,ycut);
         }
         case -1: {
            TCutG *gcut = (TCutG*)fMethods.At(0);
            TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
            return fx->EvalInstance(instance);
         }
         default: return 0;
      }
   }


   Double_t tab[kMAXFOUND];
   const Int_t kMAXSTRINGFOUND = 10;
   const char *stringStackLocal[kMAXSTRINGFOUND];
   const char **stringStack = stringStackArg?stringStackArg:stringStackLocal;
   Bool_t haveSeenBooleanOptimization = kFALSE;

   Int_t pos  = 0;
   Int_t pos2 = 0;

   for (Int_t i=0; i<fNoper ; ++i) { 
      
      const Int_t oper = GetOper()[i];
      const Int_t newaction = oper >> kTFOperShift;
      
      if (newaction<kDefinedVariable) {
         // TFormula operands.

         // one of the most used cases
         if (newaction==kConstant) { pos++; tab[pos-1] = fConst[(oper & kTFOperMask)]; continue; }
         
         switch(newaction) {

            case kEnd        : return tab[0];
            case kAdd        : pos--; tab[pos-1] += tab[pos]; continue;
            case kSubstract  : pos--; tab[pos-1] -= tab[pos]; continue;
            case kMultiply   : pos--; tab[pos-1] *= tab[pos]; continue;
            case kDivide     : pos--; if (tab[pos] == 0) tab[pos-1] = 0; //  division by 0
                                      else               tab[pos-1] /= tab[pos];
                                      continue;
            case kModulo     : {pos--; Int_t int1((Int_t)tab[pos-1]); Int_t int2((Int_t)tab[pos]); tab[pos-1] = Double_t(int1%int2); continue;}

            case kcos  : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
            case ksin  : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
            case ktan  : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
                         else tab[pos-1] = TMath::Tan(tab[pos-1]);
                         continue;
            case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} //  indetermination
                         else tab[pos-1] = TMath::ACos(tab[pos-1]);
                         continue;
            case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} //  indetermination
                         else tab[pos-1] = TMath::ASin(tab[pos-1]);
                         continue;
            case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
            case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
            case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
            case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
                         else tab[pos-1] = TMath::TanH(tab[pos-1]);
                         continue;
            case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} //  indetermination
                         else tab[pos-1] = TMath::ACosH(tab[pos-1]);
                         continue;
            case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
            case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
                     else tab[pos-1] = TMath::ATanH(tab[pos-1]); continue;
            case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;

            case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
            case kpow  : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
            case ksq   : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
            case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;

            case kstrstr : pos2 -= 2; pos++;if (strstr(stringStack[pos2],stringStack[pos2+1])) tab[pos-1]=1;
                                        else tab[pos-1]=0; continue;

            case kmin : pos--; tab[pos-1] = TMath::Min(tab[pos-1],tab[pos]); continue;
            case kmax : pos--; tab[pos-1] = TMath::Max(tab[pos-1],tab[pos]); continue;

            case klog  : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
                         else {tab[pos-1] = 0;} //{indetermination }
                          continue;
            case kexp  : { Double_t dexp = tab[pos-1];
                           if (dexp < -700) {tab[pos-1] = 0; continue;}
                           if (dexp >  700) {tab[pos-1] = TMath::Exp(700); continue;}
                           tab[pos-1] = TMath::Exp(dexp); continue;
                         }
            case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
                         else {tab[pos-1] = 0;} //{indetermination }
                         continue;

            case kpi   : pos++; tab[pos-1] = TMath::ACos(-1); continue;

            case kabs  : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
            case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
            case kint  : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
            case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
            case krndm : pos++; tab[pos-1] = gRandom->Rndm(1); continue;

            case kAnd  : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
                                else tab[pos-1]=0; continue;
            case kOr   : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
                                else tab[pos-1]=0; continue;

            case kEqual      : pos--; tab[pos-1] = (tab[pos-1] == tab[pos]) ? 1 : 0; continue;
            case kNotEqual   : pos--; tab[pos-1] = (tab[pos-1] != tab[pos]) ? 1 : 0; continue;
            case kLess       : pos--; tab[pos-1] = (tab[pos-1] <  tab[pos]) ? 1 : 0; continue;
            case kGreater    : pos--; tab[pos-1] = (tab[pos-1] >  tab[pos]) ? 1 : 0; continue;
            case kLessThan   : pos--; tab[pos-1] = (tab[pos-1] <= tab[pos]) ? 1 : 0; continue;
            case kGreaterThan: pos--; tab[pos-1] = (tab[pos-1] >= tab[pos]) ? 1 : 0; continue;
            case kNot        :        tab[pos-1] = (tab[pos-1] !=        0) ? 0 : 1; continue;

            case kStringEqual : pos2 -= 2; pos++; if (!strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
                                                  else tab[pos-1]=0; continue;
            case kStringNotEqual: pos2 -= 2; pos++;if (strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
                                                   else tab[pos-1]=0; continue;

            case kBitAnd    : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
            case kBitOr     : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
            case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
            case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
               
            case kStringConst: {
               // String
               pos2++; stringStack[pos2-1] = (char*)fExpr[i].Data();
               continue;
            }

            case kBoolOptimize: {
               // boolean operation optimizer
               
               int param = (oper & kTFOperMask);
               Bool_t skip = kFALSE;
               int op = param % 10; // 1 is && , 2 is ||
               
               if (op == 1 && (!tab[pos-1]) ) { 
                  // &&: skip the right part if the left part is already false
                  
                  skip = kTRUE;
                  
                  // Preserve the existing behavior (i.e. the result of a&&b is
                  // either 0 or 1)
                  tab[pos-1] = 0;
                  
               } else if (op == 2 && tab[pos-1] ) {  
                  // ||: skip the right part if the left part is already true
                  
                  skip = kTRUE;
                  
                  // Preserve the existing behavior (i.e. the result of a||b is
                  // either 0 or 1)
                  tab[pos-1] = 1;
               }
               
               if (skip) {
                  int toskip = param / 10;
                  i += toskip;
               }
               haveSeenBooleanOptimization = kTRUE;
               continue;
            }

            case kFunctionCall: {
               // an external function call
               
               int param = (oper & kTFOperMask);
               int fno   = param / 1000;
               int nargs = param % 1000;
               
               // Retrieve the function
               TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
               
               // Set the arguments
               TString args;
               if (nargs) {
                  UInt_t argloc = pos-nargs;
                  for(Int_t j=0;j<nargs;j++,argloc++,pos--) {
                     if (TMath::IsNaN(tab[argloc])) {
                        // TString would add 'nan' this is not what we want 
                        // so let's do somethign else
                        args += "(double)(0x8000000000000)";
                     } else {
                        args += tab[argloc];
                     }
                     args += ',';
                  }
                  args.Remove(args.Length()-1);
               }
               pos++;
               Double_t ret;
               method->Execute(args,ret);
               tab[pos-1] = ret; // check for the correct conversion!
           
               continue;
            }

//         case kParameter:    { pos++; tab[pos-1] = fParams[(oper & kTFOperMask)]; continue; }
         }

      } else {
         // TTreeFormula operands.

         // a tree variable (the most used case).

         if (newaction == kDefinedVariable) {

            const Int_t code = (oper & kTFOperMask); 
            const Int_t lookupType = fLookupType[code];
            switch (lookupType) {
               case kIndexOfEntry: tab[pos++] = fTree->GetReadEntry(); continue;
               case kEntries:      tab[pos++] = fTree->GetEntries(); continue;
               case kLength:       tab[pos++] = fManager->fNdata; continue;
               case kIteration:    tab[pos++] = instance; continue;

               case kDirect:     { TT_EVAL_INIT_LOOP; tab[pos++] = leaf->GetValue(real_instance); continue; }
               case kMethod:     { TT_EVAL_INIT_LOOP; tab[pos++] = GetValueFromMethod(code,leaf); continue; }
               case kDataMember: { TT_EVAL_INIT_LOOP; tab[pos++] = ((TFormLeafInfo*)fDataMembers.UncheckedAt(code))->
                                          GetValue(leaf,real_instance); continue; }
               case -1: break;
               default: tab[pos++] = 0; continue;
            }
            switch (fCodes[code]) {
               case -2: {
                  TCutG *gcut = (TCutG*)fMethods.At(code);
                  TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
                  TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
                  Double_t xcut = fx->EvalInstance(instance);
                  Double_t ycut = fy->EvalInstance(instance);
                  tab[pos++] = gcut->IsInside(xcut,ycut);
                  continue;
               }
               case -1: {
                  TCutG *gcut = (TCutG*)fMethods.At(code);
                  TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
                  tab[pos++] = fx->EvalInstance(instance);
                  continue;
               }
               default: {
                  tab[pos++] = 0;
                  continue;
               }
            } 
         }
         switch(newaction) {

            // a TTree Variable Alias (i.e. a sub-TTreeFormula)
            case kAlias: {
               int aliasN = i;
               TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
               Assert(subform);
              
               Double_t param = subform->EvalInstance(instance);
              
               tab[pos] = param; pos++;
               continue;
            }
            // a TTree Variable Alias String (i.e. a sub-TTreeFormula)
            case kAliasString: {
               int aliasN = i;
               TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
               Assert(subform);
              
               pos2++;
               stringStack[pos2-1] = subform->EvalStringInstance(instance);
               continue;
            }
            // a TTree Variable Alternate (i.e. a sub-TTreeFormula)
            case kAlternate: {
               int alternateN = i;
               TTreeFormula *primary = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
            
               // First check whether we are in range for the primary formula
               if (instance < primary->GetNdata()) {
               
                  Double_t param = primary->EvalInstance(instance);
               
                  ++i; // skip the alternate value.
               
                  tab[pos] = param; pos++;
               } else {
                  // The primary is not in rancge, we will calculate the alternate value
                  // via the next operation (which will be a intentional).
            
                  // kAlias no operations
               }
               continue;
            }
            case kAlternateString: {
               int alternateN = i;
               TTreeFormula *primary = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
            
               // First check whether we are in range for the primary formula
               if (instance < primary->GetNdata()) {
               
                  pos2++;
                  stringStack[pos2-1] = primary->EvalStringInstance(instance);
               
                  ++i; // skip the alternate value.
               
               } else {
                  // The primary is not in rancge, we will calculate the alternate value
                  // via the next operation (which will be a kAlias).
            
                  // intentional no operations
               }
               continue;
            }

            // a tree string
            case kDefinedString: {
               Int_t string_code = (oper & kTFOperMask); 
               TLeaf *leafc = (TLeaf*)fLeaves.UncheckedAt(string_code);

               // Now let calculate what physical instance we really need.
               const Int_t real_instance = GetRealInstance(instance,string_code);
               
               if (!instance) leafc->GetBranch()->GetEntry(leafc->GetBranch()->GetTree()->GetReadEntry());
               else {
                  // In the cases where we are beind (i.e. right of) a potential boolean optimization
                  // this tree variable reading may have not been executed with instance==0 which would
                  // result in the branch being potentially not read in.
                  if (haveSeenBooleanOptimization) {
                     TBranch *br = leafc->GetBranch();
                     Int_t treeEntry = br->GetTree()->GetReadEntry();
                     if (br->GetReadEntry() != treeEntry) br->GetEntry( treeEntry );
                  }
                  if (real_instance>fNdata[string_code]) return 0;
               }
               pos2++;
               if (fLookupType[string_code]==kDirect) {
                  stringStack[pos2-1] = (char*)leafc->GetValuePointer();
               } else {
                  stringStack[pos2-1] = (char*)GetLeafInfo(string_code)->GetValuePointer(leafc,real_instance);
               }
               continue;
            }

         }
      }

      Assert(i<fNoper);
   }
   
   Double_t result = tab[0];
   return result;
}

//______________________________________________________________________________
TFormLeafInfo *TTreeFormula::GetLeafInfo(Int_t code) const
{
//*-*-*-*-*-*-*-*Return DataMember corresponding to code*-*-*-*-*-*
//*-*            =======================================
//
//  function called by TLeafObject::GetValue
//  with the value of fLookupType computed in TTreeFormula::DefinedVariable

   return (TFormLeafInfo *)fDataMembers.UncheckedAt(code);

}

//______________________________________________________________________________
TLeaf *TTreeFormula::GetLeaf(Int_t n) const
{
//*-*-*-*-*-*-*-*Return leaf corresponding to serial number n*-*-*-*-*-*
//*-*            ============================================
//

   return (TLeaf*)fLeaves.UncheckedAt(n);
}

//______________________________________________________________________________
TMethodCall *TTreeFormula::GetMethodCall(Int_t code) const
{
//*-*-*-*-*-*-*-*Return methodcall corresponding to code*-*-*-*-*-*
//*-*            =======================================
//
//  function called by TLeafObject::GetValue
//  with the value of fLookupType computed in TTreeFormula::DefinedVariable

   return (TMethodCall *)fMethods.UncheckedAt(code);

}

//______________________________________________________________________________
Int_t TTreeFormula::GetNdata()
{
//*-*-*-*-*-*-*-*Return number of available instances in the formula-*-*-*-*-*-*
//*-*            ===================================================
//

  return fManager->GetNdata();
}

//______________________________________________________________________________
Double_t TTreeFormula::GetValueFromMethod(Int_t i, TLeaf *leaf) const
{
//*-*-*-*-*-*-*-*Return result of a leafobject method*-*-*-*-*-*-*-*
//*-*            ====================================
//

   TMethodCall *m = GetMethodCall(i);

   if (m==0) return 0;

   void *thisobj;
   if (leaf->InheritsFrom("TLeafObject") ) thisobj = ((TLeafObject*)leaf)->GetObject();
   else {
      TBranchElement * branch = (TBranchElement*)((TLeafElement*)leaf)->GetBranch();
      Int_t offset =  branch->GetInfo()->GetOffsets()[branch->GetID()];
      char* address = (char*)branch->GetAddress();

      if (address) thisobj = (char*) *(void**)(address+offset);
      else thisobj = branch->GetObject();
   }

   TMethodCall::EReturnType r = m->ReturnType();

   if (r == TMethodCall::kLong) {
      Long_t l;
      m->Execute(thisobj, l);
      return (Double_t) l;
   }
   if (r == TMethodCall::kDouble) {
      Double_t d;
      m->Execute(thisobj, d);
      return (Double_t) d;
   }
   m->Execute(thisobj);

   return 0;

}

//______________________________________________________________________________
void* TTreeFormula::GetValuePointerFromMethod(Int_t i, TLeaf *leaf) const
{
//*-*-*-*-*-*-*-*Return result of a leafobject method*-*-*-*-*-*-*-*
//*-*            ====================================
//

   TMethodCall *m = GetMethodCall(i);

   if (m==0) return 0;

   void *thisobj;
   if (leaf->InheritsFrom("TLeafObject") ) thisobj = ((TLeafObject*)leaf)->GetObject();
   else {
      TBranchElement * branch = (TBranchElement*)((TLeafElement*)leaf)->GetBranch();
      Int_t offset =  branch->GetInfo()->GetOffsets()[branch->GetID()];
      char* address = (char*)branch->GetAddress();

      if (address) thisobj = (char*) *(void**)(address+offset);
      else thisobj = branch->GetObject();
   }

   TMethodCall::EReturnType r = m->ReturnType();

   if (r == TMethodCall::kLong) {
      Long_t l;
      m->Execute(thisobj, l);
      return 0; 
   }
   if (r == TMethodCall::kDouble) {
      Double_t d;
      m->Execute(thisobj, d);
      return 0;
   }
   if (r == TMethodCall::kOther) {
      char *c;
      m->Execute(thisobj, &c);
      return c;
   }
   m->Execute(thisobj);

   return 0;

}

//______________________________________________________________________________
Bool_t TTreeFormula::IsInteger() const
{
   // return TRUE if the formula corresponds to one single Tree leaf
   // and this leaf is short, int or unsigned short, int
   // When a leaf is of type integer, the generated histogram is forced
   // to have an integer bin width

   if (fNoper==2 && GetAction(0)==kAlternate) {
      TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
      Assert(subform);
      return subform->IsInteger();
   }

   if (fNoper > 1) return kFALSE;

   if (GetAction(0)==kAlias) {
      TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
      Assert(subform);
      return subform->IsInteger();
   }
   
   if (fLeaves.GetEntries() != 1) {
      switch (fLookupType[0]) {
         case kIndexOfEntry:
         case kEntries:
         case kLength:
         case kIteration:
           return kTRUE;
         default:
           return kFALSE;
      }
   }
   
   if (EvalClass()==TBits::Class()) return kTRUE;

   return IsLeafInteger(0);
}

//______________________________________________________________________________
Bool_t TTreeFormula::IsLeafInteger(Int_t code) const
{
   // return TRUE if the leaf corresponding to code is short, int or unsigned
   // short, int When a leaf is of type integer, the generated histogram is
   // forced to have an integer bin width

   TLeaf *leaf = (TLeaf*)fLeaves.At(code);
   if (!leaf) {
      switch (fLookupType[code]) {
         case kIndexOfEntry:
         case kEntries:
         case kLength:
         case kIteration:
           return kTRUE;
         default:
           return kFALSE;
      }      
   }
   if (fAxis) return kTRUE;
   TFormLeafInfo * info;
   switch (fLookupType[code]) {
      case kMethod:
      case kDataMember:
         info = GetLeafInfo(code);
         return info->IsInteger();
      case kDirect:
         break;
   }
   if (!strcmp(leaf->GetTypeName(),"Int_t"))    return kTRUE;
   if (!strcmp(leaf->GetTypeName(),"Short_t"))  return kTRUE;
   if (!strcmp(leaf->GetTypeName(),"UInt_t"))   return kTRUE;
   if (!strcmp(leaf->GetTypeName(),"UShort_t")) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TTreeFormula::IsString() const
{
   // return TRUE if the formula is a string

   return TestBit(kIsCharacter) || (fNoper==1 && IsString(0));
}

//______________________________________________________________________________
Bool_t TTreeFormula::IsString(Int_t oper) const
{ 
   // (fOper[i]>=105000 && fOper[i]<110000) || fOper[i] == kStrings) 

   // return true if the expression at the index 'oper' is to be treated as 
   // as string

   if (TFormula::IsString(oper)) return kTRUE;
   if (GetAction(oper)==kDefinedString) return kTRUE;
   if (GetAction(oper)==kAliasString) return kTRUE;
   if (GetAction(oper)==kAlternateString) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
Bool_t  TTreeFormula::IsLeafString(Int_t code) const
{   
   // return TRUE if the leaf or data member corresponding to code is a string
   TLeaf *leaf = (TLeaf*)fLeaves.At(code);
   if (!leaf) return kFALSE;
   
   TFormLeafInfo * info;
   switch(fLookupType[code]) {
      case kDirect:
         if ( !leaf->IsUnsigned() && (leaf->InheritsFrom("TLeafC") || leaf->InheritsFrom("TLeafB") ) ) {
            // Need to find out if it is an 'array' or a pointer.
            if (leaf->GetLenStatic() > 1) return kTRUE;
            
            // Now we need to differantiate between a variable length array and
            // a TClonesArray.
            if (leaf->GetLeafCount()) {
               const char* indexname = leaf->GetLeafCount()->GetName();
               if (indexname[strlen(indexname)-1] == '_' ) {
                  // This in a clones array
                  return kFALSE;
               } else {
                  // this is a variable length char array
                  return kTRUE;
               }
               }
         } else if (leaf->InheritsFrom("TLeafElement")) {
            TBranchElement * br = (TBranchElement*)leaf->GetBranch();
            Int_t bid = br->GetID();
            if (bid < 0) return kFALSE;
            if (br->GetInfo()==0 || br->GetInfo()->GetElems()==0) {
               // Case where the file is corrupted is some ways.
               // We can not get to the actual type of the data
               // let's assume it is NOT a string.
               return kFALSE;
            }
            TStreamerElement * elem = (TStreamerElement*) br->GetInfo()->GetElems()[bid];
            if (!elem) {
               // Case where the file is corrupted is some ways.
               // We can not get to the actual type of the data
               // let's assume it is NOT a string.
               return kFALSE;
            }
            if (elem->GetNewType()== TStreamerInfo::kOffsetL +kChar_t) {
               // Check whether a specific element of the string is specified!
               if (fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
               return kTRUE;
            }
            if ( elem->GetNewType()== TStreamerInfo::kCharStar) {
               // Check whether a specific element of the string is specified!
               if (fNdimensions[code] && fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
               return kTRUE;
            }
            return kFALSE;
         } else {
            return kFALSE;
         }
      case kMethod:
         //TMethodCall *m = GetMethodCall(code);
         //TMethodCall::EReturnType r = m->ReturnType();
         return kFALSE;
      case kDataMember:
         info = GetLeafInfo(code);
         return info->IsString();
      default:
         return kFALSE;
   }
}

//______________________________________________________________________________
char *TTreeFormula::PrintValue(Int_t mode) const
{
//*-*-*-*-*-*-*-*Return value of variable as a string*-*-*-*-*-*-*-*
//*-*            ====================================
//
//      mode = -2 : Print line with ***
//      mode = -1 : Print column names
//      mode = 0  : Print column values

   return PrintValue(mode,0);
}

//______________________________________________________________________________
char *TTreeFormula::PrintValue(Int_t mode, Int_t instance) const
{
//*-*-*-*-*-*-*-*Return value of variable as a string*-*-*-*-*-*-*-*
//*-*            ====================================
//
//      mode = -2 : Print line with ***
//      mode = -1 : Print column names
//      mode = 0  : Print column values

   const int kMAXLENGTH = 1024;
   static char value[kMAXLENGTH];

   if (mode == -2) {
      for (int i = 0; i < kMAXLENGTH-1; i++)
         value[i] = '*';
      value[kMAXLENGTH-1] = 0;
   } else if (mode == -1)
      sprintf(value, "%s", GetTitle());

   if (fNstring && fNval==0 && fNoper==1) {
      if (mode == 0) {
         TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
         leaf->GetBranch()->GetEntry(leaf->GetBranch()->GetTree()->GetReadEntry());
         char * val = 0;
         if (fLookupType[0]==kDirect) {
            val = (char*)leaf->GetValuePointer();
         } else {
            val = (char*)GetLeafInfo(0)->GetValuePointer(leaf,0);
         }
         if (val) {
            strncpy(value, val, kMAXLENGTH-1);
         } else {
            //strncpy(value, " ", kMAXLENGTH-1);
         }

         value[kMAXLENGTH-1] = 0;
      }
   } else {
      if (mode == 0) {
         //NOTE: This is terrible form ... but is forced upon us by the fact that we can not
         //use the mutable keyword AND we should keep PrintValue const.
//          Int_t ndata = ((TTreeFormula*)this)->GetNdata();
         Int_t real_instance = ((TTreeFormula*)this)->GetRealInstance(instance,0);
//          fprintf(stderr,"for %s: ndata %d fNdata %d real_insta %d\n",
//                  GetTitle(),ndata,fNdata[0], real_instance);
         if (real_instance<fNdata[0]) {
            sprintf(value,"%9.9g",((TTreeFormula*)this)->EvalInstance(instance));
            char *expo = strchr(value,'e');
            if (expo) {
               if (value[0] == '-') strcpy(expo-6,expo);
               else                 strcpy(expo-5,expo);
            }
         } else {
            sprintf(value,"         ");
         }
      }
   }
   return &value[0];
}

//______________________________________________________________________________
void TTreeFormula::SetAxis(TAxis *axis)
{
   if (!axis) {fAxis = 0; return;}
   if (TestBit(kIsCharacter)) {
      fAxis = axis;
      if (fNoper==1 && GetAction(0)==kAliasString){
         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
         Assert(subform); 
         subform->SetAxis(axis);
      } else if (fNoper==2 && GetAction(0)==kAlternateString){
         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
         Assert(subform); 
         subform->SetAxis(axis);
      }
   }
   if (IsInteger()) axis->SetBit(TAxis::kIsInteger);
}

//______________________________________________________________________________
void TTreeFormula::Streamer(TBuffer &R__b)
{
   // Stream an object of class TTreeFormula.

   if (R__b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 2) {
         TTreeFormula::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
      //====process old versions before automatic schema evolution
      TFormula::Streamer(R__b);
      R__b >> fTree;
      R__b >> fNcodes;
      R__b.ReadFastArray(fCodes, fNcodes);
      R__b >> fMultiplicity;
      Int_t instance;
      R__b >> instance; //data member removed
      R__b >> fNindex;
      if (fNindex) {
         fLookupType = new Int_t[fNindex];
         R__b.ReadFastArray(fLookupType, fNindex);
      }
      fMethods.Streamer(R__b);
      //====end of old versions

   } else {
      TTreeFormula::Class()->WriteBuffer(R__b,this);
   }
}

//______________________________________________________________________________
void TTreeFormula::UpdateFormulaLeaves()
{
   // this function is called TTreePlayer::UpdateFormulaLeaves, itself
   // called by TChain::LoadTree when a new Tree is loaded.
   // Because Trees in a TChain may have a different list of leaves, one
   // must update the leaves numbers in the TTreeFormula used by the TreePlayer.

   // A safer alternative would be to recompile the whole thing .... However
   // currently compile HAS TO be called from the constructor!

   char names[512];
   Int_t nleaves = fLeafNames.GetEntriesFast();
   for (Int_t i=0;i<nleaves;i++) {
      if (!fTree) continue;
      if (!fLeafNames[i]) continue;
      sprintf(names,"%s/%s",fLeafNames[i]->GetTitle(),fLeafNames[i]->GetName());
      TLeaf *leaf = fTree->GetLeaf(names);
      fLeaves[i] = leaf;
   }
   for (Int_t j=0; j<kMAXCODES; j++) {
      for (Int_t k = 0; k<kMAXFORMDIM; k++) {
         if (fVarIndexes[j][k]) {
            fVarIndexes[j][k]->UpdateFormulaLeaves();
         }
      }
      if (fLookupType[j]==kDataMember) GetLeafInfo(j)->Update();
      if (j<fNval && fCodes[j]<0) {
         TCutG *gcut = (TCutG*)fMethods.At(j);
         if (gcut) {
           TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
           TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
           if (fx) fx->UpdateFormulaLeaves();
           if (fy) fy->UpdateFormulaLeaves();
         }
      }
   }
   for(Int_t k=0;k<fNoper;k++) {
      const Int_t oper = GetOper()[k];
      switch(oper >> kTFOperShift) {
         case kAlias:
         case kAliasString:
         case kAlternate:
         case kAlternateString:  {
            TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
            Assert(subform);
            subform->UpdateFormulaLeaves();
            break;
         }
         default:
            break;
      }
   }
}

//______________________________________________________________________________
void TTreeFormula::ResetDimensions() {
   // Populate the TTreeFormulaManager with the dimension information.

   Int_t i,k;

   // Now that we saw all the expressions and variables AND that
   // we know whether arrays of chars are treated as string or
   // not, we can properly setup the dimensions.
   TIter next(fDimensionSetup);
   Int_t last_code = -1;
   Int_t virt_dim = 0;
   for(DimensionInfo * info; (info = (DimensionInfo*)next()); ) {
      if (last_code!=info->fCode) {
         // We know that the list is ordered by code number then by
         // dimension.  Thus a different code means that we need to
         // restart at the lowest dimensions.
         virt_dim = 0;
         last_code = info->fCode;
         fNdimensions[last_code] = 0;
      }

      if (GetAction(info->fOper)==kDefinedString) {

         // We have a string used as a string (and not an array of number)
         // We need to determine which is the last dimension and skip it.
         DimensionInfo *nextinfo = (DimensionInfo*)next();
         while(nextinfo && nextinfo->fCode==info->fCode) {
            DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
            nextinfo = (DimensionInfo*)next();
         }
         if (!nextinfo) break;

         info = nextinfo;
         virt_dim = 0;
         last_code = info->fCode;
         fNdimensions[last_code] = 0;

         info->fSize = 1; // Maybe this should actually do nothing!
      }


      DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
   }

   fMultiplicity = 0;
   for(i=0;i<fNoper;i++) {
      Int_t action = GetAction(i);

      if (action==kAlias || action==kAliasString) {
         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(i));
         Assert(subform);
         switch(subform->GetMultiplicity()) {
            case 0: break;
            case 1: fMultiplicity = 1; break;
            case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
         }
         fManager->Add(subform);
         // since we are addint to this manager 'subform->ResetDimensions();'
         // will be called a little latter
         continue;
      }
      if (action==kDefinedString) {
      //if (fOper[i] >= 105000 && fOper[i]<110000) {
         // We have a string used as a string

         // This dormant portion of code would be used if (when?) we allow the histogramming
         // of the integral content (as opposed to the string content) of strings
         // held in a variable size container delimited by a null (as opposed to
         // a fixed size container or variable size container whose size is controlled
         // by a variable).  In GetNdata, we will then use strlen to grab the current length.
         //fCumulSizes[i][fNdimensions[i]-1] = 1;
         //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
         //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);

         //continue;
      }
   }

   for (i=0;i<fNcodes;i++) {
      if (fCodes[i] < 0) {
         TCutG *gcut = (TCutG*)fMethods.At(i);
         TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
         TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();

         if (fx) {
            switch(fx->GetMultiplicity()) {
               case 0: break;
               case 1: fMultiplicity = 1; break;
               case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
            }
            fManager->Add(fx);
         }
         if (fy) {
            switch(fy->GetMultiplicity()) {
               case 0: break;
               case 1: fMultiplicity = 1; break;
               case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
            }
            fManager->Add(fy);
         }

         continue;
      }

      if (fLookupType[i]==kIteration) {
          fMultiplicity = 1;
          continue;
      }

      TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
      if (!leaf) continue;

      // Reminder of the meaning of fMultiplicity:
      //  -1: Only one or 0 element per entry but contains variable length array!
      //   0: Only one element per entry, no variable length array
      //   1: loop over the elements of a variable length array
      //   2: loop over elements of fixed length array (nData is the same for all entry)

      if (leaf->GetLeafCount()) {
         // We assume only one possible variable length dimension (the left most)
         fMultiplicity = 1;
      } else if (fLookupType[i]==kDataMember) {
         TFormLeafInfo * leafinfo = GetLeafInfo(i);
         TStreamerElement * elem = leafinfo->fElement;
         if (fMultiplicity!=1) {
            if (leafinfo->HasCounter() ) fMultiplicity = 1;
            else if (elem && elem->GetArrayDim()>0) fMultiplicity = 2;
            else if (leaf->GetLenStatic()>1) fMultiplicity = 2;
         }
      } else {
        if (leaf->GetLenStatic()>1 && fMultiplicity!=1) fMultiplicity = 2;
      }

      Int_t virt_dim = 0;
      for (k = 0; k < fNdimensions[i]; k++) {
         // At this point fCumulSizes[i][k] actually contain the physical
         // dimension of the k-th dimensions.
         if ( (fCumulSizes[i][k]>=0) && (fIndexes[i][k] >= fCumulSizes[i][k]) ) {
            // unreacheable element requested:
            fManager->CancelDimension(virt_dim); // fCumulUsedSizes[virt_dim] = 0;
         }
         if ( fIndexes[i][k] < 0 ) virt_dim++;
         fFixedSizes[i][k] = fCumulSizes[i][k];
      }

      // Add up the cumulative size
      for (k = fNdimensions[i]; (k > 0); k--) {
         // NOTE: When support for inside variable dimension is added this
         // will become inacurate (since one of the value in the middle of the chain
         // is unknown until GetNdata is called.
         fCumulSizes[i][k-1] *= TMath::Abs(fCumulSizes[i][k]);
      }
      // NOTE: We assume that the inside variable dimensions are dictated by the
      // first index.
      if (fCumulSizes[i][0]>0) fNdata[i] = fCumulSizes[i][0];

      //for (k = 0; k<kMAXFORMDIM; k++) {
      //   if (fVarIndexes[i][k]) fManager->Add(fVarIndexes[i][k]);
      //}

   }
}

//______________________________________________________________________________
Bool_t TTreeFormula::LoadCurrentDim() {

   // Calculate the actual dimension for the current entry.

   Int_t size;
   Bool_t outofbounds = kFALSE;

   for (Int_t i=0;i<fNcodes;i++) {
      if (fCodes[i] < 0) continue;

      // NOTE: Currently only the leafcount can indicates a dimension that
      // is physically variable.  So only the left-most dimension is variable.
      // When an API is introduced to be able to determine a variable inside dimensions
      // one would need to add a way to recalculate the values of fCumulSizes for this
      // leaf.  This would probably require the addition of a new data member
      // fSizes[kMAXCODES][kMAXFORMDIM];
      // Also note that EvalInstance expect all the values (but the very first one)
      // of fCumulSizes to be positive.  So indicating that a physical dimension is
      // variable (expected for the first one) can NOT be done via negative values of
      // fCumulSizes.

      TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
      if (!leaf) continue;
      Bool_t hasBranchCount2 = kFALSE;
      if (leaf->GetLeafCount()) {
         TLeaf* leafcount = leaf->GetLeafCount();
         TBranch *branchcount = leafcount->GetBranch();
         TFormLeafInfo * info = 0;
         if (leaf->IsA() == TLeafElement::Class()) {
            //if branchcount address not yet set, GetEntry will set the address
            // read branchcount value
            Int_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
            if (readentry==-1) readentry=0;
            if (!branchcount->GetAddress()) branchcount->GetEntry(readentry);
            else branchcount->TBranch::GetEntry(readentry);

            size = ((TBranchElement*)branchcount)->GetNdata();
            // Reading the size as above is correct only when the branchcount
            // is of streamer type kCounter which require the underlying data
            // member to be signed integral type.

            TBranchElement* branch = (TBranchElement*) leaf->GetBranch();

            // NOTE: could be sped up
            if (fHasMultipleVarDim[i]) {// info && info->GetVarDim()>=0) {
               info = (TFormLeafInfo* )fDataMembers.At(i);
               if (branch->GetBranchCount2()) branch->GetBranchCount2()->GetEntry(readentry);

               // Here we need to add the code to take in consideration the
               // double variable length
               // We fill up the array of sizes in the TLeafInfo:
               info->LoadSizes(branch);
               hasBranchCount2 = kTRUE;
               if (info->GetVirtVarDim()>=0) info->UpdateSizes(fManager->fVarDims[info->GetVirtVarDim()]);

               // Refresh the fCumulSizes[i] to have '1' for the
               // double variable dimensions
               Int_t vdim = info->GetVarDim();
               fCumulSizes[i][vdim] =  fCumulSizes[i][vdim+1];
               for(Int_t k=vdim -1; k>=0; k--) {
                  fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
               }
               // Update fCumulUsedSizes
               // UpdateMultiVarSizes(vdim,info,i)
               //Int_t fixed = fCumulSizes[i][vdim+1];
               //for(Int_t k=vdim - 1; k>=0; k++) {
               //   Int_t fixed *= fFixedSizes[i][k];
               //   for(Int_t l=0;l<size; l++) {
               //     fCumulSizes[i][k] += info->GetSize(l) * fixed;
               //}
            }
         } else {
            Int_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
            if (readentry==-1) readentry=0;
            branchcount->GetEntry(readentry);
            size = leaf->GetLen() / leaf->GetLenStatic();
         }
         if (hasBranchCount2) {
            // We assume that fCumulSizes[i][1] contains the product of the fixed sizes
            fNdata[i] = fCumulSizes[i][1] * ((TFormLeafInfo *)fDataMembers.At(i))->GetSumOfSizes();
         } else {
            fNdata[i] = size * fCumulSizes[i][1];
         }
         if (fIndexes[i][0]==-1) {
            // Case where the index is not specified AND the 1st dimension has a variable
            // size.
            if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) fManager->fUsedSizes[0] = size;
            if (info && fIndexes[i][info->GetVarDim()]>=0) {
               for(Int_t j=0; j<size; j++) {
                  if (fIndexes[i][info->GetVarDim()] >= info->GetSize(j)) {
                     info->SetSize(j,0);
                     if (size>fManager->fCumulUsedVarDims->GetSize()) fManager->fCumulUsedVarDims->Set(size);
                     fManager->fCumulUsedVarDims->AddAt(-1,j);
                  }
               }
            }
         } else if (fIndexes[i][0] >= size) {
            // unreacheable element requested:
            fManager->fUsedSizes[0] = 0;
            fNdata[i] = 0;
            outofbounds = kTRUE;
         } else if (hasBranchCount2) {
            TFormLeafInfo * info;
            info = (TFormLeafInfo *)fDataMembers.At(i);
            if (fIndexes[i][info->GetVarDim()] >= info->GetSize(fIndexes[i][0])) {
               // unreacheable element requested:
               fManager->fUsedSizes[0] = 0;
               fNdata[i] = 0;
               outofbounds = kTRUE;
            }
         }
      } else if (fLookupType[i]==kDataMember) {
         TFormLeafInfo *leafinfo = (TFormLeafInfo*)fDataMembers.UncheckedAt(i);
         if (leafinfo->HasCounter()) {
            TBranch *branch = leaf->GetBranch();
            Int_t readentry = branch->GetTree()->GetReadEntry();
            if (readentry==-1) readentry=0;
            branch->GetEntry(readentry);
            size = (Int_t) leafinfo->GetCounterValue(leaf);
            if (fIndexes[i][0]==-1) {
               // Case where the index is not specified AND the 1st dimension has a variable
               // size.
               if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) {
                  fManager->fUsedSizes[0] = size;
               }
            } else if (fIndexes[i][0] >= size) {
               // unreacheable element requested:
               fManager->fUsedSizes[0] = 0;
               fNdata[i] = 0;
               outofbounds = kTRUE;
            } else {
               fNdata[i] = size*fCumulSizes[i][1];
            }
            if (leafinfo->GetVarDim()>=0) {
               // Here we need to add the code to take in consideration the
               // double variable length
               // We fill up the array of sizes in the TLeafInfo:
               // here we can assume that branch is a TBranch element because the other style does NOT support this type
               // of complexity.
               leafinfo->LoadSizes(dynamic_cast<TBranchElement*>(branch));
               hasBranchCount2 = kTRUE;
               if (leafinfo->GetVirtVarDim()>=0) leafinfo->UpdateSizes(fManager->fVarDims[leafinfo->GetVirtVarDim()]);

               // Refresh the fCumulSizes[i] to have '1' for the
               // double variable dimensions
               Int_t vdim = leafinfo->GetVarDim();
               fCumulSizes[i][vdim] =  fCumulSizes[i][vdim+1];
               for(Int_t k=vdim -1; k>=0; k--) {
                  fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
               }
               fNdata[i] = fCumulSizes[i][1] * leafinfo->GetSumOfSizes();
            } else {
               fNdata[i] = size * fCumulSizes[i][1];
            }
         } else if (leafinfo->GetMultiplicity()==-1) {
            TBranch *branch = leaf->GetBranch();
            Int_t readentry = branch->GetTree()->GetReadEntry();
            if (readentry==-1) readentry=0;
            branch->GetEntry(readentry);
            if (leafinfo->GetNdata(leaf)==0) {
               outofbounds = kTRUE;
            }
         }
      }
      // However we allow several dimensions that virtually vary via the size of their
      // index variables.  So we have code to recalculate fCumulUsedSizes.
      Int_t index;
      TFormLeafInfo * info = 0;
      if (fLookupType[i]!=kDirect) {
         info = (TFormLeafInfo *)fDataMembers.At(i);
      }
      for(Int_t k=0, virt_dim=0; k < fNdimensions[i]; k++) {
         if (fIndexes[i][k]<0) {
            if (fIndexes[i][k]==-2 && fManager->fVirtUsedSizes[virt_dim]<0) {

               // if fVirtUsedSize[virt_dim] is positive then VarIndexes[i][k]->GetNdata()
               // is always the same and has already been factored in fUsedSize[virt_dim]
               index = fVarIndexes[i][k]->GetNdata();
               if (index==1) {
                  // We could either have a variable size array which is currently of size one                
                  // or a single element that might or not might not be present (and is currently present!)
                  if (fVarIndexes[i][k]->GetManager()->GetMultiplicity()==1) {
                     if (index<fManager->fUsedSizes[virt_dim]) fManager->fUsedSizes[virt_dim] = index;
                  }
                  
               } else if (fManager->fUsedSizes[virt_dim]==-fManager->fVirtUsedSizes[virt_dim] || 
                          index<fManager->fUsedSizes[virt_dim]) {
                  fManager->fUsedSizes[virt_dim] = index;
               }

            } else if (hasBranchCount2 && k==info->GetVarDim()) {
               // NOTE: We assume the indexing of variable sizes on the first index!
               if (fIndexes[i][0]>=0) {
                  index = info->GetSize(fIndexes[i][0]);
                  if (fManager->fUsedSizes[virt_dim]==1 || (index!=1 && index<fManager->fUsedSizes[virt_dim]) )
                     fManager->fUsedSizes[virt_dim] = index;
               }
            }
            virt_dim++;
         }
      }
   }
   return ! outofbounds;



}

void TTreeFormula::Convert(UInt_t oldversion) 
{
   // Convert the fOper of a TTTreeFormula version fromVersion to the current in memory version

   enum { kOldAlias           = /*TFormula::kVariable*/ 100000+10000+1,
          kOldAliasString     = kOldAlias+1,
          kOldAlternate       = kOldAlias+2,
          kOldAlternateString = kOldAliasString+2
   };

   for (int k=0; k<fNoper; k++) {
      // First hide from TFormula convertion

      Int_t action = GetOper()[k];

      switch (action) {

         case kOldAlias:            GetOper()[k] = -kOldAlias; break;
         case kOldAliasString:      GetOper()[k] = -kOldAliasString; break;
         case kOldAlternate:        GetOper()[k] = -kOldAlternate; break;
         case kOldAlternateString:  GetOper()[k] = -kOldAlternateString; break;
      }
   }

   TFormula::Convert(oldversion);

   for (int i=0,offset=0; i<fNoper; i++) {
      Int_t action = GetOper()[i+offset];

      switch (action) {
         case -kOldAlias:            SetAction(i, kAlias, 0); break;
         case -kOldAliasString:      SetAction(i, kAliasString, 0); break;
         case -kOldAlternate:        SetAction(i, kAlternate, 0); break;
         case -kOldAlternateString:  SetAction(i, kAlternateString, 0); break;
      }
   }
   
}
