//this file looks like plain C, but it's actually -*- c++ -*-
#ifndef __TQCut__
#define __TQCut__

#include "TNamed.h"
#include "TObjArray.h"
#include "TTree.h"
#include "TString.h"

#include "QFramework/TQIterator.h"

class TQAnalysisJob;
class TQSample;
class TQFolder;
class TQObservable;
class TQAnalysisJob;
class TQToken;
class TQAnalysisSampleVisitorBase;

class TQCut : public TNamed {
public: 
  //various auxilliary data structures to handle "variants"
  struct VariantDefinition { // nested
    TString matchingPattern; //pattern to be matched by cuts to be replaced
    TString cutExpression; //new cut expression (ignored if empty string)
    TString weightExpression; //new weight expression (ignored if empty string)
  };
  //                           < suffix, vec< definition > >
  typedef std::vector<std::pair<TString,std::vector<VariantDefinition>>> VariantDefinitionList;
  
  
  struct VariantHandle { // nested
    TString cutExpression = "";
    TString weightExpression = "";
    TQObservable* cutObs = nullptr;
    TQObservable* weightObs = nullptr;
    std::vector<TQAnalysisJob*> analysisJobs;
    std::vector<TQSampleFolder*> variantSFs;
    std::vector<TQSampleFolder*> nominalSFs;
  };
  
  struct VariantStackElement { // nested
    //represents one layer of variants, 
    //the entries of vectors below represent the variants in the layer
    std::vector<VariantHandle> payload;
    std::vector<TQSampleFolder*> variantRoots; //first layer of the sampleFolder that is variant-specific
  };
  
  struct VariantResults { // nested
    std::vector<bool> passed;
    std::vector<double> weight;
    void resize(size_t size);
    void reset(double baseWeight=1.);
    bool passAny();
  };
  
  struct LazyWeight {
    TQCut* instance;
    double value = 0;
    LazyWeight () = delete;
    LazyWeight ( TQCut* inst) : instance(inst) {};
    operator double() {
      if (this->instance) {
        value = this->instance->getWeight(false);
        this->instance=nullptr;
      }
      return value;
    }
  };
  
protected:

  TString fCutExpression = "";
  TQObservable * fCutObservable = NULL; //!
 
  TString fWeightExpression = "";
  TQObservable * fWeightObservable = NULL; //!

  TQCut * fBase = NULL;
  //TODO: we may want to eventually repalce these TObjArray by stl containers
  //      this also allows us to easily get rid of the iterator members below
  TObjArray * fCuts = new TObjArray();
  TObjArray * fAnalysisJobs = new TObjArray(); //!

  mutable TQCutIterator fCutItr; //!
  mutable TQAnalysisJobIterator fJobItr; //!
  
  TQToken * fTreeToken = NULL; //!
  TQSample * fSample = NULL; //!
  std::vector<TQSampleFolder*> fInitializationHistory; //!
  TTree * fTree = NULL; //!
  
  //variant initialization stack. 
  std::vector<VariantStackElement*> fVariantStack; //!
  //handle to pass on dicisions for several variants at once (created at init, destroyed at finalize. sizes of vectors to be fixed at initialization)
  VariantResults* fVariantResults = nullptr; //!
 
  bool fSkipAnalysisJobs = false; //set based on tags on sample folders
  bool fSkipAnalysisJobsGlobal = false; //set based on tags during cut creation (from TQFolder)
  
  int fPrintResult = 0; // max number of events for which cut decision (and weight value) should be printed
  int fPrintResultCount = 0; //! transient member keeping track of how many decisions have already been printed
  
  void setBase(TQCut * base_);

  bool skipAnalysisJobs(TQSampleFolder * sf);

  virtual bool initializeObservables();
  virtual bool finalizeObservables();
  virtual bool initializeSelfSampleFolder(TQSampleFolder* sf);
  virtual bool finalizeSelfSampleFolder  (TQSampleFolder* sf);
  
  bool initializeVariantsSampleFolder(TQSampleFolder* sf, bool hasNewVariantLayer);
  bool initializeVariants(TQSample* sample, bool hasNewVariantLayer);
  
  bool verifyVariantSetup(const std::vector<VariantHandle>& parentHandles);
  
  bool finalizeVariantsSampleFolder(TQSampleFolder* sf);
  bool finalizeVariants();
  
  virtual TObjArray* getOwnBranches();

  bool printEvaluationStep(size_t indent) const;

  void printInternal(const TString& options, int indent);

  static TQCut* createFromFolderInternal(TQFolder* folder, TQTaggable* tags);
  void importFromFolderInternal(TQFolder * folder, TQTaggable* tags);
  
  int createVariantFolders(TQSampleFolder* sf, const TQCut::VariantDefinitionList* variantDefs);//, std::vector<TQSampleFolder*>& variantFolders);
  VariantStackElement* createVariantLayer(const std::vector<VariantHandle>& preceedingHandles, TQSampleFolder* nextSF, const VariantDefinitionList* variantDefs);
  bool createVariants(TQSampleFolder* nextSF, const VariantDefinitionList* variantDefs);
  
  void analyseVariants(const VariantResults* preceedingResults, bool useWeights, double baseWeight=1.); //base weight can be given if no previous variant result is available
public:

  int Compare(const TObject* obj) const override;
  void sort();
  int getDepth() const;
  int getWidth() const;

  void printEvaluation() const;
  void printEvaluation(Long64_t iEvent) const;
  void printWeightComponents() const;
  void printWeightComponents(Long64_t iEvent) const;
 
  static void writeDiagramHeader(std::ostream & os, TQTaggable& tags);
  static void writeDiagramFooter(std::ostream & os, TQTaggable& tags);
  int writeDiagramText(std::ostream& os, TQTaggable& tags, TString pos = "");
  bool writeDiagramToFile(const TString& filename, const TString& options = "");
  bool writeDiagramToFile(const TString& filename, TQTaggable& tags);
  bool printDiagram(TQTaggable& options);
  bool printDiagram(const TString& options);
  TString writeDiagramToString(TQTaggable& tags);
  TString getNodeName();

  TList * exportDefinitions(bool terminatingColon = false);

  static bool isValidName(const TString& name_);

  static bool parseCutDefinition(const TString& definition_, TString * name_, 
                                 TString * baseCutName_, TString * cutExpr_, TString * weightExpr_);

  static bool parseCutDefinition(TString definition_, TString& name_, 
                                 TString& baseCutName_, TString& cutExpr_, TString& weightExpr_);

  static TQCut * createCut(const TString& definition_);
  static TQCut * createCut(const TString& name, const TString& cutExpr, const TString& weightExpr = "");

  static TQCut * importFromFolder(TQFolder * folder, TQTaggable* tags = NULL);


  TQCut();
  TQCut(const TString& name_, const TString& title_ = "", const TString& cutExpression = "", const TString& weightExpression = "");

  TQCut * getBase();
  TString getPath();
  const TQCut * getBaseConst() const;
  TQCut * getRoot();

  bool isDescendantOf(TString cutName);

  static bool isTrivialTrue(const TString& expr);
  static bool isTrivialFalse(const TString& expr);

  TString getActiveCutExpression() const;
  TString getActiveWeightExpression() const;

  void printActiveCutExpression(size_t indent = 0) const;

  void setCutExpression(const TString& cutExpression);
  const TString& getCutExpression() const;
  TString getCompiledCutExpression(TQTaggable* tags);
  TString getGlobalCutExpression(TQTaggable* tags = NULL);
 
  void setWeightExpression(const TString& weightExpression);
  const TString& getWeightExpression() const;
  TString getCompiledWeightExpression(TQTaggable* tags);
  TString getGlobalWeightExpression(TQTaggable* tags = NULL);
  
  inline void setSkipAnalysisJobsGlobal(bool skip=true) {this->fSkipAnalysisJobsGlobal = skip;}
  inline bool getSkipAnalysisJobsGlobal() const {return this->fSkipAnalysisJobsGlobal;}
  
  inline void setPrintResults(int maxCount=0) {this->fPrintResult = maxCount;}
  inline bool getPrintResults() const {return this->fPrintResult;}
  
  TQObservable* getCutObservable();
  TQObservable* getWeightObservable();

  bool addCut(const TString& definition_);
  bool addCut(TQCut * cut);
  bool addCut(TQCut * cut, const TString& baseCutName);
 
  TQCut * addAndReturnCut(const TString& definition_);

  bool includeBase();
  bool removeCut(const TString& name);

  void printCuts(const TString& options = "r");
  void printCut(const TString& options = "r");
  void print(const TString& options = "r");
  void printAnalysisJobs(const TString& options = "");
  
  int dumpToFolder(TQFolder * folder);

  virtual bool isMergeable() const;

  void consolidate();

  TQCut * getCut(const TString& name);
  void getMatchingCuts(TObjArray& matchingCuts, const TString& name);
  std::vector<TString> getCutNames(const TString& cutName);
  void getMatchingCuts(TObjArray& matchingCuts, const TObjArray& name_sep, int offset=0);
  void propagateMatchingCuts(TObjArray& matchingCuts, const TObjArray& name_sep, int offset=0);
  bool isResidualMatchingSegmentOptional(const TObjArray& name_segments, int offset=0);
  TObjArray * getCuts();
  TObjArray * getListOfCuts();
  virtual TObjArray * getListOfBranches();
  TQCut * getSingleCut(TString name, TString excl_pattern = "PATTERNYOUWON'TSEE");
  
  void setCuts(TObjArray* cuts);
  
protected:
  bool initialize(TQSample* sample, const TQCut::VariantDefinitionList* variantDefs); //should not be valled from outside TQCut
public:
  virtual bool initialize(TQSample * sample); //public interface
  virtual bool finalize();
  TQSample* getSample();
  inline const std::vector<TQSampleFolder*>& getInitializationHistory() const { return this->fInitializationHistory;} 
  
  bool canInitialize(TQSampleFolder* sf) const;
  bool canFinalize(TQSampleFolder* sf) const;
protected:
  bool initializeSampleFolder(TQSampleFolder* sf, const TQCut::VariantDefinitionList* variantDefs); //should not be valled from outside TQCut
public:
  bool initializeSampleFolder(TQSampleFolder* sf); //public interface
  bool finalizeSampleFolder (TQSampleFolder* sf);
 
  bool addAnalysisJob(TQAnalysisJob * newJob_, const TString& cuts_ = "");
  int getNAnalysisJobs();
  void clearAnalysisJobs();
  TObjArray* getJobs();

  TQCut* getClone();
  TQCut* getCompiledClone(TQTaggable* tags);

  virtual bool passed(bool doPrint=false) const;
  virtual double getWeight(bool doPrint=false) const;

  virtual bool passedGlobally() const;
  virtual double getGlobalWeight() const;

  bool executeAnalysisJobs(double weight);
  void analyse(double weight, bool useWeights);
  
  virtual ~TQCut();
 
  ClassDefOverride(TQCut, 1); // a cut to be applied during an analysis

};

#endif
 TQCut.h:1
 TQCut.h:2
 TQCut.h:3
 TQCut.h:4
 TQCut.h:5
 TQCut.h:6
 TQCut.h:7
 TQCut.h:8
 TQCut.h:9
 TQCut.h:10
 TQCut.h:11
 TQCut.h:12
 TQCut.h:13
 TQCut.h:14
 TQCut.h:15
 TQCut.h:16
 TQCut.h:17
 TQCut.h:18
 TQCut.h:19
 TQCut.h:20
 TQCut.h:21
 TQCut.h:22
 TQCut.h:23
 TQCut.h:24
 TQCut.h:25
 TQCut.h:26
 TQCut.h:27
 TQCut.h:28
 TQCut.h:29
 TQCut.h:30
 TQCut.h:31
 TQCut.h:32
 TQCut.h:33
 TQCut.h:34
 TQCut.h:35
 TQCut.h:36
 TQCut.h:37
 TQCut.h:38
 TQCut.h:39
 TQCut.h:40
 TQCut.h:41
 TQCut.h:42
 TQCut.h:43
 TQCut.h:44
 TQCut.h:45
 TQCut.h:46
 TQCut.h:47
 TQCut.h:48
 TQCut.h:49
 TQCut.h:50
 TQCut.h:51
 TQCut.h:52
 TQCut.h:53
 TQCut.h:54
 TQCut.h:55
 TQCut.h:56
 TQCut.h:57
 TQCut.h:58
 TQCut.h:59
 TQCut.h:60
 TQCut.h:61
 TQCut.h:62
 TQCut.h:63
 TQCut.h:64
 TQCut.h:65
 TQCut.h:66
 TQCut.h:67
 TQCut.h:68
 TQCut.h:69
 TQCut.h:70
 TQCut.h:71
 TQCut.h:72
 TQCut.h:73
 TQCut.h:74
 TQCut.h:75
 TQCut.h:76
 TQCut.h:77
 TQCut.h:78
 TQCut.h:79
 TQCut.h:80
 TQCut.h:81
 TQCut.h:82
 TQCut.h:83
 TQCut.h:84
 TQCut.h:85
 TQCut.h:86
 TQCut.h:87
 TQCut.h:88
 TQCut.h:89
 TQCut.h:90
 TQCut.h:91
 TQCut.h:92
 TQCut.h:93
 TQCut.h:94
 TQCut.h:95
 TQCut.h:96
 TQCut.h:97
 TQCut.h:98
 TQCut.h:99
 TQCut.h:100
 TQCut.h:101
 TQCut.h:102
 TQCut.h:103
 TQCut.h:104
 TQCut.h:105
 TQCut.h:106
 TQCut.h:107
 TQCut.h:108
 TQCut.h:109
 TQCut.h:110
 TQCut.h:111
 TQCut.h:112
 TQCut.h:113
 TQCut.h:114
 TQCut.h:115
 TQCut.h:116
 TQCut.h:117
 TQCut.h:118
 TQCut.h:119
 TQCut.h:120
 TQCut.h:121
 TQCut.h:122
 TQCut.h:123
 TQCut.h:124
 TQCut.h:125
 TQCut.h:126
 TQCut.h:127
 TQCut.h:128
 TQCut.h:129
 TQCut.h:130
 TQCut.h:131
 TQCut.h:132
 TQCut.h:133
 TQCut.h:134
 TQCut.h:135
 TQCut.h:136
 TQCut.h:137
 TQCut.h:138
 TQCut.h:139
 TQCut.h:140
 TQCut.h:141
 TQCut.h:142
 TQCut.h:143
 TQCut.h:144
 TQCut.h:145
 TQCut.h:146
 TQCut.h:147
 TQCut.h:148
 TQCut.h:149
 TQCut.h:150
 TQCut.h:151
 TQCut.h:152
 TQCut.h:153
 TQCut.h:154
 TQCut.h:155
 TQCut.h:156
 TQCut.h:157
 TQCut.h:158
 TQCut.h:159
 TQCut.h:160
 TQCut.h:161
 TQCut.h:162
 TQCut.h:163
 TQCut.h:164
 TQCut.h:165
 TQCut.h:166
 TQCut.h:167
 TQCut.h:168
 TQCut.h:169
 TQCut.h:170
 TQCut.h:171
 TQCut.h:172
 TQCut.h:173
 TQCut.h:174
 TQCut.h:175
 TQCut.h:176
 TQCut.h:177
 TQCut.h:178
 TQCut.h:179
 TQCut.h:180
 TQCut.h:181
 TQCut.h:182
 TQCut.h:183
 TQCut.h:184
 TQCut.h:185
 TQCut.h:186
 TQCut.h:187
 TQCut.h:188
 TQCut.h:189
 TQCut.h:190
 TQCut.h:191
 TQCut.h:192
 TQCut.h:193
 TQCut.h:194
 TQCut.h:195
 TQCut.h:196
 TQCut.h:197
 TQCut.h:198
 TQCut.h:199
 TQCut.h:200
 TQCut.h:201
 TQCut.h:202
 TQCut.h:203
 TQCut.h:204
 TQCut.h:205
 TQCut.h:206
 TQCut.h:207
 TQCut.h:208
 TQCut.h:209
 TQCut.h:210
 TQCut.h:211
 TQCut.h:212
 TQCut.h:213
 TQCut.h:214
 TQCut.h:215
 TQCut.h:216
 TQCut.h:217
 TQCut.h:218
 TQCut.h:219
 TQCut.h:220
 TQCut.h:221
 TQCut.h:222
 TQCut.h:223
 TQCut.h:224
 TQCut.h:225
 TQCut.h:226
 TQCut.h:227
 TQCut.h:228
 TQCut.h:229
 TQCut.h:230
 TQCut.h:231
 TQCut.h:232
 TQCut.h:233
 TQCut.h:234
 TQCut.h:235
 TQCut.h:236
 TQCut.h:237
 TQCut.h:238
 TQCut.h:239
 TQCut.h:240
 TQCut.h:241
 TQCut.h:242
 TQCut.h:243
 TQCut.h:244
 TQCut.h:245
 TQCut.h:246
 TQCut.h:247
 TQCut.h:248
 TQCut.h:249
 TQCut.h:250
 TQCut.h:251
 TQCut.h:252
 TQCut.h:253
 TQCut.h:254
 TQCut.h:255
 TQCut.h:256
 TQCut.h:257
 TQCut.h:258
 TQCut.h:259
 TQCut.h:260
 TQCut.h:261
 TQCut.h:262
 TQCut.h:263
 TQCut.h:264
 TQCut.h:265
 TQCut.h:266
 TQCut.h:267
 TQCut.h:268
 TQCut.h:269
 TQCut.h:270
 TQCut.h:271
 TQCut.h:272
 TQCut.h:273
 TQCut.h:274
 TQCut.h:275
 TQCut.h:276
 TQCut.h:277
 TQCut.h:278
 TQCut.h:279
 TQCut.h:280
 TQCut.h:281
 TQCut.h:282