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

#include "QFramework/TQSampleFolder.h"
#include "TH1.h"
#include "TString.h"

class TQSystematicsManager {

  TQFolder* histos;
  TString sysPrefix = "Systematics";
  TString varPrefix = "Variations";

  std::map<TString,TQSampleFolder*> _inputCache;
  
  int nErrors = 0;
  int nErrorThreshold = 100;
protected:
  bool emitError();
  
public:
  TQSampleFolder* getSampleFolder(TQTaggable* var);
  void setSampleFolder(const TString& path, TQSampleFolder* sf);  
  virtual ~TQSystematicsManager();
  
  void setSystematicPrefix(const TString& prefix);
  void setVariationPrefix(const TString& prefix);  
  
  struct HistogramVariationComputer {
    const TH1* fBaseline = NULL;
    TH1* fDelta = NULL; 
    TH1* fRelativeDelta = NULL;

    bool emitError();
    
    HistogramVariationComputer(const TH1* base);
    ~HistogramVariationComputer() {
      delete fDelta;
      delete fRelativeDelta;
    }

    // compute histogram variation
    bool computeVariation(TObjArray* vars, TString mode);
    bool computeSingle(TObjArray* vars);
    bool computeDifference(TObjArray* vars);
    bool computeMinimum(TObjArray* vars);
    bool computeMaximum(TObjArray* vars);
    bool computeEnvelope(TObjArray* vars);
    bool computeStdDev(TObjArray* vars);
    bool computeHessian(TObjArray* vars);
    // manually set statistical error
    void useStatError(TH1* error, bool relative=true);
    // apply var = nominal +/- delta
    TH1* applyVariation(const TH1* nom, double c=1.0, bool relative=true);
  };

  // store histograms
  // raw variation, e.g. .Histograms/JET_JES_EffectiveNP1__1up
  TString storeVarHisto(TH1 * histo, const TString& nameVariation, const TString& nameChannel);
  TString storeVarHisto(TH1 * histo, const TString& path);  
  // computed systematic variation, e.g. .Histograms/Systematics/ATLAS_JES_EffectiveNP_1/Up
  TString storeSysHisto(TH1 * histo, const TString& nameVariation, const TString& direction, const TString& nameChannel);
  TString storeSysHisto(TH1 * histo, const TString& path);  
  TH1 * getVarHisto(const TString& nameVariation, const TString& nameChannel, const TString& nameSample, bool verbose = true);
  TH1 * getVarHisto(const TString& path, bool verbose = true);  
  TH1 * getSysHisto(const TString& path, bool verbose = true);
  TH1 * getHisto(TString path, bool verbose = true);    

  Bool_t isSystBlacklisted(TQFolder* sys, const std::vector<TString>&  systBlacklist, const std::vector<TString>& types = {"OverallSys","HistoSys"});
  bool processHistoSys_smoothVariation(TQTaggable* parameters, TQFolder* sys, TH1* nom, TH1* up, TH1* down);
  bool processHistoSys_systsToSymmetrizeBins(TQTaggable* parameters, TQFolder *sys, TH1* nom, TH1* up, TH1* down);
  bool processHistoSys_systsToSymmetrizeMaxBins(TQTaggable* parameters, TQFolder *sys, TH1* nom, TH1* up, TH1* down, bool force = false);
  bool processHistoSys_isFlat(TQTaggable* parameters, TQFolder* sys, TH1* ratio);  
  bool processHistoSys_checkCutoff(TQTaggable* parameters, TH1* ratio);
  
protected:
  // histogram variation computation
  TH1* computeHistogramVariation(TQFolder* computeFolder, const TString& nameChannel, const TString& nameSample);
  // bins to smooth histograms manually
  std::vector<int> getSmoothedBinBorders(TQFolder* sysConfig);

  // shape variation normalization/magnification
  TH1* normalizeShapeVariation(const TH1* h_Var, const TH1* h_Nom, const TH1* h_Sym);
  void magnifyShapeVariation(TH1*& shape_Var, const TH1 * h_Nom, Double_t magnification);

  bool smoothHist(const TString& alg, TH1* nom, TH1* var);
  
public:  
  // custom/default mode as appropriate
  bool includeOverallSys(TQFolder* sysFolder, TQFolder* sys, const TString& nameChannel, const TString& nameSample);
  bool includeHistoSys(TQFolder* sysFolder, TQFolder* sys, const TString& nameChannel, const TString& nameSample);

  // systematic processing switches
  bool isBlacklistedSys(TQFolder* sys, const std::vector<TString>&  systBlacklist, const std::vector<TString>& types = {"OverallSys","HistoSys"});
  bool isNegligibleSys(TQFolder* sys, TQTaggable* parameters);
  bool isProtectedSys(TQFolder* sys, TQTaggable* parameters, const TString& prefix) const;

  // post-process included systematics
  bool processOverallSys(TQTaggable* parameters, TQFolder* sys);
  bool processHistoSys  (TQTaggable* parameters, TQFolder* sys);
  
  static void info(TString message);
  static void error(TString message);
  static void warn(TString message);
  
 public:
  TQSystematicsManager(TQFolder* h) : histos(h) {};
  TQSystematicsManager() : TQSystematicsManager(NULL) {};
  void setRepository(TQFolder* histos);
  TQFolder* repository();
  
  ClassDef(TQSystematicsManager, 0);
  
};

  

#endif
 TQSystematicsManager.h:1
 TQSystematicsManager.h:2
 TQSystematicsManager.h:3
 TQSystematicsManager.h:4
 TQSystematicsManager.h:5
 TQSystematicsManager.h:6
 TQSystematicsManager.h:7
 TQSystematicsManager.h:8
 TQSystematicsManager.h:9
 TQSystematicsManager.h:10
 TQSystematicsManager.h:11
 TQSystematicsManager.h:12
 TQSystematicsManager.h:13
 TQSystematicsManager.h:14
 TQSystematicsManager.h:15
 TQSystematicsManager.h:16
 TQSystematicsManager.h:17
 TQSystematicsManager.h:18
 TQSystematicsManager.h:19
 TQSystematicsManager.h:20
 TQSystematicsManager.h:21
 TQSystematicsManager.h:22
 TQSystematicsManager.h:23
 TQSystematicsManager.h:24
 TQSystematicsManager.h:25
 TQSystematicsManager.h:26
 TQSystematicsManager.h:27
 TQSystematicsManager.h:28
 TQSystematicsManager.h:29
 TQSystematicsManager.h:30
 TQSystematicsManager.h:31
 TQSystematicsManager.h:32
 TQSystematicsManager.h:33
 TQSystematicsManager.h:34
 TQSystematicsManager.h:35
 TQSystematicsManager.h:36
 TQSystematicsManager.h:37
 TQSystematicsManager.h:38
 TQSystematicsManager.h:39
 TQSystematicsManager.h:40
 TQSystematicsManager.h:41
 TQSystematicsManager.h:42
 TQSystematicsManager.h:43
 TQSystematicsManager.h:44
 TQSystematicsManager.h:45
 TQSystematicsManager.h:46
 TQSystematicsManager.h:47
 TQSystematicsManager.h:48
 TQSystematicsManager.h:49
 TQSystematicsManager.h:50
 TQSystematicsManager.h:51
 TQSystematicsManager.h:52
 TQSystematicsManager.h:53
 TQSystematicsManager.h:54
 TQSystematicsManager.h:55
 TQSystematicsManager.h:56
 TQSystematicsManager.h:57
 TQSystematicsManager.h:58
 TQSystematicsManager.h:59
 TQSystematicsManager.h:60
 TQSystematicsManager.h:61
 TQSystematicsManager.h:62
 TQSystematicsManager.h:63
 TQSystematicsManager.h:64
 TQSystematicsManager.h:65
 TQSystematicsManager.h:66
 TQSystematicsManager.h:67
 TQSystematicsManager.h:68
 TQSystematicsManager.h:69
 TQSystematicsManager.h:70
 TQSystematicsManager.h:71
 TQSystematicsManager.h:72
 TQSystematicsManager.h:73
 TQSystematicsManager.h:74
 TQSystematicsManager.h:75
 TQSystematicsManager.h:76
 TQSystematicsManager.h:77
 TQSystematicsManager.h:78
 TQSystematicsManager.h:79
 TQSystematicsManager.h:80
 TQSystematicsManager.h:81
 TQSystematicsManager.h:82
 TQSystematicsManager.h:83
 TQSystematicsManager.h:84
 TQSystematicsManager.h:85
 TQSystematicsManager.h:86
 TQSystematicsManager.h:87
 TQSystematicsManager.h:88
 TQSystematicsManager.h:89
 TQSystematicsManager.h:90
 TQSystematicsManager.h:91
 TQSystematicsManager.h:92
 TQSystematicsManager.h:93
 TQSystematicsManager.h:94
 TQSystematicsManager.h:95
 TQSystematicsManager.h:96
 TQSystematicsManager.h:97
 TQSystematicsManager.h:98
 TQSystematicsManager.h:99
 TQSystematicsManager.h:100
 TQSystematicsManager.h:101
 TQSystematicsManager.h:102
 TQSystematicsManager.h:103
 TQSystematicsManager.h:104
 TQSystematicsManager.h:105
 TQSystematicsManager.h:106
 TQSystematicsManager.h:107
 TQSystematicsManager.h:108
 TQSystematicsManager.h:109
 TQSystematicsManager.h:110
 TQSystematicsManager.h:111
 TQSystematicsManager.h:112
 TQSystematicsManager.h:113
 TQSystematicsManager.h:114
 TQSystematicsManager.h:115
 TQSystematicsManager.h:116
 TQSystematicsManager.h:117
 TQSystematicsManager.h:118
 TQSystematicsManager.h:119