// @(#)root/treeplayer:$Name:  $:$Id: TSelectorDraw.cxx,v 1.11 2003/04/01 20:16:42 brun Exp $
// Author: Rene Brun   08/01/2003

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TSelectorDraw                                                        //
//                                                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TSelectorDraw.h"
#include "TROOT.h"
#include "TH2.h"
#include "TH3.h"
#include "TView.h"
#include "TPolyMarker.h"
#include "TPolyMarker3D.h"
#include "TDirectory.h"
#include "TVirtualPad.h"
#include "TProfile.h"
#include "TProfile2D.h"
#include "TTreeFormulaManager.h"
#include "TEnv.h"
#include "TTree.h"
#include "TCut.h"
#include "TEventList.h"
#include "THLimitsFinder.h"

ClassImp(TSelectorDraw)

//______________________________________________________________________________
 TSelectorDraw::TSelectorDraw()
{
   // Default selector constructor.

   fTree           = 0;
   fV1             = 0;
   fV2             = 0;
   fV3             = 0;
   fW              = 0;
   fVar1           = 0;
   fVar2           = 0;
   fVar3           = 0;
   fVar4           = 0;
   fManager        = 0;
   fMultiplicity   = 0;
   fSelect         = 0;
   fSelectedRows   = 0;
   fDraw           = 0;
   fObject         = 0;
   fOldHistogram   = 0;
   fObjEval        = kFALSE;
   fVar1Multiple   = kFALSE;
   fVar2Multiple   = kFALSE;
   fVar3Multiple   = kFALSE;
   fSelectMultiple = kFALSE;
   fCleanElist     = kFALSE;
   fTreeElist      = 0;
   fAction         = 0;
   fNfill          = 0;
   fDimension      = 0;
   fOldEstimate    = 0;
   fForceRead      = 0;
   fWeight         = 1;
   for (Int_t i=0;i<4;i++) {fNbins[i]=0; fVmin[i] = fVmax[i]= 0;}
}

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

   ClearFormula();
   if (fV1)    delete [] fV1;
   if (fV2)    delete [] fV2;
   if (fV3)    delete [] fV3;
   if (fW)     delete [] fW;
}

//______________________________________________________________________________
 void TSelectorDraw::Begin(TTree *tree)
{
   // Called everytime a loop on the tree(s) starts.

   SetStatus(0);
   fSelectedRows   = 0;
   fTree = tree;

   const char *varexp0   = fInput->FindObject("varexp")->GetTitle();
   const char *selection = fInput->FindObject("selection")->GetTitle();
   const char *option    = GetOption();

   TString  opt;
   char *hdefault = (char *)"htemp";
   char *varexp;
   Int_t i,j,hkeep;
   opt = option;
   opt.ToLower();
   fOldHistogram = 0;
   TEventList *elist = 0;
   char htitle[2560]; htitle[0] = '0';
   Bool_t profile = kFALSE;

   TCut realSelection(selection);
   TEventList *inElist = fTree->GetEventList();
   fCleanElist = kFALSE;
   fTreeElist = inElist;
   if ( inElist && inElist->GetReapplyCut() ) {
      realSelection = realSelection && inElist->GetTitle();
   }

   // what each variable should contain:
   //   varexp0   - original expression eg "a:b>>htest"
   //   hname     - name of new or old histogram
   //   hkeep     - flag if to keep new histogram
   //   hnameplus - flag if to add to current histo
   //   i         - length of variable expression stipped of everything after ">>"
   //   varexp    - variable expression stipped of everything after ">>"
   //   fOldHistogram     - pointer to hist hname
   //   elist     - pointer to selection list of hname

   Bool_t CanRebin = kTRUE;
   if (opt.Contains("same")) CanRebin = kFALSE;

   Int_t nbinsx=0, nbinsy=0, nbinsz=0;
   Double_t xmin=0, xmax=0, ymin=0, ymax=0, zmin=0, zmax=0;

   fObject  = 0;
   char *hname = 0;
   char *hnamealloc = 0;
   i = 0;
   if (varexp0 && strlen(varexp0)) {
      for(UInt_t k=strlen(varexp0)-1;k>0;k--) {
         if (varexp0[k]=='>' && varexp0[k-1]=='>') {
            i = (int)( &(varexp0[k-1]) - varexp0 );  //  length of varexp0 before ">>"
            hnamealloc = new char[strlen(&(varexp0[k+1]))+1];
            hname = hnamealloc;
            strcpy(hname,&(varexp0[k+1]));
            break;
         }
      }
   }
   //   char *hname = (char*)strstr(varexp0,">>");
   if (hname) {
      hkeep  = 1;
      varexp = new char[i+1];
      varexp[0] = 0; //necessary if i=0
      Bool_t hnameplus = kFALSE;
      while (*hname == ' ') hname++;
      if (*hname == '+') {
         hnameplus = kTRUE;
         hname++;
         while (*hname == ' ') hname++; //skip ' '
      }
      j = strlen(hname) - 1;   // skip ' '  at the end
      while (j) {
	if (hname[j] != ' ') break;
	hname[j] = 0;
	j--;
      }

      if (i) {
         strncpy(varexp,varexp0,i); varexp[i]=0;

	 Int_t mustdelete=0;

	 // parse things that follow the name of the histo between '(' and ')'.
	 // At this point hname contains the name of the specified histogram.
	 //   Now the syntax is exended to handle an hname of the following format
	 //   hname(nBIN [[,[xlow]][,xhigh]],...)
	 //   so enclosed in brackets is the binning information, xlow, xhigh, and
	 //   the same for the other dimensions

	 char *pstart;    // pointer to '('
	 char *pend;      // pointer to ')'
	 char *cdummy;    // dummy pointer
	 int ncomma;      // number of commas between '(' and ')', later number of arguments
	 int ncols;       // number of columns in varexpr
	 Double_t value;  // parsed value (by sscanf)

	 const Int_t maxvalues=9;

	 pstart= strchr(hname,'(');
	 pend =  strchr(hname,')');
	 if (pstart != NULL ){  // found the bracket

	   mustdelete=1;

	   // check that there is only one open and close bracket
	   if (pstart == strrchr(hname,'(')  &&  pend == strrchr(hname,')')) {

	     // count number of ',' between '(' and ')'
	     ncomma=0;
	     cdummy = pstart;
	     cdummy = strchr(&cdummy[1],',');
	     while (cdummy != NULL) {
	       cdummy = strchr(&cdummy[1],',');
	       ncomma++;
	     }

	     if (ncomma+1 > maxvalues) {
	       Error("DrawSelect","ncomma+1>maxvalues, ncomma=%d, maxvalues=%d",ncomma,maxvalues);
	       ncomma=maxvalues-1;
	     }

	     ncomma++; 	       // number of arguments
	     cdummy = pstart;

	     //   number of columns
	     ncols  = 1;
	     for (j=0;j<i;j++)  if (varexp[j] == ':') ncols++;
	     if (ncols > 3 ) {  // max 3 columns
	       Error("DrawSelect","ncols > 3, ncols=%d",ncols);
	       ncols = 0;
	     }

	     // check dimensions before and after ">>"
	     if (ncols*3 < ncomma) {
	       Error("DrawSelect","ncols*3 < ncomma ncols=%d, ncomma=%d",ncols,ncomma);
	       ncomma = ncols*3;
	     }

	     // scan the values one after the other
	     for (j=0;j<ncomma;j++) {
	       cdummy++;  // skip '(' or ','
	       if (sscanf(cdummy," %lf ",&value) == 1) {
                  cdummy=strchr(&cdummy[1],',');

		  switch (j) {  // do certain settings depending on position of argument
		  case 0:  // binning x-axis
                     nbinsx = (Int_t)value;
		     if      (ncols<2) {
                        gEnv->SetValue("Hist.Binning.1D.x",nbinsx);
                     } else if (ncols<3) {
		        gEnv->SetValue("Hist.Binning.2D.x",nbinsx);
		        gEnv->SetValue("Hist.Binning.2D.Prof",nbinsx);
		     } else {
		        gEnv->SetValue("Hist.Binning.3D.x",nbinsx);
		        gEnv->SetValue("Hist.Binning.3D.Profx",nbinsx);
		     }

		     break;
		  case 1:  // lower limit x-axis
                     xmin = value;
		     break;
		  case 2:  // upper limit x-axis
                     xmax = value;
		     break;
		  case 3:  // binning y-axis
                     nbinsy = (Int_t)value;
		     if (ncols<3) gEnv->SetValue("Hist.Binning.2D.y",nbinsy);
		     else {
		       gEnv->SetValue("Hist.Binning.3D.y",nbinsy);
		       gEnv->SetValue("Hist.Binning.3D.Profy",nbinsy);
		     }
		     break;
		  case 4:  // lower limit y-axis
                     ymin = value;
		     break;
		  case 5:  // upper limit y-axis
                     ymax = value;
		     break;
		  case 6:  // binning z-axis
                     nbinsz = (Int_t)value;
		     gEnv->SetValue("Hist.Binning.3D.z",nbinsz);
		     break;
		  case 7:  // lower limit z-axis
                     zmin = value;
		     break;
		  case 8:  // upper limit z-axis
                     zmax = value;
		     break;
		  default:
		     Error("DrawSelect","j>8");
		     break;
		  }
	       }  // if sscanf == 1
	     } // for j=0;j<ncomma;j++
	   } else {
	     Error("Begin","Two open or close brackets found, hname=%s",hname);
	   }

	   // fix up hname
	   pstart[0]='0';   // removes things after (and including) '('
	 } // if '(' is found

	 j = strlen(hname) - 1; // skip ' '  at the end
	 while (j) {
	   if (hname[j] != ' ') break; // skip ' '  at the end
	   hname[j] = 0;
	   j--;
	 }

         fOldHistogram = (TH1*)gDirectory->Get(hname);  // if hname contains '(...)' the return values is NULL, which is what we want
         if (fOldHistogram && !hnameplus) fOldHistogram->Reset();  // reset unless adding is wanted

	 if (mustdelete) {
	   if (gDebug) {
              Warning("Begin","Deleting old histogram, since (possibly new) limits and binnings have been given");
           }
           delete fOldHistogram; fOldHistogram=0;
	 }

      } else { // if (i)                       // make selection list (i.e. varexp0 starts with ">>")
         elist = (TEventList*)gDirectory->Get(hname);
         if (!elist) {
            elist = new TEventList(hname,realSelection.GetTitle(),1000,0);
         }
         if (elist) {
            if (!hnameplus) {
               if (elist==inElist) {
                  // We have been asked to reset the input list!!
                  // Let's set it aside for now ...
                  inElist = new TEventList(*elist);
                  fCleanElist = kTRUE;
                  fTree->SetEventList(inElist);
               }
               elist->Reset();
               elist->SetTitle(realSelection.GetTitle());
            } else {
               TCut old = elist->GetTitle();
               TCut upd = old || realSelection.GetTitle();
               elist->SetTitle(upd.GetTitle());
            }
         }
      }  // if (i)
   } else { // if (hname)
      hname  = hdefault;
      hkeep  = 0;
      varexp = (char*)varexp0;
      if (gDirectory) {
         fOldHistogram = (TH1*)gDirectory->Get(hname);
         if (fOldHistogram) { fOldHistogram->Delete(); fOldHistogram = 0;}
      }
   }

   // Decode varexp and selection
   CompileVariables(varexp, realSelection.GetTitle());
   if (!fVar1 && !elist) {SetStatus(-1); return;}

   // In case fOldHistogram exists, check dimensionality
   Int_t nsel = strlen(selection);
   if (nsel > 1) {
      sprintf(htitle,"%s {%s}",varexp,selection);
   } else {
      sprintf(htitle,"%s",varexp);
   }
   if (fOldHistogram) {
      Int_t olddim = fOldHistogram->GetDimension();
      Int_t mustdelete = 0;
      if (fOldHistogram->InheritsFrom("TProfile")) {
         profile = kTRUE;
         olddim = 2;
      }
      if (fOldHistogram->InheritsFrom("TProfile2D")) {
         profile = kTRUE;
         olddim = 3;
      }
      if (opt.Contains("prof") && fDimension>1) {
        // ignore "prof" for 1D.
         if (!profile || olddim != fDimension) mustdelete = 1;
      } else {
         if (olddim != fDimension) mustdelete = 1;
      }
      if (mustdelete) {
         Warning("Begin","Deleting old histogram with different dimensions");
         delete fOldHistogram; fOldHistogram = 0;
      }
   }

   // Create a default canvas if none exists
   fDraw = 0;
   if (!gPad && !opt.Contains("goff") && fDimension > 0) {
      if (!gROOT->GetMakeDefCanvas())  {SetStatus(-1); return;}
      (gROOT->GetMakeDefCanvas())();
   }

   // 1-D distribution
   TH1 *hist;
   if (fDimension == 1) {
      fAction = 1;
      if (!fOldHistogram) {
         fNbins[0] = gEnv->GetValue("Hist.Binning.1D.x",100);
         if (gPad && opt.Contains("same")) {
            TListIter np(gPad->GetListOfPrimitives());
            TObject *op;
            TH1 *oldhtemp = 0;
            while ((op = np()) && !oldhtemp) {
              if (op->InheritsFrom("TH1")) oldhtemp = (TH1 *)op;
            }
            if (oldhtemp) {
                fNbins[0] = oldhtemp->GetXaxis()->GetNbins();
                fVmin[0]  = oldhtemp->GetXaxis()->GetXmin();
                fVmax[0]  = oldhtemp->GetXaxis()->GetXmax();
             } else {
                fVmin[0]  = gPad->GetUxmin();
                fVmax[0]  = gPad->GetUxmax();
             }
         } else {
             fAction   = -1;
             fVmin[0] = xmin;
             fVmax[0] = xmax;
             if (xmin < xmax) CanRebin = kFALSE;
         }
      }
      if (fOldHistogram) {
         hist    = fOldHistogram;
         fNbins[0] = hist->GetXaxis()->GetNbins();
      } else {
         hist = new TH1F(hname,htitle,fNbins[0],fVmin[0],fVmax[0]);
         hist->SetLineColor(fTree->GetLineColor());
         hist->SetLineWidth(fTree->GetLineWidth());
         hist->SetLineStyle(fTree->GetLineStyle());
         hist->SetFillColor(fTree->GetFillColor());
         hist->SetFillStyle(fTree->GetFillStyle());
         hist->SetMarkerStyle(fTree->GetMarkerStyle());
         hist->SetMarkerColor(fTree->GetMarkerColor());
         hist->SetMarkerSize(fTree->GetMarkerSize());
         if (CanRebin)hist->SetBit(TH1::kCanRebin);
         if (!hkeep) {
            hist->SetBit(kCanDelete);
            if (!opt.Contains("goff")) hist->SetDirectory(0);
         }
         if (opt.Length() && opt[0] == 'e') hist->Sumw2();
      }
      fVar1->SetAxis(hist->GetXaxis());
      fObject = hist;

   // 2-D distribution
   } else if (fDimension == 2) {
      fAction = 2;
      if (!fOldHistogram || !opt.Contains("same")) {
         fNbins[0] = gEnv->GetValue("Hist.Binning.2D.y",40);
         fNbins[1] = gEnv->GetValue("Hist.Binning.2D.x",40);
         if (opt.Contains("prof")) fNbins[1] = gEnv->GetValue("Hist.Binning.2D.Prof",100);
         if (opt.Contains("same")) {
             TH1 *oldhtemp = (TH1*)gPad->FindObject(hdefault);
             if (oldhtemp) {
                fNbins[1] = oldhtemp->GetXaxis()->GetNbins();
                fVmin[1]  = oldhtemp->GetXaxis()->GetXmin();
                fVmax[1]  = oldhtemp->GetXaxis()->GetXmax();
                fNbins[0] = oldhtemp->GetYaxis()->GetNbins();
                fVmin[0]  = oldhtemp->GetYaxis()->GetXmin();
                fVmax[0]  = oldhtemp->GetYaxis()->GetXmax();
             } else {
                fNbins[1] = gEnv->GetValue("Hist.Binning.2D.x",40);
                fVmin[1]  = gPad->GetUxmin();
                fVmax[1]  = gPad->GetUxmax();
                fNbins[0] = gEnv->GetValue("Hist.Binning.2D.y",40);
                fVmin[0]  = gPad->GetUymin();
                fVmax[0]  = gPad->GetUymax();
             }
         } else {
             if (!fOldHistogram) fAction = -2;
             fVmin[1] = xmin;
             fVmax[1] = xmax;
             fVmin[0] = ymin;
             fVmax[0] = ymax;
             if (xmin < xmax && ymin < ymax) CanRebin = kFALSE;
         }
      }
      if (profile || opt.Contains("prof")) {
         TProfile *hp;
         if (fOldHistogram) {
            fAction = 4;
            hp = (TProfile*)fOldHistogram;
         } else {
            if (fAction < 0) {
               fAction = -4;
               fVmin[1] = xmin;
               fVmax[1] = xmax;
               if (xmin < xmax) CanRebin = kFALSE;
            }
            if (opt.Contains("profs"))
               hp = new TProfile(hname,htitle,fNbins[1],fVmin[1], fVmax[1],"s");
            else
               hp = new TProfile(hname,htitle,fNbins[1],fVmin[1], fVmax[1],"");
            if (!hkeep) {
               hp->SetBit(kCanDelete);
               if (!opt.Contains("goff")) hp->SetDirectory(0);
            }
            hp->SetLineColor(fTree->GetLineColor());
            hp->SetLineWidth(fTree->GetLineWidth());
            hp->SetLineStyle(fTree->GetLineStyle());
            hp->SetFillColor(fTree->GetFillColor());
            hp->SetFillStyle(fTree->GetFillStyle());
            hp->SetMarkerStyle(fTree->GetMarkerStyle());
            hp->SetMarkerColor(fTree->GetMarkerColor());
            hp->SetMarkerSize(fTree->GetMarkerSize());
            if (CanRebin)hp->SetBit(TH1::kCanRebin);
         }
         fVar2->SetAxis(hp->GetXaxis());
         fObject = hp;

      } else {
         TH2F *h2;
         if (fOldHistogram) {
            h2 = (TH2F*)fOldHistogram;
         } else {
            h2 = new TH2F(hname,htitle,fNbins[1],fVmin[1], fVmax[1], fNbins[0], fVmin[0], fVmax[0]);
            h2->SetLineColor(fTree->GetLineColor());
            h2->SetFillColor(fTree->GetFillColor());
            h2->SetFillStyle(fTree->GetFillStyle());
            h2->SetMarkerStyle(fTree->GetMarkerStyle());
            h2->SetMarkerColor(fTree->GetMarkerColor());
            h2->SetMarkerSize(fTree->GetMarkerSize());
            if (CanRebin)h2->SetBit(TH1::kCanRebin);
            if (!hkeep) {
               h2->SetBit(TH1::kNoStats);
               h2->SetBit(kCanDelete);
               if (!opt.Contains("goff")) h2->SetDirectory(0);
            }
         }
         fVar1->SetAxis(h2->GetYaxis());
         fVar2->SetAxis(h2->GetXaxis());
         Int_t noscat = strlen(option);
         if (opt.Contains("same")) noscat -= 4;
         fObject = h2;
         if (!noscat) {
            fAction = 12;
            if (!fOldHistogram && !opt.Contains("same")) fAction = -12;
         }
      }

   // 3-D distribution
   } else if (fDimension == 3) {
      fAction = 3;
      if (!fOldHistogram || !opt.Contains("same")) {
         fNbins[0] = gEnv->GetValue("Hist.Binning.3D.z",20);
         fNbins[1] = gEnv->GetValue("Hist.Binning.3D.y",20);
         fNbins[2] = gEnv->GetValue("Hist.Binning.3D.x",20);
         if (opt.Contains("same")) {
             TH1 *oldhtemp = (TH1*)gPad->FindObject(hdefault);
             if (oldhtemp) {
                fNbins[2] = oldhtemp->GetXaxis()->GetNbins();
                fVmin[2]  = oldhtemp->GetXaxis()->GetXmin();
                fVmax[2]  = oldhtemp->GetXaxis()->GetXmax();
                fNbins[1] = oldhtemp->GetYaxis()->GetNbins();
                fVmin[1]  = oldhtemp->GetYaxis()->GetXmin();
                fVmax[1]  = oldhtemp->GetYaxis()->GetXmax();
                fNbins[0] = oldhtemp->GetZaxis()->GetNbins();
                fVmin[0]  = oldhtemp->GetZaxis()->GetXmin();
                fVmax[0]  = oldhtemp->GetZaxis()->GetXmax();
             } else {
                TView *view = gPad->GetView();
                Double_t *rmin = view->GetRmin();
                Double_t *rmax = view->GetRmax();
                fNbins[2] = gEnv->GetValue("Hist.Binning.3D.z",20);
                fVmin[2]  = rmin[0];
                fVmax[2]  = rmax[0];
                fNbins[1] = gEnv->GetValue("Hist.Binning.3D.y",20);
                fVmin[1]  = rmin[1];
                fVmax[1]  = rmax[1];
                fNbins[0] = gEnv->GetValue("Hist.Binning.3D.x",20);
                fVmin[0]  = rmin[2];
                fVmax[0]  = rmax[2];
             }
         } else {
             if (!fOldHistogram) fAction = -3;
             fVmin[2] = xmin;
             fVmax[2] = xmax;
             fVmin[1] = ymin;
             fVmax[1] = ymax;
             fVmin[0] = zmin;
             fVmax[0] = zmax;
             if (xmin < xmax && ymin < ymax && zmin < zmax) CanRebin = kFALSE;
         }
      }
      if (profile || opt.Contains("prof")) {
         TProfile2D *hp;
         if (fOldHistogram) {
            fAction = 23;
            hp = (TProfile2D*)fOldHistogram;
         } else {
            if (fAction < 0) {
               fAction = -23;
               fVmin[2] = xmin;
               fVmax[2] = xmax;
               fVmin[1] = ymin;
               fVmax[1] = ymax;
             if (xmin < xmax && ymin < ymax) CanRebin = kFALSE;
            }
            if (opt.Contains("profs"))
               hp = new TProfile2D(hname,htitle,fNbins[2],fVmin[2], fVmax[2],fNbins[1],fVmin[1], fVmax[1],"s");
            else
               hp = new TProfile2D(hname,htitle,fNbins[2],fVmin[2], fVmax[2],fNbins[1],fVmin[1], fVmax[1],"");
            if (!hkeep) {
               hp->SetBit(kCanDelete);
               if (!opt.Contains("goff")) hp->SetDirectory(0);
            }
            hp->SetLineColor(fTree->GetLineColor());
            hp->SetLineWidth(fTree->GetLineWidth());
            hp->SetLineStyle(fTree->GetLineStyle());
            hp->SetFillColor(fTree->GetFillColor());
            hp->SetFillStyle(fTree->GetFillStyle());
            hp->SetMarkerStyle(fTree->GetMarkerStyle());
            hp->SetMarkerColor(fTree->GetMarkerColor());
            hp->SetMarkerSize(fTree->GetMarkerSize());
            if (CanRebin)hp->SetBit(TH1::kCanRebin);
         }
         fVar2->SetAxis(hp->GetYaxis());
         fVar3->SetAxis(hp->GetXaxis());
         fObject = hp;

      } else {
         TH3F *h3;
         if (fOldHistogram) {
            h3 = (TH3F*)fOldHistogram;
         } else {
            h3 = new TH3F(hname,htitle,fNbins[2],fVmin[2], fVmax[2],fNbins[1],fVmin[1], fVmax[1], fNbins[0], fVmin[0], fVmax[0]);
            h3->SetLineColor(fTree->GetLineColor());
            h3->SetFillColor(fTree->GetFillColor());
            h3->SetFillStyle(fTree->GetFillStyle());
            h3->SetMarkerStyle(fTree->GetMarkerStyle());
            h3->SetMarkerColor(fTree->GetMarkerColor());
            h3->SetMarkerSize(fTree->GetMarkerSize());
            if (CanRebin)h3->SetBit(TH1::kCanRebin);
            if (!hkeep) {
               h3->SetBit(kCanDelete);
               h3->SetBit(TH1::kNoStats);
               if (!opt.Contains("goff")) h3->SetDirectory(0);
            }
         }
         fVar1->SetAxis(h3->GetZaxis());
         fVar2->SetAxis(h3->GetYaxis());
         fVar3->SetAxis(h3->GetXaxis());
         fObject = h3;
         Int_t noscat = strlen(option);
         if (opt.Contains("same")) noscat -= 4;
         if (!noscat) {
            fAction = 13;
            if (!fOldHistogram && !opt.Contains("same")) fAction = -13;
         }
      }

   // An Event List
   } else {
      fAction = 5;
      fOldEstimate = fTree->GetEstimate();
      fTree->SetEstimate(1);
      fObject = elist;
   }
   if (hkeep) delete [] varexp;
   if (hnamealloc) delete [] hnamealloc;
   fVar1Multiple = kFALSE;
   fVar2Multiple = kFALSE;
   fVar3Multiple = kFALSE;
   fSelectMultiple = kFALSE;
   if (fVar1 && fVar1->GetMultiplicity()) fVar1Multiple = kTRUE;
   if (fVar2 && fVar2->GetMultiplicity()) fVar2Multiple = kTRUE;
   if (fVar3 && fVar3->GetMultiplicity()) fVar3Multiple = kTRUE;
   if (fSelect && fSelect->GetMultiplicity()) fSelectMultiple = kTRUE;

   fForceRead = fTree->TestBit(TTree::kForceRead);
   fWeight  = fTree->GetWeight();
   fNfill   = 0;
   if (!fV1 && fVar1)   fV1 = new Double_t[fTree->GetEstimate()];
   if (!fV2 && fVar2)   fV2 = new Double_t[fTree->GetEstimate()];
   if (!fV3 && fVar3)   fV3 = new Double_t[fTree->GetEstimate()];
   if (!fW)             fW  = new Double_t[fTree->GetEstimate()];
}

//______________________________________________________________________________
 void TSelectorDraw::ClearFormula()
{
   // Delete internal buffers.

   delete fVar1;   fVar1 = 0;
   delete fVar2;   fVar2 = 0;
   delete fVar3;   fVar3 = 0;
   delete fVar4;   fVar4 = 0;
   delete fSelect; fSelect = 0;
   fManager = 0;
   fMultiplicity = 0;
}

//______________________________________________________________________________
 void TSelectorDraw::CompileVariables(const char *varexp, const char *selection)
{
   // Compile input variables and selection expression.
   //
   //  varexp is an expression of the general form e1:e2:e3
   //    where e1,etc is a formula referencing a combination of the columns
   //  Example:
   //     varexp = x  simplest case: draw a 1-Dim distribution of column named x
   //            = sqrt(x)         : draw distribution of sqrt(x)
   //            = x*y/z
   //            = y:sqrt(x) 2-Dim dsitribution of y versus sqrt(x)
   //
   //  selection is an expression with a combination of the columns
   //  Example:
   //      selection = "x<y && sqrt(z)>3.2"
   //       in a selection all the C++ operators are authorized

   const Int_t MAXCOL = 4;
   TString title;
   Int_t i,nch,ncols;
   Int_t index[MAXCOL];

   // Compile selection expression if there is one
   fDimension = 0;
   ClearFormula();
   fMultiplicity = 0;
   fObjEval = kFALSE;

   if (strlen(selection)) {
      fSelect = new TTreeFormula("Selection",selection,fTree);
      if (!fSelect->GetNdim()) {delete fSelect; fSelect = 0; return; }
   }
   // if varexp is empty, take first column by default
   nch = strlen(varexp);
   if (nch == 0) {fDimension = 0; return;}
   title = varexp;

   // otherwise select only the specified columns
   ncols  = 1;
   for (i=0;i<nch;i++)  if (title[i] == ':') ncols++;
   if (ncols > 3 ) return;
   MakeIndex(title,index);

   fManager = new TTreeFormulaManager();
   if (fSelect) fManager->Add(fSelect);
   fTree->ResetBit(TTree::kForceRead);
   if (ncols >= 1) {
      fVar1 = new TTreeFormula("Var1",GetNameByIndex(title,index,0),fTree);
      if (!fVar1->GetNdim()) { ClearFormula(); return;}
      fManager->Add(fVar1);
   }
   if (ncols >= 2) {
      fVar2 = new TTreeFormula("Var2",GetNameByIndex(title,index,1),fTree);
      if (!fVar2->GetNdim()) { ClearFormula(); return;}
      fManager->Add(fVar2);
   }
   if (ncols >= 3) {
      fVar3 = new TTreeFormula("Var3",GetNameByIndex(title,index,2),fTree);
      if (!fVar3->GetNdim()) { ClearFormula(); return;}
      fManager->Add(fVar3);
   }
   fManager->Sync();

   if (fManager->GetMultiplicity()==-1) fTree->SetBit(TTree::kForceRead);
   if (fManager->GetMultiplicity()>=1) fMultiplicity = fManager->GetMultiplicity();

   fDimension    = ncols;

   if (ncols==1) {
      TClass *cl = fVar1->EvalClass();
      if (cl) {
         fObjEval = kTRUE;
      }
   }
}

//______________________________________________________________________________
 const char *TSelectorDraw::GetNameByIndex(TString &varexp, Int_t *index,Int_t colindex)
{
   // Return name corresponding to colindex in varexp.
   //
   // varexp is a string of names separated by :
   // index is an array with pointers to the start of name[i] in varexp

   Int_t i1,n;
   static TString column;
   if (colindex<0 ) return "";
   i1 = index[colindex] + 1;
   n  = index[colindex+1] - i1;
   column = varexp(i1,n);
   return column.Data();
}

//______________________________________________________________________________
 void TSelectorDraw::MakeIndex(TString &varexp, Int_t *index)
{
   // Build Index array for names in varexp.

   Int_t ivar = 1;
   index[0]  = -1;
   for (Int_t i=0;i<varexp.Length();i++) {
      if (varexp[i] == ':') {
         index[ivar] = i;
         ivar++;
      }
   }
   index[ivar] = varexp.Length();
}


//______________________________________________________________________________
 Bool_t TSelectorDraw::Notify()
{
   // This function is called at the first entry of a new tree in a chain.

   if (fTree) fWeight  = fTree->GetWeight();
   if (fVar1) fVar1->UpdateFormulaLeaves();
   if (fVar2) fVar2->UpdateFormulaLeaves();
   if (fVar3) fVar3->UpdateFormulaLeaves();
   if (fVar4) fVar4->UpdateFormulaLeaves();
   if (fSelect) fSelect->UpdateFormulaLeaves();
   return kTRUE;
}

//______________________________________________________________________________
 void TSelectorDraw::ProcessFill(Int_t entry)
{
   // Called in the entry loop for all entries accepted by Select.

   if (fObjEval) {
      ProcessFillObject(entry);
      return;
   }

   if (fMultiplicity) {
      ProcessFillMultiple(entry);
      return;
   }

   // simple case with no multiplicity
   if ( fForceRead && fManager->GetNdata() <= 0) return;

   if (fSelect) {
      fW[fNfill] = fWeight*fSelect->EvalInstance(0);
      if (!fW[fNfill]) return;
   } else fW[fNfill] = fWeight;
   if (fVar1) {
      fV1[fNfill] = fVar1->EvalInstance(0);
   }
   if (fVar2) {
      fV2[fNfill] = fVar2->EvalInstance(0);
      if (fVar3) {
         fV3[fNfill] = fVar3->EvalInstance(0);
      }
   }
   fNfill++;
   if (fNfill >= fTree->GetEstimate()) {
      TakeAction();
      fNfill = 0;
   }
}

//______________________________________________________________________________
 void TSelectorDraw::ProcessFillMultiple(Int_t /*entry*/)
{
   // Called in the entry loop for all entries accepted by Select.
   // Complex case with multiplicity.

   // Grab the array size of the formulas for this entry
   Int_t ndata = fManager->GetNdata();

   // No data at all, let's move on to the next entry.
   if (!ndata) return;

   Int_t nfill0 = fNfill;

   // Calculate the first values
   if (fSelect) {
      fW[fNfill] = fWeight*fSelect->EvalInstance(0);
      if (!fW[fNfill] && !fSelectMultiple) return;
   } else fW[fNfill] = fWeight;
   if (fVar1) {
      fV1[fNfill] = fVar1->EvalInstance(0);
      if (fVar2) {
         fV2[fNfill] = fVar2->EvalInstance(0);
         if (fVar3) {
            fV3[fNfill] = fVar3->EvalInstance(0);
         }
      }
   }
   if (fW[fNfill]) {
      fNfill++;
      if (fNfill >= fTree->GetEstimate()) {
         TakeAction();
         fNfill = 0;
      }
   }
   Double_t ww = fW[nfill0];

   for (Int_t i=1;i<ndata;i++) {
      if (fSelectMultiple) {
         ww = fWeight*fSelect->EvalInstance(i);
         if (ww == 0) continue;
      }
      if (fVar1) {
         if (fVar1Multiple) fV1[fNfill] = fVar1->EvalInstance(i);
         else               fV1[fNfill] = fV1[nfill0];
         if (fVar2) {
            if (fVar2Multiple) fV2[fNfill] = fVar2->EvalInstance(i);
            else               fV2[fNfill] = fV2[nfill0];
            if (fVar3) {
               if (fVar3Multiple) fV3[fNfill] = fVar3->EvalInstance(i);
               else               fV3[fNfill] = fV3[nfill0];
            }
         }
      }
      fW[fNfill] = ww;

      fNfill++;
      if (fNfill >= fTree->GetEstimate()) {
         TakeAction();
         fNfill = 0;
      }
   }
}

//______________________________________________________________________________
 void TSelectorDraw::ProcessFillObject(Int_t /*entry*/)
{
   // Called in the entry loop for all entries accepted by Select.
   // Case where the only variable returns an object (or pointer to).

   // Complex case with multiplicity.

   // Grab the array size of the formulas for this entry
   Int_t ndata = fManager->GetNdata();

   // No data at all, let's move on to the next entry.
   if (!ndata) return;

   Int_t nfill0 = fNfill;
   Double_t ww = 0;

   for (Int_t i=0;i<ndata;i++) {
      if (i==0) {
         if (fSelect) {
            fW[fNfill] = fWeight*fSelect->EvalInstance(0);
            if (!fW[fNfill] && !fSelectMultiple) return;
         } else fW[fNfill] = fWeight;
         ww = fW[nfill0];
      } else if (fSelectMultiple) {
         ww = fWeight*fSelect->EvalInstance(i);
         if (ww == 0) continue;
      }
      if (fVar1) {
         TClass *cl = fVar1->EvalClass();
         if (cl==TBits::Class()) {

            void *obj = fVar1->EvalObject(i);

            TBits *bits = (TBits*)obj;
            Int_t nbits = bits->GetNbits();

            Int_t nextbit = -1;
            while(1) {
               nextbit = bits->FirstSetBit(nextbit+1);
               if (nextbit >= nbits) break;
               fV1[fNfill] = nextbit;
               fW[fNfill] =  ww;
               fNfill++;
            }

         } else {

           Warning("ProcessFillObject",
                   "Not implemented for %s",
                   cl?cl->GetName():"unknown class");

         }
      }
   }
   if (fNfill >= fTree->GetEstimate()) {
      TakeAction();
      fNfill = 0;
   }

}

//_______________________________________________________________________
 void TSelectorDraw::SetEstimate(Int_t)
{
   // Set number of entries to estimate variable limits.

   delete [] fV1;  fV1 = 0;
   delete [] fV2;  fV2 = 0;
   delete [] fV3;  fV3 = 0;
   delete [] fW;   fW  = 0;
}

//______________________________________________________________________________
 void TSelectorDraw::TakeAction()
{
   // Execute action for object obj fNfill times.

   Int_t i;
   //__________________________1-D histogram_______________________
   if      (fAction ==  1) ((TH1*)fObject)->FillN(fNfill,fV1,fW);
   //__________________________2-D histogram_______________________
   else if (fAction ==  2) {
      TH2 *h2 = (TH2*)fObject;
      for(i=0;i<fNfill;i++) h2->Fill(fV2[i],fV1[i],fW[i]);
   }
   //__________________________Profile histogram_______________________
   else if (fAction ==  4) ((TProfile*)fObject)->FillN(fNfill,fV2,fV1,fW);
   //__________________________Event List______________________________
   else if (fAction ==  5) {
      TEventList *elist = (TEventList*)fObject;
      Int_t enumb = fTree->GetChainOffset() + fTree->GetReadEntry();
      if (elist->GetIndex(enumb) < 0) elist->Enter(enumb);
   }
   //__________________________2D scatter plot_______________________
   else if (fAction == 12) {
      TPolyMarker *pm = new TPolyMarker(fNfill);
      pm->SetMarkerStyle(fTree->GetMarkerStyle());
      pm->SetMarkerColor(fTree->GetMarkerColor());
      pm->SetMarkerSize(fTree->GetMarkerSize());
      Double_t u, v;
      Double_t umin = gPad->GetUxmin();
      Double_t umax = gPad->GetUxmax();
      Double_t vmin = gPad->GetUymin();
      Double_t vmax = gPad->GetUymax();

      for (i=0;i<fNfill;i++) {
         u = gPad->XtoPad(fV2[i]);
         v = gPad->YtoPad(fV1[i]);
         if (u < umin) u = umin;
         if (u > umax) u = umax;
         if (v < vmin) v = vmin;
         if (v > vmax) v = vmax;
         pm->SetPoint(i,u,v);
      }

      pm->Draw();
      TH2 *h2 = (TH2*)fObject;
      for(i=0;i<fNfill;i++) h2->Fill(fV2[i],fV1[i],fW[i]);
   }
   //__________________________3D scatter plot_______________________
   else if (fAction ==  3) {
      TH3 *h3 =(TH3*)fObject;
      for(i=0;i<fNfill;i++) h3->Fill(fV3[i],fV2[i],fV1[i],fW[i]);
   }
   else if (fAction == 13) {
      TPolyMarker3D *pm3d = new TPolyMarker3D(fNfill);
      pm3d->SetMarkerStyle(fTree->GetMarkerStyle());
      pm3d->SetMarkerColor(fTree->GetMarkerColor());
      pm3d->SetMarkerSize(fTree->GetMarkerSize());
      for (i=0;i<fNfill;i++) { pm3d->SetPoint(i,fV3[i],fV2[i],fV1[i]);}
      pm3d->Draw();
      TH3 *h3 =(TH3*)fObject;
      for(i=0;i<fNfill;i++) h3->Fill(fV3[i],fV2[i],fV1[i],fW[i]);
   }
   //__________________________2D Profile Histogram__________________
   else if (fAction == 23) {
      TProfile2D *hp2 =(TProfile2D*)fObject;
      for(i=0;i<fNfill;i++) hp2->Fill(fV3[i],fV2[i],fV1[i],fW[i]);
   }
   else if (fAction < 0) {
      fAction = -fAction;
      TakeEstimate();
   }

   // Do we need to update screen?
   fSelectedRows += fNfill;
   if (!fTree->GetUpdate()) return;
   if (fSelectedRows > fDraw+fTree->GetUpdate()) {
      if (fDraw) gPad->Modified();
      else       fObject->Draw(fOption.Data());
      gPad->Update();
      fDraw = fSelectedRows;
   }
}

//______________________________________________________________________________
 void TSelectorDraw::TakeEstimate()
{
   // Estimate limits for 1-D, 2-D or 3-D objects.

   Int_t i;
   Double_t rmin[3],rmax[3];
   fVmin[0] = fVmin[1] = fVmin[2] = FLT_MAX; //in float.h
   fVmax[0] = fVmax[1] = fVmax[2] = -fVmin[0];
   //__________________________1-D histogram_______________________
   if      (fAction ==  1) {
      TH1 *h1 = (TH1*)fObject;
      if (fObject->TestBit(TH1::kCanRebin)) {
         for (i=0;i<fNfill;i++) {
            if (fVmin[0] > fV1[i]) fVmin[0] = fV1[i];
            if (fVmax[0] < fV1[i]) fVmax[0] = fV1[i];
         }
         THLimitsFinder::GetLimitsFinder()->FindGoodLimits(h1,fVmin[0],fVmax[0]);
      }
      h1->FillN(fNfill, fV1, fW);
   //__________________________2-D histogram_______________________
   } else if (fAction ==  2) {
      TH2 *h2 = (TH2*)fObject;
      if (fObject->TestBit(TH1::kCanRebin)) {
         for (i=0;i<fNfill;i++) {
            if (fVmin[0] > fV1[i]) fVmin[0] = fV1[i];
            if (fVmax[0] < fV1[i]) fVmax[0] = fV1[i];
            if (fVmin[1] > fV2[i]) fVmin[1] = fV2[i];
            if (fVmax[1] < fV2[i]) fVmax[1] = fV2[i];
         }
         THLimitsFinder::GetLimitsFinder()->FindGoodLimits(h2,fVmin[1],fVmax[1],fVmin[0],fVmax[0]);
      }
      for(i=0;i<fNfill;i++) h2->Fill(fV2[i],fV1[i],fW[i]);
   //__________________________Profile histogram_______________________
   } else if (fAction ==  4) {
      TProfile *hp = (TProfile*)fObject;
      if (fObject->TestBit(TH1::kCanRebin)) {
         for (i=0;i<fNfill;i++) {
            if (fVmin[0] > fV1[i]) fVmin[0] = fV1[i];
            if (fVmax[0] < fV1[i]) fVmax[0] = fV1[i];
            if (fVmin[1] > fV2[i]) fVmin[1] = fV2[i];
            if (fVmax[1] < fV2[i]) fVmax[1] = fV2[i];
         }
         THLimitsFinder::GetLimitsFinder()->FindGoodLimits(hp,fVmin[1],fVmax[1]);
      }
      hp->FillN(fNfill, fV2, fV1, fW);
   //__________________________2D scatter plot_______________________
   } else if (fAction == 12) {
      TH2 *h2 = (TH2*)fObject;
      if (fObject->TestBit(TH1::kCanRebin)) {
         for (i=0;i<fNfill;i++) {
            if (fVmin[0] > fV1[i]) fVmin[0] = fV1[i];
            if (fVmax[0] < fV1[i]) fVmax[0] = fV1[i];
            if (fVmin[1] > fV2[i]) fVmin[1] = fV2[i];
            if (fVmax[1] < fV2[i]) fVmax[1] = fV2[i];
         }
         THLimitsFinder::GetLimitsFinder()->FindGoodLimits(h2,fVmin[1],fVmax[1],fVmin[0],fVmax[0]);
      }

      if (!strstr(fOption.Data(),"same") && !strstr(fOption.Data(),"goff")) {
         UInt_t statbit = h2->TestBit(TH1::kNoStats);
         h2->SetBit(TH1::kNoStats);
         h2->DrawCopy(fOption.Data());
         if (statbit) h2->SetBit(TH1::kNoStats);
         gPad->Update();
      }
      TPolyMarker *pm = new TPolyMarker(fNfill);
      pm->SetMarkerStyle(fTree->GetMarkerStyle());
      pm->SetMarkerColor(fTree->GetMarkerColor());
      pm->SetMarkerSize(fTree->GetMarkerSize());
      Double_t u, v;
      Double_t umin = gPad->GetUxmin();
      Double_t umax = gPad->GetUxmax();
      Double_t vmin = gPad->GetUymin();
      Double_t vmax = gPad->GetUymax();

      for (i=0;i<fNfill;i++) {
         u = gPad->XtoPad(fV2[i]);
         v = gPad->YtoPad(fV1[i]);
         if (u < umin) u = umin;
         if (u > umax) u = umax;
         if (v < vmin) v = vmin;
         if (v > vmax) v = vmax;
         pm->SetPoint(i,u,v);
      }
      if (!fDraw && !strstr(fOption.Data(),"goff")) pm->Draw();
      if (!h2->TestBit(kCanDelete)) {
         for (i=0;i<fNfill;i++) h2->Fill(fV2[i],fV1[i],fW[i]);
      }
   //__________________________3D scatter plot_______________________
   } else if (fAction == 3 || fAction == 13) {
      TH3 *h3 = (TH3*)fObject;
      if (fObject->TestBit(TH1::kCanRebin)) {
         for (i=0;i<fNfill;i++) {
            if (fVmin[0] > fV1[i]) fVmin[0] = fV1[i];
            if (fVmax[0] < fV1[i]) fVmax[0] = fV1[i];
            if (fVmin[1] > fV2[i]) fVmin[1] = fV2[i];
            if (fVmax[1] < fV2[i]) fVmax[1] = fV2[i];
            if (fVmin[2] > fV3[i]) fVmin[2] = fV3[i];
            if (fVmax[2] < fV3[i]) fVmax[2] = fV3[i];
         }
         THLimitsFinder::GetLimitsFinder()->FindGoodLimits(h3,fVmin[2],fVmax[2],fVmin[1],fVmax[1],fVmin[0],fVmax[0]);
      }

      if (fAction == 3 || !h3->TestBit(kCanDelete)) {
         for (i=0;i<fNfill;i++) h3->Fill(fV3[i],fV2[i],fV1[i],fW[i]);
      }
      if (fAction == 3) return;
      if (!strstr(fOption.Data(),"same") && !strstr(fOption.Data(),"goff")) {
         h3->DrawCopy(fOption.Data());
         gPad->Update();
      } else {
         rmin[0] = fVmin[2]; rmin[1] = fVmin[1]; rmin[2] = fVmin[0];
         rmax[0] = fVmax[2]; rmax[1] = fVmax[1]; rmax[2] = fVmax[0];
         gPad->Clear();
         gPad->Range(-1,-1,1,1);
         new TView(rmin,rmax,1);
      }
      TPolyMarker3D *pm3d = new TPolyMarker3D(fNfill);
      pm3d->SetMarkerStyle(fTree->GetMarkerStyle());
      pm3d->SetMarkerColor(fTree->GetMarkerColor());
      pm3d->SetMarkerSize(fTree->GetMarkerSize());
      for (i=0;i<fNfill;i++) { pm3d->SetPoint(i,fV3[i],fV2[i],fV1[i]);}
      if (!fDraw && !strstr(fOption.Data(),"goff")) pm3d->Draw();
   //__________________________2D Profile Histogram__________________
   } else if (fAction == 23) {
      TProfile2D *hp = (TProfile2D*)fObject;
      if (hp->TestBit(TH1::kCanRebin)) {
         for (i=0;i<fNfill;i++) {
            if (fVmin[0] > fV1[i]) fVmin[0] = fV1[i];
            if (fVmax[0] < fV1[i]) fVmax[0] = fV1[i];
            if (fVmin[1] > fV2[i]) fVmin[1] = fV2[i];
            if (fVmax[1] < fV2[i]) fVmax[1] = fV2[i];
            if (fVmin[2] > fV3[i]) fVmin[2] = fV3[i];
            if (fVmax[2] < fV3[i]) fVmax[2] = fV3[i];
         }
         THLimitsFinder::GetLimitsFinder()->FindGoodLimits(hp,fVmin[2],fVmax[2],fVmin[1],fVmax[1]);
      }
      for (i=0;i<fNfill;i++) hp->Fill(fV3[i],fV2[i],fV1[i],fW[i]);
   }
}

//______________________________________________________________________________
 void TSelectorDraw::Terminate()
{
   // Called at the end of a loop on a TTree.

   if (fNfill) TakeAction();

   if (fSelectedRows == 0) fDraw = 1; // do not draw

   SetStatus(fSelectedRows);
}


ROOT page - Class index - Top of the page

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