///////////////////////////////////////////////////////////////////////////
//
// Generic Histogram container with support for groups and filling of groups
// by passing a vector of data
//
// Authors:
//   Julian Book   <Julian.Book@cern.ch>
/*

  TOADD: reserved words, MC signals, hist classes, MC weighting, plotting!

  Histograms such as THxF,D, TProfile,2D,3D and n-dimensonal objects such as
  (THn, THnSparse) can be added via the various template functions:
  - AddHistogram
  - AddProfile + different error option (Mean,Rms,.. see: TProfile::BuildOptions(..))
  - AddSparse
  In addition histograms can be filled with weights.

  Different kind of binnings can be passed (linear, arbitrary, logarithmic)
  either via the PairAnalysisHelper functionalities:
  - PairAnalysisHelper::MakeLinBinning(nbins,low,high)
  - PairAnalysisHelper::MakeLogBinning(nbins,low,high)
  - PairAnalysisHelper::MakeArbitraryBinning("1.,4.,10.,..")

  The 'name' and 'title;titleX;titleY;...' of the objects and all axis labels,
  units and names and object names are set in a consistent way and
  it is ensured that they are unique.

  Variables are added via the enumerator of PairAnalysisVarManager. Any
  computation of variables (max=10) are implemented according to TFormula
  using the TMath functions.

  The arguments and options in the function DrawSame and DrawTaskSame provide various and 
  powerful possibilities to plot and post-process histograms. 
  
  Examples:

  // 1 dimensional
  AddHistogram("Event", PairAnalysisHelper::MakeLinBinning(200,-1.,1.),  PairAnalysisVarManager::kXvPrim);

  AddHistogram("Event", PairAnalysisHelper::MakeLinBinning(200,0.0,10.0), "VtxChi/VtxNDF");          // using formulas

  AddHistogram("Track", PairAnalysisHelper::MakeLogBinning(400,0,4.),  PairAnalysisVarManager::kPt); // logarithmic

  AddHistogram("Hit.TRD",PairAnalysisHelper::MakeLinBinning(105,-1.e+2,5.),  "ElossdEdx-ElossMC");   // use MC truth

  // 2 dimensional
  AddHistogram("Track", PairAnalysisHelper::MakeLinBinning(100,-0.5,3.), PairAnalysisVarManager::kY,
                        PairAnalysisHelper::MakeLinBinning(125,0,5.), PairAnalysisVarManager::kPt);

  AddProfile(  "Track", PairAnalysisHelper::MakeLogBinning(50,0.05,10.), PairAnalysisVarManager::kP,
                        PairAnalysisVarManager::kTRDHits, "I"); // Y-average

  ...

*/
//                                                                       //
///////////////////////////////////////////////////////////////////////////

#include <typeinfo>

#include <TAxis.h>
#include <TCanvas.h>
#include <TCollection.h>
#include <TError.h>
#include <TFile.h>
#include <TFormula.h>
#include <TGaxis.h>
#include <TH1.h>
#include <TH1D.h>
#include <TH1F.h>
#include <TH2.h>
#include <TH3.h>
#include <THStack.h>
#include <THashList.h>
#include <THn.h>
#include <THnBase.h>
#include <THnSparse.h>
#include <TKey.h>
#include <TLatex.h>
#include <TLegend.h>
#include <TLegendEntry.h>
#include <TMath.h>
#include <TObjArray.h>
#include <TObjString.h>
#include <TProfile.h>
#include <TProfile2D.h>
#include <TProfile3D.h>
#include <TROOT.h>
#include <TString.h>
#include <TVectorD.h>
#include <TVirtualPS.h>

#include "PairAnalysis.h"
#include "PairAnalysisHelper.h"
#include "PairAnalysisHistos.h"
#include "PairAnalysisMetaData.h"
#include "PairAnalysisSignalMC.h"
#include "PairAnalysisStyler.h"
#include "PairAnalysisVarManager.h"

ClassImp(PairAnalysisHistos)


  PairAnalysisHistos::PairAnalysisHistos()
  :  //   TCollection(),
  TNamed("PairAnalysisHistos", "PairAnalysis Histogram Container")
  , fHistoList()
  , fMetaData(0x0)
  , fList(0x0)
  , fUsedVars(new TBits(PairAnalysisVarManager::kNMaxValues))
  , fReservedWords(new TString("Hit;Track;Pair"))
  , fPrecision(kFloat) {
  //
  // Default constructor
  //
  fHistoList.SetOwner(kTRUE);
  fHistoList.SetName("PairAnalysis_Histos");
  PairAnalysisVarManager::InitFormulas();
  PairAnalysisStyler::LoadStyle();
}

//_____________________________________________________________________________
PairAnalysisHistos::PairAnalysisHistos(const char* name, const char* title)
  :  //   TCollection(),
  TNamed(name, title)
  , fHistoList()
  , fMetaData(0x0)
  , fList(0x0)
  , fUsedVars(new TBits(PairAnalysisVarManager::kNMaxValues))
  , fReservedWords(new TString("Hit;Track;Pair"))
  , fPrecision(kFloat) {
  //
  // TNamed constructor
  //
  fHistoList.SetOwner(kTRUE);
  fHistoList.SetName(name);
  PairAnalysisVarManager::InitFormulas();
  PairAnalysisStyler::LoadStyle();
}

//_____________________________________________________________________________
PairAnalysisHistos::~PairAnalysisHistos() {
  //
  // Destructor
  //
  fHistoList.Clear();
  if (fUsedVars) delete fUsedVars;
  if (fList) fList->Clear();
  if (fMetaData) delete fMetaData;
  delete fReservedWords;
}

//_____________________________________________________________________________
void PairAnalysisHistos::UserHistogram(const char* histClass,
                                       Int_t ndim,
                                       TObjArray* limits,
                                       UInt_t* vars,
                                       UInt_t valTypeW) {
  //
  // Histogram creation n>3 dimension only with non-linear binning
  //

  Bool_t isOk = kTRUE;
  isOk &= (ndim < 21 && ndim > 3);
  if (!isOk) {
    Warning(
      "UserHistogram",
      "Array sizes should be between 3 and 20. Not adding Histogram to '%s'.",
      histClass);
    return;
  }
  isOk &= (ndim == limits->GetEntriesFast());
  if (!isOk) return;

  // set automatic histo name
  TString name;
  for (Int_t iv = 0; iv < ndim; iv++)
    name += Form("%s_", PairAnalysisVarManager::GetValueName(vars[iv]));
  name.Resize(name.Length() - 1);

  isOk &= IsHistogramOk(histClass, name);

  THnD* hist;
  Int_t bins[ndim];
  if (isOk) {
    // get number of bins
    for (Int_t idim = 0; idim < ndim; idim++) {
      TVectorD* vec = (TVectorD*) limits->At(idim);
      bins[idim]    = vec->GetNrows() - 1;
    }

    hist = new THnD(name.Data(), "", ndim, bins, 0x0, 0x0);

    // set binning
    for (Int_t idim = 0; idim < ndim; idim++) {
      TVectorD* vec = (TVectorD*) limits->At(idim);
      hist->SetBinEdges(idim, vec->GetMatrixArray());
    }

    // store variales in axes
    StoreVariables(hist, vars);
    hist->SetUniqueID(valTypeW);  // store weighting variable

    // store which variables are used
    for (Int_t i = 0; i < ndim; i++)
      fUsedVars->SetBitNumber(vars[i], kTRUE);
    fUsedVars->SetBitNumber(valTypeW, kTRUE);

    Bool_t isReserved = fReservedWords->Contains(histClass);
    if (isReserved)
      UserHistogramReservedWords(histClass, hist);
    else
      UserHistogram(histClass, hist);
  }
}

//_____________________________________________________________________________
void PairAnalysisHistos::AddSparse(const char* histClass,
                                   Int_t ndim,
                                   TObjArray* limits,
                                   UInt_t* vars,
                                   UInt_t valTypeW) {
  //
  // THnSparse creation with non-linear binning
  //

  Bool_t isOk = kTRUE;
  isOk &= (ndim == limits->GetEntriesFast());
  if (!isOk) return;

  // set automatic histo name
  TString name;
  for (Int_t iv = 0; iv < ndim; iv++)
    name += Form("%s_", PairAnalysisVarManager::GetValueName(vars[iv]));
  name.Resize(name.Length() - 1);

  isOk &= IsHistogramOk(histClass, name);

  //  THnSparseD *hist;
  PairAnalysisHn* hist;
  Int_t bins[ndim];
  if (isOk) {
    // get number of bins
    for (Int_t idim = 0; idim < ndim; idim++) {
      TVectorD* vec = (TVectorD*) limits->At(idim);
      bins[idim]    = vec->GetNrows() - 1;
    }

    //    hist=new THnSparseD(name.Data(),"", ndim, bins, 0x0, 0x0);
    hist = new PairAnalysisHn(name.Data(), "", ndim, bins, 0x0, 0x0);

    // set binning
    for (Int_t idim = 0; idim < ndim; idim++) {
      TVectorD* vec = (TVectorD*) limits->At(idim);
      hist->SetBinEdges(idim, vec->GetMatrixArray());
    }

    // store variales in axes
    StoreVariables(hist, vars);
    hist->SetUniqueID(valTypeW);  // store weighting variable

    // store which variables are used
    for (Int_t i = 0; i < ndim; i++)
      fUsedVars->SetBitNumber(vars[i], kTRUE);
    fUsedVars->SetBitNumber(valTypeW, kTRUE);

    Bool_t isReserved = fReservedWords->Contains(histClass);
    if (isReserved)
      UserHistogramReservedWords(histClass, hist);
    else
      UserHistogram(histClass, hist);
  }
}

//_____________________________________________________________________________
void PairAnalysisHistos::AddSparse(const char* histClass,
                                   Int_t ndim,
                                   TObjArray* limits,
                                   TFormula** vars,
                                   UInt_t valTypeW) {
  //
  // THnSparse creation with non-linear binning
  //

  Bool_t isOk = kTRUE;
  isOk &= (ndim == limits->GetEntriesFast());
  if (!isOk) return;

  // set automatic histo name
  TString name;
  for (Int_t iv = 0; iv < ndim; iv++)
    name += Form("%s_", (PairAnalysisHelper::GetFormulaName(vars[iv])).Data());
  name.Resize(name.Length() - 1);
  name.ReplaceAll("f(", "");
  name.ReplaceAll(")", "");
  name.Prepend("f(");
  name.Append(")");

  isOk &= IsHistogramOk(histClass, name);

  //  THnSparseD *hist;
  PairAnalysisHn* hist;
  Int_t bins[ndim];
  if (isOk) {
    // get number of bins
    for (Int_t idim = 0; idim < ndim; idim++) {
      TVectorD* vec = (TVectorD*) limits->At(idim);
      bins[idim]    = vec->GetNrows() - 1;
    }

    //    hist=new THnSparseD(name.Data(),"", ndim, bins, 0x0, 0x0);
    hist = new PairAnalysisHn(name.Data(), "", ndim, bins, 0x0, 0x0);

    // set binning
    for (Int_t idim = 0; idim < ndim; idim++) {
      TVectorD* vec = (TVectorD*) limits->At(idim);
      hist->SetBinEdges(idim, vec->GetMatrixArray());
    }

    // add formulas to list of functions
    for (Int_t idim = 0; idim < ndim; idim++) {
      vars[idim]->SetName(Form("axis%dFormula", idim));
      hist->GetListOfFunctions()->Add(vars[idim]);
    }

    // store variales in axes
    //    StoreVariables(hist, vars);
    hist->SetUniqueID(valTypeW);  // store weighting variable

    // adapt the name and title of the histogram in case they are empty
    AdaptNameTitle(hist, histClass);

    // store which variables are used
    //for(Int_t i=0; i<ndim; i++)   fUsedVars->SetBitNumber(vars[i],kTRUE);
    fUsedVars->SetBitNumber(valTypeW, kTRUE);

    Bool_t isReserved = fReservedWords->Contains(histClass);
    if (isReserved)
      UserHistogramReservedWords(histClass, hist);
    else
      UserHistogram(histClass, hist);
  }
}

//_____________________________________________________________________________
TString PairAnalysisHistos::UserHistogram(const char* histClass,
                                          TObject* hist) {
  //
  // Add any type of user histogram
  //

  //special case for the calss Pair. where histograms will be created for all pair classes
  Bool_t isReserved = fReservedWords->Contains(histClass);
  if (isReserved) {
    UserHistogramReservedWords(histClass, hist);
    return hist->GetName();
  }

  // if (!IsHistogramOk(histClass,hist->GetName())) return hist->GetName();
  // THashList *classTable=(THashList*)fHistoList.FindObject(histClass);
  //  //  hist->SetDirectory(0);

  // store variables axis
  UInt_t valType[20] = {0};
  // extract variables from axis
  FillVarArray(hist, valType);
  // TODO: implement THn/PairAnalysisHn
  // change to mc truth variables if available
  TString hclass = histClass;
  if (hclass.Contains("MCtruth") && !(hist->IsA() == PairAnalysisHn::Class())) {
    for (Int_t i = 0; i < 2; i++) {
      /// protection for changes of variable enum (in the postprocessing) --> use axistname indentification
      //      UInt_t valTypeFromTitle = 0;
      if (!i)
        valType[i] = PairAnalysisVarManager::GetValueType(
          ((TH1*) hist)->GetXaxis()->GetName());
      else
        valType[i] = PairAnalysisVarManager::GetValueType(
          ((TH1*) hist)->GetYaxis()->GetName());
      //Printf("SWITCH TO MC: before: %d %s, (via axis name %d) ---->",valType[i],PairAnalysisVarManager::GetValueName(valType[i]),valTypeFromTitle);
      valType[i] = PairAnalysisVarManager::GetValueTypeMC(valType[i]);
      // if theres no corresponding MCtruth variable, skip adding this histogram
      //      if(valType[i] < PairAnalysisVarManager::kNMaxValues && valType[i]>0) return hist->GetName();
      if (valType[i] < PairAnalysisVarManager::kPairMax && valType[i] > 0)
        return hist->GetName();
      // request filling of mc variable
      fUsedVars->SetBitNumber(valType[i], kTRUE);
      //      Printf("after: %d %s",valType[i],PairAnalysisVarManager::GetValueName(valType[i]));
    }
    StoreVariables(hist, valType);
    hist->SetUniqueID(valType[19]);  // store weighting variable
    // check for formulas
    if (hist->InheritsFrom(TH1::Class())) {
      TIter next(((TH1*) hist)->GetListOfFunctions());
      TFormula* f = 0;
      while ((f = dynamic_cast<TFormula*>(next()))) {
        for (Int_t i = 0; i < f->GetNpar(); i++) {
          Int_t parMC =
            PairAnalysisVarManager::GetValueTypeMC(f->GetParameter(i));
          // if theres none corresponding MCtruth variable, skip adding this histogram
          if (parMC < PairAnalysisVarManager::kNMaxValues)
            return hist->GetName();
          f->SetParameter(i, parMC);
          f->SetParName(i, PairAnalysisVarManager::GetValueName(parMC));
          fUsedVars->SetBitNumber(parMC, kTRUE);
        }
      }
      // change histogram key according to mctruth information
      AdaptNameTitle((TH1*) hist, histClass);
    }
  } else {
    StoreVariables(hist, valType);
    hist->SetUniqueID(valType[19]);  // store weighting variable
  }

  // add histogram to class
  if (!IsHistogramOk(histClass, hist->GetName())) return hist->GetName();
  THashList* classTable = (THashList*) fHistoList.FindObject(histClass);
  //  hist->SetDirectory(0);
  if (classTable) classTable->Add(hist);
  return hist->GetName();
}

//_____________________________________________________________________________
TH1* PairAnalysisHistos::GetTHist(const char* histClass,
                                  const char* name,
                                  const char* title,
                                  const TVectorD* const binsX,
                                  const TVectorD* const binsY,
                                  const TVectorD* const binsZ) {
  //
  // retrieve n-dimensional Hist depending on arguments
  //
  Bool_t isOk = kTRUE;
  isOk &= IsHistogramOk(histClass, name);
  isOk &= (binsX != 0x0);
  if (!isOk) return 0x0;
  switch (fPrecision) {
    case kFloat:
      if (!binsY)
        return (new TH1F(
          name, title, binsX->GetNrows() - 1, binsX->GetMatrixArray()));
      else if (!binsZ)
        return (new TH2F(name,
                         title,
                         binsX->GetNrows() - 1,
                         binsX->GetMatrixArray(),
                         binsY->GetNrows() - 1,
                         binsY->GetMatrixArray()));
      else
        return (new TH3F(name,
                         title,
                         binsX->GetNrows() - 1,
                         binsX->GetMatrixArray(),
                         binsY->GetNrows() - 1,
                         binsY->GetMatrixArray(),
                         binsZ->GetNrows() - 1,
                         binsZ->GetMatrixArray()));
      break;
    case kDouble:
      if (!binsY)
        return (new TH1D(
          name, title, binsX->GetNrows() - 1, binsX->GetMatrixArray()));
      else if (!binsZ)
        return (new TH2D(name,
                         title,
                         binsX->GetNrows() - 1,
                         binsX->GetMatrixArray(),
                         binsY->GetNrows() - 1,
                         binsY->GetMatrixArray()));
      else
        return (new TH3D(name,
                         title,
                         binsX->GetNrows() - 1,
                         binsX->GetMatrixArray(),
                         binsY->GetNrows() - 1,
                         binsY->GetMatrixArray(),
                         binsZ->GetNrows() - 1,
                         binsZ->GetMatrixArray()));
      break;
    default: return 0x0; break;
  }
}

//_____________________________________________________________________________
TH1* PairAnalysisHistos::GetTProf(const char* histClass,
                                  const char* name,
                                  const char* title,
                                  const TVectorD* const binsX,
                                  const TVectorD* const binsY,
                                  const TVectorD* const binsZ,
                                  TString option) {
  //
  // retrieve n-dimensional profile histogram with error options depending on arguments
  //
  Bool_t isOk = kTRUE;
  isOk &= IsHistogramOk(histClass, name);
  isOk &= (binsX != 0x0);
  if (!isOk) return 0x0;
  // parse error option
  TString opt   = "";
  Double_t pmin = 0., pmax = 0.;
  if (!option.IsNull()) {
    TObjArray* arr = option.Tokenize(";");
    arr->SetOwner();
    opt = ((TObjString*) arr->At(0))->GetString();
    if (arr->GetEntriesFast() > 1)
      pmin = (((TObjString*) arr->At(1))->GetString()).Atof();
    if (arr->GetEntriesFast() > 2)
      pmax = (((TObjString*) arr->At(2))->GetString()).Atof();
    delete arr;
  }
  // build profile with error options and return it
  TH1* prof = 0x0;
  if (!binsY)
    return (new TProfile(name,
                         title,
                         binsX->GetNrows() - 1,
                         binsX->GetMatrixArray(),
                         pmin,
                         pmax,
                         opt.Data()));
  else if (!binsZ) {
    prof = new TProfile2D(name,
                          title,
                          binsX->GetNrows() - 1,
                          binsX->GetMatrixArray(),
                          binsY->GetNrows() - 1,
                          binsY->GetMatrixArray());
    ((TProfile2D*) prof)->BuildOptions(pmin, pmax, opt.Data());
    return prof;
  } else {
    prof = new TProfile3D(name,
                          title,
                          binsX->GetNrows() - 1,
                          binsX->GetMatrixArray(),
                          binsY->GetNrows() - 1,
                          binsY->GetMatrixArray(),
                          binsZ->GetNrows() - 1,
                          binsZ->GetMatrixArray());
    ((TProfile3D*) prof)->BuildOptions(pmin, pmax, opt.Data());
    return prof;
  }
}

//_____________________________________________________________________________
TFormula* PairAnalysisHistos::GetFormula(const char* name,
                                         const char* formula) {
  //
  // build a TFormula object
  //
  TFormula* form = new TFormula(name, formula);
  // compile function
  if (form->Compile()) return 0x0;
  //set parameter/variable identifier
  for (Int_t i = 0; i < form->GetNpar(); i++) {
    form->SetParName(
      i, PairAnalysisVarManager::GetValueName(form->GetParameter(i)));
    fUsedVars->SetBitNumber((Int_t) form->GetParameter(i), kTRUE);
  }
  return form;
}

//_____________________________________________________________________________
void PairAnalysisHistos::AddClass(const char* histClass) {
  //
  // Add a class of histograms
  // Several classes can be added by separating them by a ';' e.g. 'class1;class2;class3'
  //
  TString hists(histClass);
  TObjArray* arr = hists.Tokenize(";");
  TIter next(arr);
  TObject* o = 0;
  while ((o = next())) {
    if (fHistoList.FindObject(o->GetName())) {
      Warning(
        "AddClass", "Cannot create class '%s' it already exists.", histClass);
      continue;
    }
    if (fReservedWords->Contains(o->GetName())) {
      Error("AddClass", "Pair is a reserved word, please use another name");
      continue;
    }
    THashList* table = new THashList;
    table->SetOwner(kTRUE);
    table->SetName(o->GetName());
    fHistoList.Add(table);
  }
  delete arr;
}

//_____________________________________________________________________________
void PairAnalysisHistos::FillClass(TString histClass, const Double_t* values) {
  //
  // Fill class 'histClass' (by name)
  //
  THashList* classTable = (THashList*) fHistoList.FindObject(histClass.Data());
  if (!classTable) {
    //    Warning("FillClass","Cannot fill class '%s' its not defined.",histClass.Data());
    return;
  }

  TIter nextHist(classTable);
  TObject* obj = 0;
  while ((obj = (TObject*) nextHist()))
    FillValues(obj, values);

  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::UserHistogramReservedWords(const char* histClass,
                                                    const TObject* hist) {
  //
  // Creation of histogram for all pair or track types
  //
  TString title(hist->GetTitle());

  TIter nextClass(&fHistoList);
  THashList* l = 0;
  while ((l = static_cast<THashList*>(nextClass()))) {
    TString name(l->GetName());
    if (name.Contains(histClass)) {
      TObject* h = hist->Clone();
      // Tobject has no function SetDirectory, didn't we need this???
      //      h->SetDirectory(0);
      if (h->InheritsFrom(TH1::Class()))
        ((TH1*) h)->SetTitle(Form("%s %s", title.Data(), l->GetName()));
      else
        ((THnBase*) h)->SetTitle(Form("%s %s", title.Data(), l->GetName()));

      UserHistogram(l->GetName(), h);
    }
  }
  delete hist;

  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::DumpToFile(const char* file) {
  //
  // Dump the histogram list to a newly created root file
  //
  TFile f(file, "recreate");
  fHistoList.Write(fHistoList.GetName(), TObject::kSingleKey);
  f.Close();
}

//_____________________________________________________________________________
TObject* PairAnalysisHistos::GetHist(const char* histClass,
                                     const char* name) const {
  //
  // return object 'name' in 'histClass'
  //
  THashList* classTable = (THashList*) fHistoList.FindObject(histClass);
  if (!classTable) return 0x0;
  return classTable->FindObject(name);
}

//_____________________________________________________________________________
TH1* PairAnalysisHistos::GetHistogram(const char* histClass,
                                      const char* name) const {
  //
  // return histogram 'name' in 'histClass'
  //
  return ((TH1*) GetHist(histClass, name));
}

//_____________________________________________________________________________
TObject* PairAnalysisHistos::GetHist(const char* cutClass,
                                     const char* histClass,
                                     const char* name) const {
  //
  // return object from list of list of histograms
  // this function is thought for retrieving histograms if a list of PairAnalysisHistos is set
  //

  if (!fList) return 0x0;
  THashList* h = dynamic_cast<THashList*>(fList->FindObject(cutClass));
  if (!h) return 0x0;
  THashList* classTable = dynamic_cast<THashList*>(h->FindObject(histClass));
  if (!classTable) return 0x0;
  return classTable->FindObject(name);
}

//_____________________________________________________________________________
TH1* PairAnalysisHistos::GetHistogram(const char* cutClass,
                                      const char* histClass,
                                      const char* name) const {
  //
  // return histogram from list of list of histograms
  // this function is thought for retrieving histograms if a list of PairAnalysisHistos is set
  //
  return ((TH1*) GetHist(cutClass, histClass, name));
}

//_____________________________________________________________________________
void PairAnalysisHistos::Draw(const Option_t* option) {
  //
  // Draw histograms
  //

  TString drawStr(option);
  TObjArray* arr = drawStr.Tokenize(";");
  arr->SetOwner();
  TIter nextOpt(arr);

  TString drawClasses;
  TObjString* ostr = 0x0;

  TString currentOpt;
  TString testOpt;
  while ((ostr = (TObjString*) nextOpt())) {
    currentOpt = ostr->GetString();
    currentOpt.Remove(TString::kBoth, '\t');
    currentOpt.Remove(TString::kBoth, ' ');

    testOpt = "classes=";
    if (currentOpt.Contains(testOpt.Data())) {
      drawClasses = currentOpt(testOpt.Length(), currentOpt.Length());
    }
  }

  delete arr;
  drawStr.ToLower();
  //optionsfList
  //   Bool_t same=drawOpt.Contains("same"); //FIXME not yet implemented

  TCanvas* c = 0x0;
  if (gVirtualPS) {
    if (!gPad) {
      Error("Draw",
            "When writing to a file you have to create a canvas before opening "
            "the file!!!");
      return;
    }
    c = gPad->GetCanvas();
    c->cd();
    //     c=new TCanvas;
  }

  TIter nextClass(&fHistoList);
  THashList* classTable = 0;
  //   Bool_t first=kTRUE;
  while ((classTable = (THashList*) nextClass())) {
    //test classes option
    if (!drawClasses.IsNull() && !drawClasses.Contains(classTable->GetName()))
      continue;
    //optimised division
    Int_t nPads = classTable->GetEntries();
    Int_t nCols = (Int_t) TMath::Ceil(TMath::Sqrt(nPads));
    Int_t nRows = (Int_t) TMath::Ceil((Double_t) nPads / (Double_t) nCols);

    //create canvas
    if (!gVirtualPS) {
      TString canvasName;
      canvasName.Form("c%s_%s", GetName(), classTable->GetName());
      c = (TCanvas*) gROOT->FindObject(canvasName.Data());
      if (!c)
        c = new TCanvas(canvasName.Data(),
                        Form("%s: %s", GetName(), classTable->GetName()));
      c->Clear();
    } else {
      //       if (first){
      //         first=kFALSE;
      //         if (nPads>1) gVirtualPS->NewPage();
      //       } else {
      if (nPads > 1) c->Clear();
      //       }
    }
    if (nCols > 1 || nRows > 1) c->Divide(nCols, nRows);

    //loop over histograms and draw them
    TIter nextHist(classTable);
    Int_t iPad = 0;
    TH1* h     = 0;
    while ((h = (TH1*) nextHist())) {
      TString drawOpt;
      if ((h->InheritsFrom(TH2::Class()))) drawOpt = "colz";
      if (nCols > 1 || nRows > 1) c->cd(++iPad);
      if (TMath::Abs(h->GetXaxis()->GetBinWidth(1)
                     - h->GetXaxis()->GetBinWidth(2))
          > 1e-10)
        gPad->SetLogx();
      if (TMath::Abs(h->GetYaxis()->GetBinWidth(1)
                     - h->GetYaxis()->GetBinWidth(2))
          > 1e-10)
        gPad->SetLogy();
      if (TMath::Abs(h->GetZaxis()->GetBinWidth(1)
                     - h->GetZaxis()->GetBinWidth(2))
          > 1e-10)
        gPad->SetLogz();
      TString histOpt = h->GetOption();
      histOpt.ToLower();
      if (histOpt.Contains("logx")) gPad->SetLogx();
      if (histOpt.Contains("logy")) gPad->SetLogy();
      if (histOpt.Contains("logz")) gPad->SetLogz();
      histOpt.ReplaceAll("logx", "");
      histOpt.ReplaceAll("logy", "");
      histOpt.ReplaceAll("logz", "");
      h->Draw(drawOpt.Data());
    }
    if (gVirtualPS) { c->Update(); }
  }
  //   if (gVirtualPS) delete c;
}

//_____________________________________________________________________________
void PairAnalysisHistos::Print(const Option_t* option) const {
  //
  // Print classes and histograms
  //
  TString optString(option);

  if (optString.IsNull()) PrintStructure();
}

//_____________________________________________________________________________
void PairAnalysisHistos::PrintStructure() const {
  //
  // Print classes and histograms in the class to stdout
  //
  if (!fList) {
    TIter nextClass(&fHistoList);
    THashList* classTable = 0;
    while ((classTable = (THashList*) nextClass())) {
      TIter nextHist(classTable);
      TObject* o = 0;
      Printf("+ %s\n", classTable->GetName());
      while ((o = nextHist()))
        Printf("| ->%s\n", o->GetName());
    }
  } else {
    TIter nextCutClass(fList);
    THashList* cutClass = 0x0;
    while ((cutClass = (THashList*) nextCutClass())) {
      TString cla = cutClass->GetName();
      if (cla.Contains("QAcuts")) continue;
      Printf("+ %s\n", cutClass->GetName());
      TIter nextClass(cutClass);
      THashList* classTable = 0;
      while ((classTable = (THashList*) nextClass())) {
        TIter nextHist(classTable);
        TObject* o = 0;
        Printf("|  + %s\n", classTable->GetName());
        while ((o = nextHist()))
          Printf("|  | ->%s\n", o->GetName());
      }
    }
  }
}

//_____________________________________________________________________________
void PairAnalysisHistos::SetHistogramList(THashList& list,
                                          Bool_t setOwner /*=kTRUE*/) {
  //
  // set histogram classes and histograms to this instance. It will take onwnership!
  //
  ResetHistogramList();
  TString name(GetName());
  //  if (name == "PairAnalysisHistos")
  SetName(list.GetName());
  TIter next(&list);
  TObject* o;
  while ((o = next())) {
    fHistoList.Add(o);
  }
  if (setOwner) {
    list.SetOwner(kFALSE);
    fHistoList.SetOwner(kTRUE);
    fHistoList.SetName(list.GetName());
  } else {
    fHistoList.SetOwner(kFALSE);
    fHistoList.SetName(list.GetName());
  }
}

//_____________________________________________________________________________
Bool_t PairAnalysisHistos::SetCutClass(const char* cutClass) {
  //
  // Assign histogram list according to cutClass
  //

  if (!fList) return kFALSE;
  ResetHistogramList();
  THashList* h = dynamic_cast<THashList*>(fList->FindObject(cutClass));
  if (!h) {
    Warning("SetCutClass", "cutClass '%s' not found", cutClass);
    return kFALSE;
  }
  SetHistogramList(*h, kFALSE);
  return kTRUE;
}
//_____________________________________________________________________________
Bool_t PairAnalysisHistos::IsHistogramOk(const char* histClass,
                                         const char* name) {
  //
  // check whether the histogram class exists and the histogram itself does not exist yet
  //
  Bool_t isReserved = fReservedWords->Contains(histClass);
  if (!fHistoList.FindObject(histClass) && !isReserved) {
    Warning("IsHistogramOk",
            "Cannot create histogram. Class '%s' not defined. Please create it "
            "using AddClass before.",
            histClass);
    return kFALSE;
  }
  if (GetHist(histClass, name)) {
    Warning("IsHistogramOk",
            "Cannot create histogram '%s' in class '%s': It already exists!",
            name,
            histClass);
    return kFALSE;
  }
  return kTRUE;
}

// //_____________________________________________________________________________
// TIterator* PairAnalysisHistos::MakeIterator(Bool_t dir) const
// {
//   //
//   //
//   //
//   return new TListIter(&fHistoList, dir);
// }

//_____________________________________________________________________________
void PairAnalysisHistos::ReadFromFile(const char* file,
                                      const char* task,
                                      const char* config) {
  //
  // Read histos from file
  //
  TFile f(file);
  TIter nextKey(f.GetListOfKeys());
  TKey* key = 0;
  while ((key = (TKey*) nextKey())) {
    TString name = key->GetName();
    // check for meta data
    if (name.Contains(Form("PairAnalysisMetaData_%s", task))) {
      fMetaData = new PairAnalysisMetaData();
      fMetaData->SetMetaData(*dynamic_cast<TList*>(f.Get(key->GetName())),
                             kFALSE);
    }
    // check for histos
    if (!name.Contains(Form("PairAnalysisHistos_%s", task))) continue;
    if (!strlen(task) && !name.Contains(task)) continue;
    TObject* o  = f.Get(key->GetName());
    TList* list = dynamic_cast<TList*>(o);
    if (!list)
      continue;
    else
      fList = list;
    THashList* listCfg = dynamic_cast<THashList*>(list->FindObject(config));
    if (!listCfg) continue;
    SetHistogramList(*listCfg);
    break;
  }
  f.Close();
  // load style
  PairAnalysisStyler::LoadStyle();
}

//_____________________________________________________________________________
TObjArray* PairAnalysisHistos::DrawTaskSame(TString histName,
                                            TString opt,
                                            TString histClassDenom,
                                            TString taskDenom) {
  ///
  /// Draw histograms of different tasks into the same canvas
  ///
  /// additional plotting options to DrawSame:
  /// "selcfg":     option to (de-)select certain task/config specified in "histClassDenom",
  ///               delimiters ':;,' are recognized, exclusion done by prepending '!'
  /// "cutstep":    histograms of the cut steps are compared for a single task (see AnalysisFilter::AddHistos)
  ///
  /// if argument "taskDenom" is provided histogram ratios to this task/config are calculated


  TObjArray* selections = histClassDenom.Tokenize(":;,");

  opt.ToLower();
  TString optString(opt);
  Bool_t optGoff    = optString.Contains("goff");
  Bool_t optEff     = optString.Contains("eff");
  Bool_t optCutStep = optString.Contains("cutstep");
  Bool_t optSelCfg  = optString.Contains("selcfg");
  opt.ReplaceAll("selcfg", "");
  fHistoList.SetOwner(kFALSE);

  /// output array
  TObjArray* arr = NULL;
  if (optGoff) Info("DrawTaskSame", "graphics option off, collect an array");
  {
    //    arr=(TObjArray*)gROOT->FindObject(Form("%s",histName.Data()));
    //arr=(TObjArray*)gROOT->FindObject(GetName());
    //    if(arr) { Warning("DrawTaskSame","Clear existing array %s",GetName()); arr->ls(); arr->Clear(); }
    //    else
    arr = new TObjArray();
    //    arr->SetName(Form("%s",histName.Data()));
    arr->SetName(GetName());
    arr->SetOwner(kFALSE);
  }

  /// legend
  TString legendname = GetName();
  //  printf("DrawTaskSame: legendname %s\n",legendname.Data());

  /// reserved words
  TObjArray* reservedWords = fReservedWords->Tokenize(":;");

  /// find cut step lists if option 'cutstep' is active
  if (optCutStep) {
    TString cutstepTask = fHistoList.GetName();
    THashList* listCutStep =
      dynamic_cast<THashList*>(fList->FindObject(cutstepTask));
    if (listCutStep) fList = listCutStep;
  }

  /// find denominator list 'taskDenom'
  THashList* listDenom =
    dynamic_cast<THashList*>(fList->FindObject(taskDenom.Data()));
  if (listDenom) opt += "div";

  /// iterate over all tasks and their lists in the file
  TIter nextCfg(fList);
  THashList* listCfg = 0;
  while ((listCfg = static_cast<THashList*>(nextCfg()))) {

    TString lname = listCfg->GetName();

    /// exclude QAcuts
    if (lname.Contains("QAcuts_")) continue;
    Info("DrawTaskSame", " Task name %s ", lname.Data());

    /// skip same config if argument 'taskDenom' is set
    if (!optEff && listDenom && lname.EqualTo(taskDenom)) continue;

    /// skip configs according to selection done via histClassDenom and option 'selcfg'
    if (optSelCfg && selections->GetEntriesFast()) {
      Bool_t pass = kFALSE;
      for (Int_t is = 0; is < selections->GetEntriesFast(); is++) {
        Bool_t testIgnore = kFALSE;
        TString raw       = ((TObjString*) selections->At(is))->GetString();

        //	printf("sel: '%s' \n",  histClassDenom.Data());

        /// check if selection string contains reserved word
        /// if true ignore it for config selection
        for (Int_t ir = 0; ir < reservedWords->GetEntriesFast(); ir++) {
          testIgnore =
            raw.Contains(((TObjString*) reservedWords->At(ir))->GetString());
          if (testIgnore) break;
        }
        if (testIgnore) continue;

        TString srch = raw;
        srch.ReplaceAll("!", "");
        Bool_t optExclSel = !(srch.EqualTo(raw));  // exclude or not
        // printf("selection %d/%d: raw '%s' \t search: '%s' exclude: %d compare to: '%s' \t pass %d \n",
        //        is,selections->GetEntriesFast()-1,raw.Data(),srch.Data(),optExclSel,lname.Data(),pass);
        // printf("\t decision !(%d^%d)=%d  \n",(!lname.EqualTo(srch)),(optExclSel),!(!lname.EqualTo(srch))^(optExclSel));
        /// decision
        if (!(!lname.EqualTo(srch)) ^ (optExclSel)) pass = kTRUE;
        /// same config found - direct decision (skip other selections)
        if (lname.EqualTo(srch)) {
          pass = !(!lname.EqualTo(srch)) ^ (optExclSel);
          // printf("\t same config found -> stop with pass: %d \n",pass);
          break;
        }
        // remove config selection string abgearbeitet
        //      histClassDenom.ReplaceAll(raw.Data(),"");
      }
      if (!pass) continue;
    }

    /// keep only legend name!=task name
    if (lname.EqualTo(legendname)) legendname = "";

    /// update current histogram list
    ResetHistogramList();
    TIter next(listCfg);
    Int_t idx = 0;
    TObject* o;
    while ((o = next())) {
      fHistoList.AddAt(o, idx++);
    }
    //fHistoList.Print();

    /// adapt name for legend
    SetName(listCfg->GetName());
    arr->AddAll(
      DrawSame(histName, (opt + "task").Data(), histClassDenom, listDenom));
  }

  /// set legend name
  if (optString.Contains("leg")) {
    //    printf("DrawTaskSame: SET legendname %s\n",legendname.Data());
    legendname.ReplaceAll(".", "");
    TList* prim  = gPad->GetListOfPrimitives();
    TLegend* leg = (TLegend*) prim->FindObject("TPave");
    // remove legend header from legend entry
    TList* llist = leg->GetListOfPrimitives();
    Int_t nent   = llist->GetEntries();
    for (Int_t il = 0; il < nent; il++) {
      TLegendEntry* lent = static_cast<TLegendEntry*>(llist->At(il));
      TString lst(lent->GetLabel());
      lst.ReplaceAll(legendname.Data(), "");
      lent->SetLabel(lst.Data());
    }

    if (!legendname.EqualTo("none"))
      leg->SetHeader("");
    else
      leg->SetHeader(legendname.Data());
    PairAnalysisStyler::SetLegendAttributes(
      leg);  // coordinates, margins, fillstyle, fontsize
    leg->Draw();
  }

  /// cleanup
  if (selections) delete selections;
  if (reservedWords) delete reservedWords;
  if (!optGoff) delete arr;

  return arr;
}

//_____________________________________________________________________________
TObjArray* PairAnalysisHistos::DrawSame(TString histName,
                                        TString option,
                                        TString histClassDenom,
                                        THashList* listDenom) {
  ///
  /// Draw histograms with the same histName into a canvas
  ///
  /// additional plotting options to TH1::Draw():
  /// "back":       iterate backwards over the histClasses
  /// "goff":       graphics are switched off & an array with the objects is returned
  /// "task":       histograms of different tasks are compared (see DrawTaskSame)
  ///
  /// "div":        histograms of different tasks are divided (see DrawTaskSame) INTERNAL?
  /// "eff":        efficiencies are calculated
  /// "ratio":      ratios of any histclass to "histClassDenom" are calculated
  /// "oneOver":    the histogram is rescaled by 1./(bin contents)
  /// "stack":      build and plot a stack histogram
  ///
  /// "noMc":       no mc signals are plotted
  /// "noMcTrue":   no mc truth signals are plotted
  /// "onlyMc":     only mc signals are plotted
  /// "onlyMcTrue": only mc truth signals are plotted
  /// "sel":        option to (de-)select certain histClasses specified in "histClassDenom",
  ///               delimiters ":;," are recognized, exclusion done by prepending "!"
  ///
  /// "can":        a new canvas is created with name: "c"+"histName"
  /// "logx,y,z":   the axis are plotted in log-scale (labels are added automatically according to the range)
  /// "meta"        adds default meta data to the pad (see PairAnalysisMetaData::DrawSame)
  /// "legF":       (option "F":filled) legend will be created with caption=className ,
  ///               can be modified by PairAnalysisHistos::SetName("mycaption"),
  ///               change of legend position: see PairAnalysisStyler::SetLegendAlign
  /// "meanX,Y":    quote the mean in the legend (Y only works for TProfile a.t.m.)
  /// "rmsX,Y":     quote the rms in the legend (Y only works for TProfile a.t.m.)
  /// "det":        adds the detector name to the legend for detector specific histograms (e.g. hit histograms)
  ///
  /// "width":      scale histograms by 1./bin width according to TH1::Scale
  /// "rebinstat0.XY":  the objects are rebinned to have <"0.XY" stat uncertainty in each bin (max two digits)
  /// "rebinX":     rebins the histogram along x-axis by factor "X" (for X<10)
  /// "sclmax":     scale the histogram by 1./maximum
  /// "norm":       histogram is normalized to 1.
  /// "normY":      2D-histograms are normalized in x-axis slices to 1.
  /// "cum":        calculate cumulated sum of bins (+under- & overflow) for 1D-histograms (left-to-right)
  /// "cumR":       calculate cumulated sum of bins (+under- & overflow)for 1D-histograms ("R"=reverse: right-to-left)
  /// "events":     use number of selected (after cuts) events in meta data to normalize the histograms
  /// "smoothX":    smooths the histogram along x-axis by factor "X" (for X<10)
  ///
  /// "rststy":     reset style index to zero (usefull when the same color code should be plotted on top of each other)
  /// "geant":      translate geantId to geant process names (see PairAnalysisHelper::SetGEANTBinLabels)
  /// "pdg":        translate bin low edges into pdg label
  /// "pdgc":       translate bin low edges into pdg label for bins with entries

  TString optString(option);
  optString.ToLower();
  printf("Plot hist: '%s' class-denom/sel: '%s' \t listDenom: '%s' \t options: "
         "'%s' \n",
         histName.Data(),
         histClassDenom.Data(),
         (listDenom ? listDenom->GetName() : ""),
         optString.Data());
  Bool_t optBack = optString.Contains("back");
  optString.ReplaceAll("back", "");
  Bool_t optGoff = optString.Contains("goff");
  optString.ReplaceAll("goff", "");
  Bool_t optTask = optString.Contains("task");
  optString.ReplaceAll("task", "");
  Bool_t optCutStep = optString.Contains("cutstep");
  optString.ReplaceAll("cutstep", "");
  /// options - calulation
  Bool_t optDiv = optString.Contains("div");
  optString.ReplaceAll("div", "");
  Bool_t optEff = optString.Contains("eff");
  optString.ReplaceAll("eff", "");
  Bool_t optRatio = optString.Contains("ratio");
  optString.ReplaceAll("ratio", "");
  Bool_t optOneOver = optString.Contains("oneover");
  optString.ReplaceAll("oneover", "");
  /// options - selection
  Bool_t optNoMCtrue = optString.Contains("nomctrue");
  optString.ReplaceAll("nomctrue", "");
  Bool_t optNoMC = optString.Contains("nomc");
  optString.ReplaceAll("nomc", "");
  Bool_t optOnlyMCtrue = optString.Contains("onlymctrue");
  optString.ReplaceAll("onlymctrue", "");
  Bool_t optOnlyMC = optString.Contains("onlymc");
  optString.ReplaceAll("onlymc", "");
  Bool_t optSel = optString.Contains("sel");
  optString.ReplaceAll("sel", "");
  /// options - representation
  Bool_t optCan = optString.Contains("can");
  optString.ReplaceAll("can", "");
  Bool_t optLegFull = optString.Contains("legf");
  optString.ReplaceAll("legf", "");
  Bool_t optLeg = optString.Contains("leg");
  optString.ReplaceAll("leg", "");
  Bool_t optDet = optString.Contains("det");
  optString.ReplaceAll("det", "");
  Bool_t optMeta = optString.Contains("meta");
  optString.ReplaceAll("meta", "");
  Bool_t optWdth = optString.Contains("width");
  optString.ReplaceAll("width", "");
  Bool_t optRbnStat = optString.Contains("rebinstat");
  optString.ReplaceAll("rebinstat", "stat");
  Bool_t optRbn    = optString.Contains("rebin");
  Bool_t optSmooth = optString.Contains("smooth");
  Bool_t optSclMax = optString.Contains("sclmax");
  optString.ReplaceAll("sclmax", "");
  Bool_t optNormY = optString.Contains("normy");
  optString.ReplaceAll("normy", "");
  Bool_t optNorm = optString.Contains("norm");
  optString.ReplaceAll("norm", "");
  Bool_t optCumR = optString.Contains("cumr");
  optString.ReplaceAll("cumr", "");
  Bool_t optCum = optString.Contains("cum");
  optString.ReplaceAll("cum", "");
  Bool_t optEvt = optString.Contains("events");
  optString.ReplaceAll("events", "");
  Bool_t optStack = optString.Contains("stack");
  optString.ReplaceAll("stack", "");
  Bool_t optRstSty = optString.Contains("rststy");
  optString.ReplaceAll("rststy", "");
  Bool_t optSlicesY = optString.Contains("slicesy");
  optString.ReplaceAll("slicesy", "");
  /// options - information
  Bool_t optMeanX = optString.Contains("meanx");
  optString.ReplaceAll("meanx", "");
  Bool_t optRmsX = optString.Contains("rmsx");
  optString.ReplaceAll("rmsx", "");
  Bool_t optMeanY = optString.Contains("meany");
  optString.ReplaceAll("meany", "");
  Bool_t optRmsY = optString.Contains("rmsy");
  optString.ReplaceAll("rmsy", "");
  Bool_t optGeant = optString.Contains("geant");
  optString.ReplaceAll("geant", "");
  Bool_t optPdgClean = optString.Contains("pdgc");
  optString.ReplaceAll("pdgc", "");
  Bool_t optPdg = optString.Contains("pdg");
  optString.ReplaceAll("pdg", "");

  /// set rebinning
  Int_t rbn = 2;
  if (optRbn) {
    TString rebin(
      optString(optString.Index("rebin", 5, 0, TString::kExact) + 5));
    if (rebin.IsDigit()) {
      rbn = rebin.Atoi();
      optString.ReplaceAll(rebin, "");
    }
    optString.ReplaceAll("rebin", "");
  }
  /// set stat. uncertainty limit for rebinning
  /// NOTE: first check for one digit, then 2 digits
  TArrayD* limits = NULL;
  Double_t stat   = 0.8;
  if (optRbnStat) {
    TString rebin(
      optString(optString.Index("stat", 4, 0, TString::kExact) + 4, 4));
    if (!rebin.IsFloat())
      rebin = optString(optString.Index("stat", 4, 0, TString::kExact) + 4, 3);
    if (rebin.IsFloat()) {
      stat = rebin.Atof();
      //    printf("rebinstat string: '%s' -> %f\n",rebin.Data(),stat);
      optString.ReplaceAll(rebin, "");
    }
    optString.ReplaceAll("stat", "");
  }

  /// set smoothing
  Int_t smth = 1;
  if (optSmooth) {
    TString smooth(
      optString(optString.Index("smooth", 6, 0, TString::kExact) + 6));
    if (smooth.IsDigit()) {
      smth = smooth.Atoi();
      optString.ReplaceAll(smooth, "");
    }
    optString.ReplaceAll("smooth", "");
  }

  /// activate std option for legend and conncetions
  if (optLegFull) optLeg = kTRUE;
  if (optCumR) optCum = kTRUE;

  /// selection string
  TString select("");
  TObjArray* selections = (optSel ? histClassDenom.Tokenize(":;,") : NULL);
  if (optSel) histClassDenom = "";

  /// output array
  TObjArray* arr = 0x0;
  if (optGoff) {
    Info("DrawSame", "graphics option off, collect an array");
    //    arr=(TObjArray*)gROOT->FindObject(Form("%s",histName.Data()));
    arr = (TObjArray*) gROOT->FindObject(GetName());
    if (arr) {
      Warning("DrawSame", "Clear existing array %s", GetName());
      arr->ls();
      arr->Clear();
    } else
      arr = new TObjArray();
    //    arr->SetName(Form("%s",histName.Data()));
    arr->SetName(GetName());
    arr->SetOwner(kFALSE);
  }

  /// stack option
  THStack* hs = NULL;
  // if(optStack) {
  //   hs = new THStack("hs","stacked histograms");
  // }

  /// add canvas
  TCanvas* c = 0;
  if (optCan) {
    c = (TCanvas*) gROOT->FindObject(Form("c%s", histName.Data()));
    if (!c) {
      c = new TCanvas(Form("c%s", histName.Data()),
                      Form("All '%s' histograms", histName.Data()));
    }
    // c->Clear();
    c->cd();
  }

  /// count number of drawn objects in pad
  TH1* hFirst = 0x0;
  TObject* obj;
  Int_t nobj  = 0;
  TList* prim = (gPad ? gPad->GetListOfPrimitives() : 0x0);
  //  if(prim) prim->ls();
  //  if(prim && prim->GetSize()>1 && !optGoff) prim->RemoveLast(); // remove redraw axis histogram
  for (Int_t io = 0; io < (prim ? prim->GetSize() : 0); io++) {
    obj = prim->At(io);
    if (obj->InheritsFrom(TH1::Class()) && obj != prim->At(io + 1)) nobj++;
    if (obj->InheritsFrom(THStack::Class()) && obj != prim->At(io + 1)) nobj++;
    if (nobj == 1) hFirst = (TH1*) obj;
  }

  /// add or get legend
  TLegend* leg = 0;
  if ((optLeg && !nobj)) {
    leg = new TLegend(0. + gPad->GetLeftMargin() + gStyle->GetTickLength("Y"),
                      0. + gPad->GetBottomMargin() + gStyle->GetTickLength("X"),
                      1. - gPad->GetRightMargin() + gStyle->GetTickLength("Y"),
                      1. - gPad->GetTopMargin() + gStyle->GetTickLength("X"),
                      GetName(),
                      "nbNDC");
    if (optTask && !optCutStep) leg->SetHeader("");
  } else if (nobj) {
    leg = (TLegend*) prim->FindObject("TPave");
    // leg->SetX1(0. + gPad->GetLeftMargin()  + gStyle->GetTickLength("Y"));
    // leg->SetY1(0. + gPad->GetBottomMargin()+ gStyle->GetTickLength("X"));
    // leg->SetX2(1. - gPad->GetRightMargin() + gStyle->GetTickLength("Y"));
    // leg->SetY2(1. - gPad->GetTopMargin()   + gStyle->GetTickLength("X"));
    // leg->SetOption("nbNDC");
  }

  Info("DrawSame", "Basics: nobj: %d \t leg: %p", nobj, leg);

  /// logaritmic axes
  if (optString.Contains("logx")) gPad->SetLogx();
  if (optString.Contains("logy")) gPad->SetLogy();
  if (optString.Contains("logz")) gPad->SetLogz();
  optString.ReplaceAll("logx", "");
  optString.ReplaceAll("logy", "");
  optString.ReplaceAll("logz", "");

  /// meta data
  Int_t events = 1;
  if (fMetaData && optEvt) fMetaData->GetMeta("events", &events);

  Int_t i = nobj;
  if (optTask && nobj) i = nobj;
  TListIter next(&fHistoList, (optBack ? kIterBackward : kIterForward));
  //TIter next(&fHistoList);
  THashList* classTable = 0;
  //  TH1 *hFirst=0x0;
  /// iterate over all histogram classes (events,pairs,tracks,hits)
  while ((classTable = (THashList*) next())) {
    TString histClass = classTable->GetName();

    Int_t ndel = histClass.CountChar('_');
    Info("DrawSame",
         "Search for hist: '%s' class-denom: '%s' select: '%s' \t ndel: %d \t "
         "for class: '%s'",
         histName.Data(),
         histClassDenom.Data(),
         select.Data(),
         ndel,
         histClass.Data());

    /// check selections done via MC options 'onlyMC', 'noMC', 'noMCtrue', 'eff'
    if ((optNoMC && ndel > 0) || (optEff && ndel < 1)
        || (optNoMCtrue && histClass.Contains("_MCtruth"))
        || (optOnlyMC && ndel < 1) || (optOnlyMCtrue && ndel < 2))
      continue;

    /// histclass selections done via option 'sel' and argument 'histClassDenom' -> into array selections
    if (optSel && selections->GetEntriesFast()) {
      Bool_t pass = kFALSE;
      for (Int_t is = 0; is < selections->GetEntriesFast(); is++) {
        TString raw  = ((TObjString*) selections->At(is))->GetString();
        TString srch = raw;
        srch.ReplaceAll("!", "");
        Bool_t optExclSel = !(srch.EqualTo(raw));  // exclude or not
        /// decision
        if (!(!histClass.Contains(srch, TString::kIgnoreCase)) ^ (optExclSel))
          pass = kTRUE;
        /// exact string found - direct decision (ignore other selections)
        if (histClass.EqualTo(srch, TString::kIgnoreCase)) {
          pass =
            !(!histClass.EqualTo(srch, TString::kIgnoreCase)) ^ (optExclSel);
          break;
        }
      }
      if (!pass) continue;
    }


    /// find the histogram 'histName' in the class table
    /// or the corressponding MC histogram
    TH1* h = (TH1*) classTable->FindObject(histName.Data());
    if (!h && !optNoMC && !optNoMCtrue) {
      /// TODO: improve for tprofiles, formulas and more dimensional histos
      TString histdenomMC = histName + "MC";
      h                   = (TH1*) classTable->FindObject(histdenomMC.Data());
    }
    if (!h) continue;
    if (h->GetEntries() < 1.) continue;

    /// get histClassDenom for efficiency caluclation, e.g. the MCtruth (denominator)
    if (optEff && !histClass.Contains("_MCtruth"))
      histClassDenom = histClass + "_MCtruth";
    Info("DrawSame",
         " Hist found in histClass '%s' (search for denom '%s') ",
         histClass.Data(),
         histClassDenom.Data());

    /// check if 'ratio' or 'eff' should be build
    if ((optEff || optRatio) /*&& !optTask*/
        && (histClass.EqualTo(histClassDenom)
            || !fHistoList.FindObject(histClassDenom.Data())))
      continue;  /// TODO: why  '!optTask' was needed?
    else if (!histClassDenom.IsNull())
      Info("DrawSame", " Denom histClass '%s' found ", histClassDenom.Data());

    /// set first histogram
    if (i == 0 && !hFirst) hFirst = h;

    /// print normalisation option
    if (optRbn || optRbnStat)
      Info("DrawSame",
           " Rebin by %d, to <%.1f%% stat. uncertainty per bin",
           (optRbn ? rbn : 0),
           (optRbnStat ? stat * 100 : 0));
    if (optNormY || optNorm || optEvt)
      Info("DrawSame",
           " Normalize in y-axis,2D's only(%d), by int.(%d), by #events(%d)",
           optNormY,
           optNorm,
           optEvt);
    if (optSclMax) Info("DrawSame", " Scale to maximum(%d)", optSclMax);
    if (optCum)
      Info("DrawSame",
           " Cumulate sum of bins along x-axis, 1D's left-to-right(%d), "
           "right-to-left(%d)",
           !optCumR,
           optCumR);

    /// rebin, normalize, cumulate and scale spectra according to options 'rebinX','rebinStat','norm','normY','cum','cumR','events','sclMax'
    h->Sumw2();
    if (optRbn && h->InheritsFrom(TH2::Class()))
      h = ((TH2*) h)->RebinX(rbn, h->GetName());
    else if (optRbn)
      h->Rebin(rbn);
    if (optNormY && h->GetDimension() == 2 && !(h->GetSumOfWeights() == 0)
        && !optCum)
      PairAnalysisHelper::NormalizeSlicesY((TH2*) h);
    if (optRbnStat && h->GetDimension() == 1) {
      /// rebin until stat. uncertainty is lower than 'stat'
      limits = PairAnalysisHelper::MakeStatBinLimits(h, stat);
      h = h->Rebin(limits->GetSize() - 1, h->GetName(), limits->GetArray());
      h->Scale(1., "width");
      //      delete limits;
    }
    if (optCum) PairAnalysisHelper::Cumulate(h, optCumR, optNorm);
    if (optSmooth) h->Smooth(smth);

    /// get default histogram titles
    TString ytitle = h->GetYaxis()->GetTitle();
    TString ztitle = h->GetZaxis()->GetTitle();
    if (ytitle.Contains("{evt}")) optEvt = kFALSE;

    if (optNorm && !(h->GetSumOfWeights() == 0) && !optCum)
      h = h->DrawNormalized(i > 0 ? (optString + "same").Data()
                                  : optString.Data());
    if (optEvt) h->Scale(1. / events);
    if (optSclMax) h->Scale(1. / h->GetBinContent(h->GetMaximumBin()));

    /// modify titles according to options
    switch (h->GetDimension()) {
      case 1:
        if (optEvt) h->SetYTitle((ytitle + "/N_{evt}").Data());
        if (optNorm) h->SetYTitle((ytitle.Append(" (normalized)")).Data());
        if (optCum) h->SetYTitle((ytitle.Prepend("cumulated ")).Data());
        if (optRatio) h->SetYTitle("ratio");
        if (optDiv) h->SetYTitle("ratio");
        if (optEff) h->SetYTitle("acceptance #times efficiency");
        if (optSclMax) h->SetYTitle((ytitle + "/N_{max}").Data());
        break;
      case 2:
        if (optEvt) h->SetZTitle((ztitle + "/N_{evt}").Data());
        //	if(optNormY)  h->SetYTitle( (ytitle.Append(" (normalized)")).Data() );
        if (optNorm) h->SetZTitle((ztitle.Prepend("normalized ")).Data());
        if (optRatio) h->SetZTitle("ratio");
        if (optDiv) h->SetZTitle("ratio");
        if (optEff) h->SetZTitle("acceptance #times efficiency");
        if (optSclMax) h->SetZTitle((ztitle + "/N_{max}").Data());
        break;
    }

    /// Calculate ratios and Draw histograms
    if ((optEff || optRatio) && !optNorm && !optEvt && !optTask) {
      Info("DrawSame",
           " Calculate '%s' w/o normalisation and within the same task",
           (optEff ? "efficiency" : "ratio"));
      //	TString    clMC     = histClass+"_MCtruth";
      THashList* clDenom =
        (THashList*) fHistoList.FindObject(histClassDenom.Data());
      TH1* hMC =
        (TH1*)
          h->Clone();  // needed to preserve the labeling of non-mc histogram
      TString histdenomMC = UserHistogram(histClassDenom.Data(), hMC);
      TH1* hdenom         = (TH1*) clDenom->FindObject(histdenomMC.Data());
      if (!hdenom) {
        Error("DrawSame", "Denominator object not found");
        continue;
      }
      Info("DrawSame",
           " Divide %s(#=%.3e) by %s(#=%.3e)",
           h->GetName(),
           h->GetEntries(),
           hdenom->GetName(),
           hdenom->GetEntries());
      delete hMC;  //delete the surplus object
      // normalize and rebin only once
      hdenom->Sumw2();  //why is it crashing here
      if (optRbnStat && (optEff || !(i % 10))) {
        hdenom = hdenom->Rebin(
          limits->GetSize() - 1, hdenom->GetName(), limits->GetArray());
        hdenom->Scale(1., "width");
      }
      if (optRbn && (optEff || !(i % 10))) hdenom->RebinX(rbn);
      if (optEvt && (optEff || !(i % 10))) hdenom->Scale(1. / events);
      if (!hdenom || !h->Divide(hdenom)) {
        Warning("DrawSame(eff/ratio)", "Division failed!!!!");
        continue;
      }
    } else if (optTask && (optDiv || optEff || optRatio)) {
      Info("DrawSame",
           " Calculate '%s' using different tasks",
           (optEff ? "efficiency" : (optRatio ? "ratio" : "divison")));
      // denominators
      TH1* hdenom = 0x0;
      TH1* htden  = 0x0;
      if (optEff || optRatio) {
        THashList* clDenom =
          (THashList*) fHistoList.FindObject(histClassDenom.Data());
        TH1* hMC =
          (TH1*)
            h->Clone();  // needed to preserve the labeling of non-mc histogram
        TString histdenomMC = UserHistogram(histClassDenom.Data(), hMC);
        //delete the surplus object
        delete hMC;

        if (clDenom) {
          hdenom = (TH1*) clDenom->FindObject(histdenomMC.Data());
        }

        if (listDenom) {
          THashList* clTaskDen =
            (THashList*) listDenom->FindObject(histClassDenom.Data());
          if (clTaskDen) {
            //	  htden=(TH1*)clTaskDen->FindObject(hdenom->GetName());
            htden = (TH1*) clTaskDen->FindObject(histdenomMC.Data());
            Info("DrawSame",
                 "calculate eff/ratio using task-denom: '%s' class-denom: '%s' "
                 "hist-denom: '%s'",
                 listDenom->GetName(),
                 histClassDenom.Data(),
                 histdenomMC.Data());
            // keep only one of them, otherwise you might divide the same objects twice
            if (htden) hdenom = 0x0;
          }
        }

      }  // optEff || optRatio


      // task ratio
      TH1* htnom = 0x0;
      if (optDiv && !optEff) {
        Info("DrawSame",
             " Search for '%s' in task '%s'",
             histClass.Data(),
             listDenom->GetName());
        THashList* clTaskNom =
          (THashList*) listDenom->FindObject(histClass.Data());
        if (!clTaskNom) continue;
        htnom = (TH1*) clTaskNom->FindObject(histName.Data());
        if (!htnom) continue;
      }

      if (hdenom) hdenom->Sumw2();
      if (htden) htden->Sumw2();
      if (htnom) htnom->Sumw2();

      /// check consistent bins and rebin if needed
      Int_t nbinsh  = (h ? h->GetNbinsX() : -1);
      Int_t nbinsd  = (hdenom ? hdenom->GetNbinsX() : -2);
      Int_t nbinstd = (htden ? htden->GetNbinsX() : -3);
      Int_t nbinstn = (htnom ? htnom->GetNbinsX() : -4);

      // normalize and rebin only once
      if (optRbn) {
        if (hdenom && nbinsd > nbinsh) hdenom->RebinX(rbn);
        if (htden && nbinstd > nbinsh) htden->RebinX(rbn);
        if (htnom && nbinstn > nbinsh) htnom->RebinX(rbn);
      }
      if (optRbnStat) {
        if (hdenom && nbinsd > nbinsh) {
          hdenom = hdenom->Rebin(
            limits->GetSize() - 1, hdenom->GetName(), limits->GetArray());
          hdenom->Scale(1., "width");
        }
        if (htden && nbinstd > nbinsh) {
          htden = htden->Rebin(
            limits->GetSize() - 1, htden->GetName(), limits->GetArray());
          htden->Scale(1., "width");
        }
        if (htnom && nbinstn > nbinsh) {
          htnom = htnom->Rebin(
            limits->GetSize() - 1, htnom->GetName(), limits->GetArray());
          htnom->Scale(1., "width");
        }
      }

      if (optEvt && !i) {
        if (hdenom) hdenom->Scale(1. / events);
        if (htden) htden->Scale(1. / events);
        if (htnom) htnom->Scale(1. / events);
      }

      Info("DrawSame",
           "  Use nominator (%p,#=%.3e) and denominator 'same task & different "
           "class'(%p,#=%.3e), 'certain task & different class'(%p,#=%.3e), "
           "'certain task & same class'(%p,#=%.3e)",
           h,
           h->GetEntries(),
           hdenom,
           (hdenom ? hdenom->GetEntries() : 0),
           htden,
           (htden ? htden->GetEntries() : 0),
           htnom,
           (htnom ? htnom->GetEntries() : 0));
      // Printf("h %p (bins%d) \t hdenom %p (bins%d) \t htdenom %p (bins%d) \t htnom %p (bins%d)",
      //        h,h->GetNbinsX(),hdenom,(hdenom?hdenom->GetNbinsX():0),
      //        htden,(htden?htden->GetNbinsX():0),htnom,(htnom?htnom->GetNbinsX():0));

      // standard ratio
      if (hdenom && !h->Divide(hdenom)) {
        Warning("DrawSame(eff/ratio)", "h & denom division failed!!!!");
        continue;
      } else if (htden && htnom && !i && !htnom->Divide(htden)) {
        Warning("DrawSame(eff/ratio)",
                "task-nom/task-denom division failed!!!!");
        continue;
      } else if (optDiv && htnom && !h->Divide(htnom)) {
        Warning("DrawSame(eff/ratio)", "h & task-nom division failed!!!!");
        continue;
      } else if (htden && !h->Divide(htden)) {
        Warning("DrawSame(eff/ratio)", "h & task-denom division failed!!!!");
        continue;
      }
    }

    /// scale by 1./bin width, helpfull for arbitrary bin sizes
    if (optWdth && !optRbnStat) h->Scale(1., "width");


    /// flip bin contents of histograms to 1./content
    if (optOneOver) {
      Info("DrawSame", " Scale by 1/content");
      TH1* hOne = (TH1*) h->Clone("one");
      hOne->Reset("ICSE");
      for (Int_t ib = 0; ib < (h->GetNbinsX() + 2) * (h->GetNbinsY() + 2)
                                * (h->GetNbinsZ() + 2);
           ib++)
        hOne->SetBinContent(ib, 1.);
      if (hOne->Divide(h)) h = hOne;
    }

    /// set special geant labels
    if (optGeant) {
      Info("DrawSame", " Set GEANT bin labels");
      PairAnalysisHelper::SetGEANTBinLabels(h);
    }

    /// set special pdg labels
    if (optPdg || optPdgClean) {
      Info("DrawSame", " Set PDG bin labels");
      PairAnalysisHelper::SetPDGBinLabels(h, optPdgClean);
    }

    /// style histograms if not done before
    /// take into account reset style option 'RstSty'
    if (h->GetLineColor() == kBlack
        && !optString.Contains("col")) {  // avoid color updates
      h->UseCurrentStyle();
      PairAnalysisStyler::Style(h, i - (optRstSty ? nobj : 0));
    }
    /// some default styles for certain options
    if (optString.Contains("scat")) h->SetMarkerStyle(kDot);
    if (optString.Contains("e")) h->SetLineStyle(kSolid);
    //    if(optString.Contains("text")) { h->SetLineColor(1); h->SetMarkerColor(1); }

    /// set histogram title to current histClass
    //      h->SetName(histClass.Data());
    h->SetTitle(histClass.Data());

    /// add histograms to returned array if option 'goff' is active, otherwise
    /// draw the histogram
    if (optGoff) {
      if (optTask) h->SetTitle(Form("%s %s", GetName(), h->GetTitle()));
      arr->Add(h);
    } else if (optStack) {
      if (!hs)
        hs = new THStack(
          "hs",
          Form(";%s;%s", h->GetXaxis()->GetTitle(), h->GetYaxis()->GetTitle()));
      hs->Add(h);
    } else {
      optString.ReplaceAll(" ", "");
      Info("DrawSame", " Draw object with options: '%s'", optString.Data());
      //      h->Draw(i>0?(optString+"same").Data():optString.Data());
      if (!optSlicesY) {
        h->Draw(h != hFirst ? (optString + "same").Data() : optString.Data());
      } else if (h->GetDimension() == 2) {
        // loop over all projections
        for (Int_t bin = 1; bin < h->GetNbinsX(); bin++) {
          TH1* hp = ((TH2*) h)->ProjectionY(
            Form("%s_%d", h->GetName(), bin), bin, bin, "e");
          if (!hp) continue;
          Long64_t nentries = Long64_t(hp->GetEntries());
          if (nentries == 0) {
            delete hp;
            continue;
          }
          PairAnalysisStyler::Style(hp, i + (bin - 1) - (optRstSty ? nobj : 0));
          if (optRbn) hp->Rebin(rbn);
          if (optRbnStat) {
            /// rebin until stat. uncertainty is lower than 'stat'
            limits = PairAnalysisHelper::MakeStatBinLimits(hp, stat);
            hp     = hp->Rebin(
              limits->GetSize() - 1, hp->GetName(), limits->GetArray());
            hp->Scale(1., "width");
          }
          if (optCum) PairAnalysisHelper::Cumulate(hp, optCumR, optNorm);
          if (optSmooth) hp->Smooth(smth);
          hp->Draw(hFirst ? (optString + "same").Data() : optString.Data());
        }
      }
    }


    /// protection e.g. normalization not possible TProfile
    if (h && h->GetEntries() > 0.) {

      TString ratioName = histClassDenom;
      TString divName   = (listDenom ? listDenom->GetName() : "");
      if (optEff) divName += (listDenom ? "(MC)" : "");
      // adapt legend name
      // remove reserved words
      TObjArray* reservedWords = fReservedWords->Tokenize(":;");
      for (Int_t ir = 0; ir < reservedWords->GetEntriesFast(); ir++) {
        //	  printf("histClass %s \t search for %s \n",histClass.Data(),((TObjString*)reservedWords->At(ir))->GetString().Data());
        histClass.ReplaceAll(((TObjString*) reservedWords->At(ir))->GetString(),
                             "");
        ratioName.ReplaceAll(((TObjString*) reservedWords->At(ir))->GetString(),
                             "");
        divName.ReplaceAll(((TObjString*) reservedWords->At(ir))->GetString(),
                           "");
      }
      // change default signal names to titles
      for (Int_t isig = 0; isig < PairAnalysisSignalMC::kNSignals; isig++) {
        TString src = PairAnalysisSignalMC::fgkSignals[isig][0];
        TString rpl = PairAnalysisSignalMC::fgkSignals[isig][1];
        // avoid mc signal in header AND leg-entry
        if (leg
            && (rpl.EqualTo(leg->GetHeader()) || src.EqualTo(leg->GetHeader())))
          rpl = "";
        histClass.ReplaceAll(src, rpl);
        ratioName.ReplaceAll(src, rpl);
        divName.ReplaceAll(src, rpl);
      }
      //	printf("histClass %s \n",histClass.Data());

      // change MCtruth to MC
      for (Int_t isig = 0; isig < PairAnalysisSignalMC::kNSignals; isig++) {
        histClass.ReplaceAll("MCtruth", "MC");
        ratioName.ReplaceAll("MCtruth", "MC");
        divName.ReplaceAll("MCtruth", "MC");
      }
      // remove pairing name if it is a MC
      for (Int_t iptype = 0; iptype < PairAnalysis::kPairTypes; iptype++) {
        if (ndel > 0)
          histClass.ReplaceAll(PairAnalysis::PairClassName(iptype), "");
        if (ratioName.CountChar('_') > 0)
          ratioName.ReplaceAll(PairAnalysis::PairClassName(iptype), "");
        if (divName.CountChar('_') > 0)
          divName.ReplaceAll(PairAnalysis::PairClassName(iptype), "");
      }
      // save Dalitz and Short underscore
      histClass.ReplaceAll("_{Dalitz}", "#{Dalitz}");
      ratioName.ReplaceAll("_{Dalitz}", "#{Dalitz}");
      divName.ReplaceAll("_{Dalitz}", "#{Dalitz}");
      histClass.ReplaceAll("_{S}", "#{S}");
      ratioName.ReplaceAll("_{S}", "#{S}");
      divName.ReplaceAll("_{S}", "#{S}");
      // remove delimiters
      histClass.ReplaceAll("_", " ");
      ratioName.ReplaceAll("_", " ");
      divName.ReplaceAll("_", " ");
      histClass.ReplaceAll(".", "");
      ratioName.ReplaceAll(".", "");
      divName.ReplaceAll(".", "");
      // get Dalitz and Short back
      histClass.ReplaceAll("#{Dalitz}", "_{Dalitz}");
      ratioName.ReplaceAll("#{Dalitz}", "_{Dalitz}");
      divName.ReplaceAll("#{Dalitz}", "_{Dalitz}");
      histClass.ReplaceAll("#{S}", "_{S}");
      ratioName.ReplaceAll("#{S}", "_{S}");
      divName.ReplaceAll("#{S}", "_{S}");
      // remove trailing and leading spaces
      histClass.Remove(TString::kBoth, ' ');
      ratioName.Remove(TString::kBoth, ' ');
      divName.Remove(TString::kBoth, ' ');

      //build final ratio name
      if (optRatio) histClass += "/" + ratioName;

      // delete the surplus
      delete reservedWords;

      // modify legend option
      TString legOpt = optString + "L";
      legOpt.ReplaceAll("hist", "");
      legOpt.ReplaceAll("scat", "");
      if (legOpt.Contains("col")) legOpt = "";
      legOpt.ReplaceAll("z", "");
      legOpt.ReplaceAll("e", "");
      if (optTask) histClass.Prepend(Form("%s ", GetName()));
      if ((optTask && optCutStep && i) || (optStack && (i - nobj)))
        histClass.Prepend("+");
      if (optDiv && !optOneOver)
        histClass.ReplaceAll(GetName(),
                             Form("%s/%s", GetName(), divName.Data()));
      if (optDiv && optOneOver) histClass.Prepend(Form("%s/", divName.Data()));
      if (optDet) {
        for (ECbmModuleId idet = ECbmModuleId::kRef;
             idet < ECbmModuleId::kNofSystems;
             ++idet) {
          if (histName.Contains(PairAnalysisHelper::GetDetName(idet)))
            histClass = PairAnalysisHelper::GetDetName(idet);
        }
      }
      //	else if(nobj)     histClass="";
      if (optMeanX) histClass += Form(" #LTx#GT=%.1e", h->GetMean());
      if (optRmsX) histClass += Form(" RMS(x)=%.1e", h->GetRMS());
      if (optMeanY) histClass += Form(" #LTy#GT=%.2e", h->GetMean(2));
      if (optRmsY) histClass += Form(" RMS(y)=%.2e", h->GetRMS(2));
      histClass.ReplaceAll("e+00", "");
      // no entry for colored plots
      if (optLeg && leg /*&& !legOpt.Contains("col")*/)
        leg->AddEntry(h, histClass.Data(), legOpt.Data());
      //      if (leg) leg->AddEntry(h,classTable->GetName(),(optString+"L").Data());
      ++i;

    } else if (nobj && leg)
      leg->AddEntry(hFirst, "", "");

    //++i;


    //    }
    // cleanup
    if (limits) delete limits;
  }  //while loop histclass

  /// draw stack histogram
  if (optStack) {
    optString.ReplaceAll(" ", "");
    Info(
      "DrawSame", " Draw stacked object with options: '%s'", optString.Data());
    hs->Draw(nobj > 0 ? (optString + "same").Data() : optString.Data());
  }

  /// draw legend only once
  /// set legend coordinates, margins, fillstyle, fontsize
  if (leg) {
    PairAnalysisStyler::SetLegendAttributes(leg, optLegFull);
    if (!nobj) leg->Draw();
  }

  /// automatic axis minimum and maximum
  if (gPad) {
    Double_t max = -1e10;
    Double_t min = +1e10;
    TListIter nextObj(gPad->GetListOfPrimitives(), kIterBackward);
    //  TObject *obj;
    while ((obj = nextObj())) {
      if (obj->InheritsFrom(TH1::Class())) {
        TH1* h1 = static_cast<TH1*>(obj);

        max = TMath::Max(
          max, PairAnalysisHelper::GetContentMaximum(h1));  //h1->GetMaximum();
        Double_t tmpmax = max * (gPad->GetLogy() ? 5. : 1.1);
        if (optEff) tmpmax = 1.1;
        h1->SetMaximum(tmpmax);

        Double_t objmin = PairAnalysisHelper::GetContentMinimum(h1);
        if (gPad->GetLogy() && objmin < 0.) objmin = 0.5;
        min             = TMath::Min(min, objmin);
        Double_t tmpmin = min * (min < 0. ? 1.1 : 0.9);
        //      if(optEff) tmpmin=0.;
        h1->SetMinimum(tmpmin);

        // Printf("after %s max%f \t min%f \t for logy %.3e >? %.3e",
        // 	     h1->GetTitle(),tmpmax,tmpmin, tmpmax/(tmpmin>0.?tmpmin:1.),TMath::Power(10.,TGaxis::GetMaxDigits()));

        //      Printf("max%f \t min%f",h1->GetMaximum(),PairAnalysisHelper::GetContentMinimum(h1));
        // max=TMath::Max(max,PairAnalysisHelper::GetContentMaximum(h1));
        // min=TMath::Min(min,PairAnalysisHelper::GetContentMinimum(h1));//hobj->GetBinContent(hobj->GetMinimumBin()));
        // Printf("max%f \t min%f",max,min);
        // if(!optEff) h1->SetMaximum(max*(gPad->GetLogy()?5.:1.1));
        // else        h1->SetMaximum(1.1);
        // if(!optEff) h1->SetMinimum( min*(min<0.?1.1:0.9) ); //TODO: doesnt work, why?? Negative values?

        /// automatically set log option labels
        if (gPad->GetLogy()
            && (tmpmax / (tmpmin > 0. ? tmpmin : 1.)
                  > TMath::Power(10., TGaxis::GetMaxDigits())
                || tmpmin < TMath::Power(10., -TGaxis::GetMaxDigits())
                || tmpmin > TMath::Power(10., +TGaxis::GetMaxDigits()))) {
          //      if(gPad->GetLogy() && tmpmax/(tmpmin>0.?tmpmin:1.) > TMath::Power(10.,TGaxis::GetMaxDigits())) {
          h1->GetYaxis()->SetMoreLogLabels(kFALSE);
          h1->GetYaxis()->SetNoExponent(kFALSE);
        }
        Double_t tmpXmin = h1->GetXaxis()->GetXmin();
        if (gPad->GetLogx()
            && h1->GetXaxis()->GetXmax()
                   / (TMath::Abs(tmpXmin) < 1.e-10 ? 1. : tmpXmin)
                 > TMath::Power(10., TGaxis::GetMaxDigits())) {
          //	printf("Xaxis: max%f , min%f \t ratio %.3e >? %.3e \n",h1->GetXaxis()->GetXmax(),(TMath::Abs(tmpXmin)<1.e-10?1.:tmpXmin),
          //              h1->GetXaxis()->GetXmax()/(TMath::Abs(tmpXmin)<1.e-10?1.:tmpXmin),TMath::Power(10.,TGaxis::GetMaxDigits()));
          h1->GetXaxis()->SetMoreLogLabels(kFALSE);
          h1->GetXaxis()->SetNoExponent(kFALSE);
        }
      }
    }
    /// draw only once the default metadata if option 'meta' is active
    if (!nobj && optMeta && fMetaData && !gPad->GetPrimitive("meta")) {
      fMetaData->DrawSame("");
    }

    /// force legend to be drawn always on top, remove multiple versions of it
    /// they show up when one uses the 'task' draw option
    if (!optTask && 0) {
      if (leg) leg->DrawClone();
      nextObj.Reset();
      Int_t ileg = 0;
      while ((obj = nextObj())) {
        if (obj->InheritsFrom(TLegend::Class())) {
          if (ileg > 0) delete obj;
          ileg++;
        }
      }
    }
  }

  /// styling
  /// NOTE: this draws a copy of the first histogram
  //if(gPad && !optGoff) gPad->RedrawAxis();

  /// remove canvas if graphics are switched off ('goff')
  //  if(optGoff) { c->Close(); delete c; }

  /// clean up
  if (selections) delete selections;

  return arr;
}

//_____________________________________________________________________________
void PairAnalysisHistos::SetReservedWords(const char* words) {
  //
  // set reserved words
  //

  (*fReservedWords) = words;
}

//_____________________________________________________________________________
void PairAnalysisHistos::StoreVariables(TObject* obj, UInt_t valType[20]) {
  //
  //
  //
  if (!obj) return;
  if (obj->InheritsFrom(TH1::Class()))
    StoreVariables(static_cast<TH1*>(obj), valType);
  else if (obj->InheritsFrom(THnBase::Class()))
    StoreVariables(static_cast<THnBase*>(obj), valType);

  return;
}


//_____________________________________________________________________________
void PairAnalysisHistos::StoreVariables(TH1* obj, UInt_t valType[20]) {
  //
  // store variables in the axis (special for TProfile3D)
  //

  Int_t dim = obj->GetDimension();

  // dimension correction for profiles
  if (obj->IsA() == TProfile::Class() || obj->IsA() == TProfile2D::Class()
      || obj->IsA() == TProfile3D::Class()) {
    dim++;
  }

  if (dim >= 1) { obj->GetXaxis()->SetUniqueID(valType[0]); }
  if (dim >= 2) { obj->GetYaxis()->SetUniqueID(valType[1]); }
  if (dim >= 3) { obj->GetZaxis()->SetUniqueID(valType[2]); }
  // Tprofile3D variable
  if (dim >= 4) { obj->SetUniqueID(valType[3]); }

  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::StoreVariables(THnBase* obj, UInt_t valType[20]) {
  //
  // store variables in the axis
  //

  obj->Sumw2();

  // check for formulas and skip the rest if needed
  TList* list = obj->GetListOfFunctions();
  if (obj->IsA() == PairAnalysisHn::Class())
    list = (static_cast<PairAnalysisHn*>(obj))->GetListOfFunctions();
  if (list && list->Last()) return;

  Int_t dim = obj->GetNdimensions();

  for (Int_t it = 0; it < dim; it++) {
    obj->GetAxis(it)->SetUniqueID(valType[it]);
    obj->GetAxis(it)->SetName(
      Form("%s", PairAnalysisVarManager::GetValueName(valType[it])));
    obj->GetAxis(it)->SetTitle(
      Form("%s %s",
           PairAnalysisVarManager::GetValueLabel(valType[it]),
           PairAnalysisVarManager::GetValueUnit(valType[it])));
  }
  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::FillValues(TObject* obj, const Double_t* values) {
  //
  //
  //
  if (!obj) return;
  if (obj->InheritsFrom(TH1::Class()))
    FillValues(static_cast<TH1*>(obj), values);
  else if (obj->InheritsFrom(THnBase::Class()))
    FillValues(static_cast<THnBase*>(obj), values);

  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::FillValues(TH1* obj, const Double_t* values) {
  //
  // fill values for TH1 inherted classes
  //

  Int_t dim   = obj->GetDimension();
  Bool_t bprf = kFALSE;
  //  UInt_t nValues = (UInt_t) PairAnalysisVarManager::kNMaxValues;
  UInt_t valueTypes = obj->GetUniqueID();
  if (valueTypes == (UInt_t) PairAnalysisHistos::kNoAutoFill) return;
  Bool_t weight = (valueTypes != kNoWeights);

  // check if tprofile
  if (obj->IsA() == TProfile::Class() || obj->IsA() == TProfile2D::Class()
      || obj->IsA() == TProfile3D::Class())
    bprf = kTRUE;

  // TO BEAUTIFY: switch off manually weighting of profile3Ds
  if (obj->IsA() == TProfile3D::Class()) weight = kFALSE;

  // check for formulas
  TList* list     = obj->GetListOfFunctions();
  TFormula* xform = dynamic_cast<TFormula*>(list->FindObject("xFormula"));
  TFormula* yform = dynamic_cast<TFormula*>(list->FindObject("yFormula"));
  TFormula* zform = dynamic_cast<TFormula*>(list->FindObject("zFormula"));
  TFormula* pform = dynamic_cast<TFormula*>(list->FindObject("pFormula"));
  TFormula* wform = dynamic_cast<TFormula*>(list->FindObject("wFormula"));
  //  Bool_t bform = (xform || yform || zform /*|| wform*/);

  // get variables from axis unique IDs
  UInt_t value1 = obj->GetXaxis()->GetUniqueID();
  UInt_t value2 = obj->GetYaxis()->GetUniqueID();
  UInt_t value3 = obj->GetZaxis()->GetUniqueID();
  UInt_t value4 =
    obj->GetUniqueID();  // get weighting/profile var stored in the unique ID

  Double_t fvals[4] = {
    values[value1], values[value2], values[value3], values[value4]};

  // use formulas to update fill values
  if (xform) fvals[0] = PairAnalysisHelper::EvalFormula(xform, values);
  if (yform) fvals[1] = PairAnalysisHelper::EvalFormula(yform, values);
  if (zform) fvals[2] = PairAnalysisHelper::EvalFormula(zform, values);
  if (wform) fvals[3] = PairAnalysisHelper::EvalFormula(wform, values);
  if (pform)
    fvals[3] = PairAnalysisHelper::EvalFormula(
      pform, values);  // weighting overwriting for Profile3D

  /*
  // ask for inclusive trigger map variables
  if(value1!=PairAnalysisVarManager::kTriggerInclONL && value1!=PairAnalysisVarManager::kTriggerInclOFF &&
     value2!=PairAnalysisVarManager::kTriggerInclONL && value2!=PairAnalysisVarManager::kTriggerInclOFF &&
     value3!=PairAnalysisVarManager::kTriggerInclONL && value3!=PairAnalysisVarManager::kTriggerInclOFF &&
     value4!=PairAnalysisVarManager::kTriggerInclONL && value4!=PairAnalysisVarManager::kTriggerInclOFF ) {
    // no trigger map variable selected
    */
  switch (dim) {
    case 1:
      if (!bprf && !weight)
        obj->Fill(fvals[0]);  // histograms
      else if (!bprf && weight)
        obj->Fill(fvals[0], fvals[3]);  // weighted histograms
      else if (bprf && !weight)
        ((TProfile*) obj)->Fill(fvals[0], fvals[1]);  // profiles
      else
        ((TProfile*) obj)
          ->Fill(fvals[0], fvals[1], fvals[3]);  // weighted profiles
      break;
    case 2:
      if (!bprf && !weight)
        obj->Fill(fvals[0], fvals[1]);  // histograms
      else if (!bprf && weight)
        ((TH2*) obj)
          ->Fill(fvals[0], fvals[1], fvals[3]);  // weighted histograms
      else if (bprf && !weight)
        ((TProfile2D*) obj)->Fill(fvals[0], fvals[1], fvals[2]);  // profiles
      else
        ((TProfile2D*) obj)
          ->Fill(fvals[0], fvals[1], fvals[2], fvals[3]);  // weighted profiles
      break;
    case 3:
      if (!bprf && !weight)
        ((TH3*) obj)->Fill(fvals[0], fvals[1], fvals[2]);  // histograms
      else if (!bprf && weight)
        ((TH3*) obj)
          ->Fill(
            fvals[0], fvals[1], fvals[2], fvals[3]);  // weighted histograms
      else if (bprf && !weight)
        ((TProfile3D*) obj)
          ->Fill(fvals[0], fvals[1], fvals[2], fvals[3]);  // profiles
      else
        Printf(" WARNING: weighting NOT yet possible for TProfile3Ds !");
      break;
  }
  /*  }
  else {
    // fill inclusive trigger map variables
    if(weight) return;
    switch ( dim ) {
    case 1:
      for(Int_t i=0; i<30; i++) { if(TESTBIT((UInt_t)fvals[0],i)) obj->Fill(i); }
      break;
    case 2:
      if((value1==PairAnalysisVarManager::kTriggerInclOFF && value2==PairAnalysisVarManager::kTriggerInclONL) ||
	 (value1==PairAnalysisVarManager::kTriggerInclONL && value2==PairAnalysisVarManager::kTriggerInclOFF) ) {
	for(Int_t i=0; i<30; i++) {
	  if((UInt_t)fvals[0]==BIT(i)) {
	    for(Int_t i2=0; i2<30; i2++) {
	      if((UInt_t)fvals[1]==BIT(i2)) {
		obj->Fill(i, i2);
	      } // bit fired
	    } //loop 2
	  }//bit fired
	} // loop 1
      }
      else if(value1==PairAnalysisVarManager::kTriggerInclONL || value1==PairAnalysisVarManager::kTriggerInclOFF) {
	for(Int_t i=0; i<30; i++) { if(TESTBIT((UInt_t)fvals[0],i)) obj->Fill(i, fvals[1]); }
      }
      else if(value2==PairAnalysisVarManager::kTriggerInclONL || value2==PairAnalysisVarManager::kTriggerInclOFF) {
	for(Int_t i=0; i<30; i++) { if(TESTBIT((UInt_t)fvals[1],i)) obj->Fill(fvals[0], i); }
      }
      else //makes no sense
	return;
      break;
    default: return;
    }

  } //end: trigger filling
  */

  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::FillValues(THnBase* obj, const Double_t* values) {
  //
  // fill values for THn inherted classes
  //

  // skip if manual filling
  UInt_t value4 = obj->GetUniqueID();  // weighting variable if any
  if (value4 == (UInt_t) PairAnalysisHistos::kNoAutoFill) return;

  // check for formulas and skip the rest if needed
  TList* list = obj->GetListOfFunctions();
  if (obj->IsA() == PairAnalysisHn::Class())
    list = (static_cast<PairAnalysisHn*>(obj))->GetListOfFunctions();
  Bool_t useFormulas = (list && list->Last());

  //  do weighting
  Bool_t weight = (value4 != kNoWeights);

  // fill array
  const Int_t dim = obj->GetNdimensions();
  Double_t fill[dim];

  // loop over all axes
  for (Int_t it = 0; it < dim; it++) {
    if (useFormulas) {
      TString formName = Form("axis%dFormula", it);
      TFormula* form   = dynamic_cast<TFormula*>(list->FindObject(formName));
      fill[it]         = PairAnalysisHelper::EvalFormula(form, values);
    } else {
      fill[it] = values[obj->GetAxis(it)->GetUniqueID()];
    }
  }

  // fill object
  if (!weight)
    obj->Fill(fill);
  else
    obj->Fill(fill, values[value4]);

  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::FillVarArray(TObject* obj, UInt_t* valType) {
  //
  // extract variables stored in the axis (special for TProfile3D)
  //


  if (!obj) return;

  if (obj->InheritsFrom(TH1::Class())) {
    valType[0] = ((TH1*) obj)->GetXaxis()->GetUniqueID();
    valType[1] = ((TH1*) obj)->GetYaxis()->GetUniqueID();
    valType[2] = ((TH1*) obj)->GetZaxis()->GetUniqueID();
    valType[3] =
      ((TH1*) obj)
        ->GetUniqueID();  // weighting(profile) var stored in unique ID
  } else if (obj->InheritsFrom(THnBase::Class())) {
    for (Int_t it = 0; it < ((THn*) obj)->GetNdimensions(); it++)
      valType[it] = ((THn*) obj)->GetAxis(it)->GetUniqueID();
  }
  valType[19] = obj->GetUniqueID();  //weights
  return;
}

//_____________________________________________________________________________
void PairAnalysisHistos::AdaptNameTitle(TH1* hist, const char* histClass) {

  //
  // adapt name and title of the histogram
  //

  Int_t dim            = hist->GetDimension();
  TString currentName  = "";  //hist->GetName();
  TString currentTitle = "";  //hist->GetTitle();
  TString hclass       = histClass;
  //get reserved class
  TObjArray* arr = hclass.Tokenize("_.");
  arr->SetOwner();
  hclass = ((TObjString*) arr->At(0))->GetString();
  delete arr;
  hclass.ToLower();

  Bool_t bname  = (currentName.IsNull());
  Bool_t btitle = (currentTitle.IsNull());
  Bool_t bprf   = kFALSE;
  if (hist->IsA() == TProfile::Class() || hist->IsA() == TProfile2D::Class()
      || hist->IsA() == TProfile3D::Class())
    bprf = kTRUE;

  // tprofile options
  Double_t pmin = 0., pmax = 0.;
  TString option = "", calcrange = "";
  Bool_t bStdOpt = kTRUE;
  if (bprf) {
    switch (dim) {
      case 3:
        option = ((TProfile3D*) hist)->GetErrorOption();
        pmin   = ((TProfile3D*) hist)->GetTmin();
        pmax   = ((TProfile3D*) hist)->GetTmax();
        break;
      case 2:
        option = ((TProfile2D*) hist)->GetErrorOption();
        pmin   = ((TProfile2D*) hist)->GetZmin();
        pmax   = ((TProfile2D*) hist)->GetZmax();
        break;
      case 1:
        option = ((TProfile*) hist)->GetErrorOption();
        pmin   = ((TProfile*) hist)->GetYmin();
        pmax   = ((TProfile*) hist)->GetYmax();
        break;
    }
    if (option.Contains("s", TString::kIgnoreCase)) bStdOpt = kFALSE;
    if (pmin != pmax)
      calcrange = Form("#cbar_{%+.*f}^{%+.*f}",
                       PairAnalysisHelper::GetPrecision(pmin),
                       pmin,
                       PairAnalysisHelper::GetPrecision(pmax),
                       pmax);
  }

  UInt_t varx   = hist->GetXaxis()->GetUniqueID();
  UInt_t vary   = hist->GetYaxis()->GetUniqueID();
  UInt_t varz   = hist->GetZaxis()->GetUniqueID();
  UInt_t varp   = hist->GetUniqueID();
  Bool_t weight = (varp != kNoWeights);
  if (bprf && dim == 3) weight = kFALSE;  // no weighting for profile3D

  // store titles in the axis
  if (btitle) {
    TString tit = "";
    /////// set NAMES
    hist->GetXaxis()->SetName(PairAnalysisVarManager::GetValueName(varx));
    hist->GetYaxis()->SetName(PairAnalysisVarManager::GetValueName(vary));
    hist->GetZaxis()->SetName(PairAnalysisVarManager::GetValueName(varz));
    // adapt according to formula
    TFormula* xform = dynamic_cast<TFormula*>(
      hist->GetListOfFunctions()->FindObject("xFormula"));
    TFormula* yform = dynamic_cast<TFormula*>(
      hist->GetListOfFunctions()->FindObject("yFormula"));
    TFormula* zform = dynamic_cast<TFormula*>(
      hist->GetListOfFunctions()->FindObject("zFormula"));
    TFormula* wform = dynamic_cast<TFormula*>(
      hist->GetListOfFunctions()->FindObject("wFormula"));
    if (xform) {
      hist->GetXaxis()->SetName(
        PairAnalysisHelper::GetFormulaName(xform).Data());
    }
    if (yform) {
      hist->GetYaxis()->SetName(
        PairAnalysisHelper::GetFormulaName(yform).Data());
    }
    if (zform) {
      hist->GetZaxis()->SetName(
        PairAnalysisHelper::GetFormulaName(zform).Data());
    }
    /////// set TITLE
    hist->GetXaxis()->SetTitle(PairAnalysisVarManager::GetValueLabel(varx));
    hist->GetYaxis()->SetTitle(PairAnalysisVarManager::GetValueLabel(vary));
    hist->GetZaxis()->SetTitle(PairAnalysisVarManager::GetValueLabel(varz));
    // adapt according to formula
    if (xform) {
      hist->GetXaxis()->SetTitle(
        PairAnalysisHelper::GetFormulaTitle(xform).Data());
    }
    if (yform) {
      hist->GetYaxis()->SetTitle(
        PairAnalysisHelper::GetFormulaTitle(yform).Data());
    }
    if (zform) {
      hist->GetZaxis()->SetTitle(
        PairAnalysisHelper::GetFormulaTitle(zform).Data());
    }
    // profile axis
    if (bprf && dim < 3) {
      TAxis* ax = 0x0;
      switch (dim) {
        case 2: ax = hist->GetZaxis(); break;
        case 1: ax = hist->GetYaxis(); break;
      }
      tit = ax->GetTitle();
      tit.Prepend((bStdOpt ? "#LT" : "RMS("));
      tit.Append((bStdOpt ? "#GT" : ")"));
      // TODO: activate -->      tit.Append ( Form("_{%ss}",hclass.Data()));
      tit.Append(calcrange.Data());
      ax->SetTitle(tit.Data());
    }
    // append the units for all axes (except formula)
    tit = Form("%s %s",
               hist->GetXaxis()->GetTitle(),
               PairAnalysisVarManager::GetValueUnit(varx));
    if (!xform) hist->GetXaxis()->SetTitle(tit.Data());
    tit = Form("%s %s",
               hist->GetYaxis()->GetTitle(),
               PairAnalysisVarManager::GetValueUnit(vary));
    if (!yform) hist->GetYaxis()->SetTitle(tit.Data());
    tit = Form("%s %s",
               hist->GetZaxis()->GetTitle(),
               PairAnalysisVarManager::GetValueUnit(varz));
    if (!zform) hist->GetZaxis()->SetTitle(tit.Data());
    // overwrite titles with hist class if needed
    if (!bprf) {
      switch (dim) {
        case 1: hist->GetYaxis()->SetTitle(Form("%ss", hclass.Data())); break;
        case 2: hist->GetZaxis()->SetTitle(Form("%ss", hclass.Data())); break;
      }
    }
    // weighted axis (maximal 2 dimensional)
    if (weight) {
      TAxis* ax = hist->GetYaxis();
      if (dim == 2) ax = hist->GetZaxis();
      tit = PairAnalysisVarManager::GetValueLabel(varp);
      if (wform) { tit = PairAnalysisHelper::GetFormulaTitle(wform); }
      ax->SetTitle(Form("%s weighted %s", tit.Data(), ax->GetTitle()));
    }

    // create an unique name
    TFormula* pform = dynamic_cast<TFormula*>(
      hist->GetListOfFunctions()->FindObject("pFormula"));
    if (bname) switch (dim) {
        case 3:
          currentName += Form("%s_", hist->GetXaxis()->GetName());
          currentName += Form("%s_", hist->GetYaxis()->GetName());
          currentName += Form("%s", hist->GetZaxis()->GetName());
          if (bprf && !pform)
            currentName += Form("-%s%s",
                                PairAnalysisVarManager::GetValueName(varp),
                                (bStdOpt ? "avg" : "rms"));
          else if (bprf)
            currentName +=
              Form("-%s%s",
                   PairAnalysisHelper::GetFormulaName(pform).Data(),
                   (bStdOpt ? "avg" : "rms"));
          if (weight && !bprf)
            currentName +=
              Form("-wght%s", PairAnalysisVarManager::GetValueName(varp));
          break;
        case 2:
          currentName += Form("%s_", hist->GetXaxis()->GetName());
          currentName += Form("%s", hist->GetYaxis()->GetName());
          if (bprf)
            currentName += Form(
              "-%s%s", hist->GetZaxis()->GetName(), (bStdOpt ? "avg" : "rms"));
          if (weight && !wform)
            currentName +=
              Form("-wght%s", PairAnalysisVarManager::GetValueName(varp));
          else if (weight && wform)
            currentName +=
              Form("-wght%s", PairAnalysisHelper::GetFormulaName(wform).Data());
          break;
        case 1:
          currentName += Form("%s", hist->GetXaxis()->GetName());
          if (bprf)
            currentName += Form(
              "-%s%s", hist->GetYaxis()->GetName(), (bStdOpt ? "avg" : "rms"));
          if (weight && !wform)
            currentName +=
              Form("-wght%s", PairAnalysisVarManager::GetValueName(varp));
          else if (weight && wform)
            currentName +=
              Form("-wght%s", PairAnalysisHelper::GetFormulaName(wform).Data());
          break;
      }
    // to differentiate btw. leg and pair histos
    //    if(!strcmp(histClass,"Pair")) currentName.Prepend("p");
    if (hclass.Contains("pair")) currentName.Prepend("p");
    hist->SetName(currentName.Data());
  }
}


//_____________________________________________________________________________
void PairAnalysisHistos::AdaptNameTitle(THnBase* hist, const char* histClass) {

  //
  // adapt name and title of the histogram
  //

  Int_t dim            = hist->GetNdimensions();
  TString currentName  = "";  //hist->GetName();
  TString currentTitle = "";  //hist->GetTitle();
  TString hclass       = histClass;
  //get reserved class
  TObjArray* arr = hclass.Tokenize("_.");
  arr->SetOwner();
  hclass = ((TObjString*) arr->At(0))->GetString();
  delete arr;
  hclass.ToLower();

  Bool_t bname  = (currentName.IsNull());
  Bool_t btitle = (currentTitle.IsNull());

  TList* list = (static_cast<PairAnalysisHn*>(hist))->GetListOfFunctions();

  // store titles in the axis
  if (btitle) {
    TString tit = "";
    // adapt according to formula
    for (Int_t it = 0; it < dim; it++) {
      TString formName = Form("axis%dFormula", it);
      TFormula* form   = dynamic_cast<TFormula*>(list->FindObject(formName));
      hist->GetAxis(it)->SetName(
        PairAnalysisHelper::GetFormulaName(form).Data());
      // adapt according to formula
      hist->GetAxis(it)->SetTitle(
        PairAnalysisHelper::GetFormulaTitle(form).Data());
    }
  }

  // create an unique name
  if (bname) {
    currentName = hist->GetName();
    if (hclass.Contains("pair")) currentName.Prepend("p");
    hist->SetName(currentName.Data());
  }
}