#include "SFramework/TSSystematicsManager.h"

#include "QFramework/TQIterator.h"

// #define _DEBUG_

#include "QFramework/TQLibrary.h"

//__________________________________________________________________________________|___________

TSSystematicsManager::TSSystematicsManager(TQFolder* h) : TQSystematicsManager(h) {
  // legacy compatibility
  this->setVariationPrefix("");
}

//__________________________________________________________________________________|___________

TSSystematicsManager::TSSystematicsManager() : TQSystematicsManager(NULL) {
  // legacy compatibility  
  this->setVariationPrefix("");
}

//__________________________________________________________________________________|___________

bool TSSystematicsManager::processAllSystematics(TQFolder * parameters, TList* allSamples,
                                                   const TString& selectedSystFilter, const std::vector<TString>& sampleBlacklist, const std::vector<TString>&  systBlacklist) {
  // perform processing on all systematics
  info(TString::Format("processAllSystematics(): Start processing systematics matching '%s'",selectedSystFilter.Data()));

  TString overallFilter;
  TString shapeFilter;
  std::vector<TString> systematicsTypes = parameters->getTagVString("select.SystematicsTypes");
  if(systematicsTypes.empty()) {
    systematicsTypes.push_back("HistoSys");
    systematicsTypes.push_back("OverallSys");
  }    
  for (auto t : systematicsTypes) {
    if (t.Contains("OverallSys")) overallFilter = "OverallSys."+selectedSystFilter;
    if (t.Contains("HistoSys")) shapeFilter = "HistoSys."+selectedSystFilter;
  }
  
  TString allFilter = "*"+selectedSystFilter;

  // loop over all regions and samples
  TQFolderIterator sampleitr(allSamples);
  while (sampleitr.hasNext()) {
    TQFolder* sampleDef = sampleitr.readNext();
    if(!sampleDef) continue;
    bool isBlacklisted = false;
    for (auto& s: sampleBlacklist) {
      if(TQStringUtils::matches(sampleDef->getName(),"Sample."+s)) {
        isBlacklisted = true;
        break;
      }
    }
    if(isBlacklisted) continue;
    
    TQFolder* dropped = sampleDef->getFolder(".Dropped+");

    if (parameters->getTagBoolDefault("pruneNegligibles", false)) {
      // loop over all samples to remove the negligible ones
      TQFolderIterator allsysitr(sampleDef->getListOfFolders(allFilter), true);
      while(allsysitr.hasNext()) {
        TQFolder* sys = allsysitr.readNext();
        if (!sys || isBlacklistedSys(sys, systBlacklist)) continue;
        // prune syst based on contribution in region
        if(isNegligibleSys(sys,parameters)) {
          sys->detachFromBase();
          dropped->addObject(sys);
        }
      }
    }

    if (!overallFilter.IsNull()) {
      TQFolderIterator overallsysitr(sampleDef->getListOfFolders(overallFilter), true);
      while(overallsysitr.hasNext()){
        TQFolder* sys = overallsysitr.readNext();
        if(!sys || isBlacklistedSys(sys, systBlacklist)) continue;
        // process overall systematics
        if(!processOverallSys(parameters,sys)){
          sys->detachFromBase();
          dropped->addObject(sys);
        }
      }
    }

    if (!shapeFilter.IsNull()) {
      TQFolderIterator histosysitr(sampleDef->getListOfFolders(shapeFilter), true);
      while(histosysitr.hasNext()){
        TQFolder* sys = histosysitr.readNext();
        if(!sys || isBlacklistedSys(sys, systBlacklist)) continue;
        // process histogram systematics
        if(!processHistoSys(parameters,sys)){
          sys->detachFromBase();
          dropped->addObject(sys);
        }
      }
    }
  }
  return true;
}

//__________________________________________________________________________________|___________

bool TSSystematicsManager::includeSystematics(TList* allSamples, TQFolder* sysFolder) {

  TString sysName(sysFolder->GetName());
  
  //@tag: [IsOverallSys,IsHistoSys] declare as Normalization (OverallSys) and/or shape (HistoSys) systematic
  bool isOverallSys	= sysFolder->getTagBoolDefault("IsOverallSys", true);
  bool isHistoSys	= sysFolder->getTagBoolDefault("IsHistoSys", false);

  //@tag: [Include,Exclude] Inclusion and Exclusion string patterns for systematics  (will be matched to "Channel:Sample")
  TString filterInclude = sysFolder->getTagStringDefault("Include", "*");
  TString filterExclude = sysFolder->getTagStringDefault("Exclude", "");

  // loop over combinations of channels and samples
  int nOverall = 0;
  int nHisto = 0;
  TQFolderIterator itr(allSamples);
  while (itr.hasNext()) {
    TQFolder * sampleDef = itr.readNext();
    TString nameSample;
    TString nameChannel;    
    if(!sampleDef->getTagString("~Sample",nameSample) || !sampleDef->getTagString("~Channel",nameChannel)){
      error("unable to find 'Sample' or 'Channel' information!");
      return false;
    }
    TString typeSample = sampleDef->getTagStringDefault("~Type","B");
    if(typeSample == "D") continue;

    int nbins = sampleDef->getTagIntegerDefault("Bins",0);
    
    /* ===== systematics filter ===== */

    bool passesInclude = TQStringUtils::matchesFilter(nameChannel + ":" + nameSample, filterInclude, ",", true);
    bool passesExclude = TQStringUtils::matchesFilter(nameChannel + ":" + nameSample, filterExclude, ",", true);
    if (!passesInclude || passesExclude) {
      DEBUGclass("skipping '%s:%s' due to filters:\n  Include=%s\n  Exclude=%s",nameChannel.Data(),nameSample.Data(),filterInclude.Data(),filterExclude.Data());
      continue;
    }

    if(isOverallSys){
      TQFolder* sys = sampleDef->getFolder("OverallSys."+sysName+"+");
      sys->setTagString("Systematic",sysName);
      DEBUGclass("including %s as overall systematic for sample %s",sysName.Data(),nameSample.Data());
      if(!includeOverallSys(sysFolder,sys,nameChannel,nameSample)){
        sys->detachFromBase();
        delete sys;
      } else {
        nOverall++;
        sys->importTags(sysFolder->getBase());        
        sys->importTags(sysFolder);
      }
    }
    if(nbins != 1 && isHistoSys){
      TQFolder* sys = sampleDef->getFolder("HistoSys."+sysName+"+");
      sys->setTagString("Systematic",sysName);
      DEBUGclass("including %s as histo systematic for sample %s",sysName.Data(),nameSample.Data());      
      if(!includeHistoSys(sysFolder,sys,nameChannel,nameSample)){
        sys->detachFromBase();
        delete sys;
      } else {
        nHisto++;        
        sys->importTags(sysFolder->getBase());                
        sys->importTags(sysFolder);
      }
    }
  }
  
  info(TString::Format("includeSystematics('%s'): Included %d overall & %d histogram systematics. Included: '%s'. Excluded: '%s'", sysName.Data(), nOverall, nHisto,filterInclude.Data(),filterExclude.Data()));
  
  return true;
}

//__________________________________________________________________________________|___________

bool TSSystematicsManager::includeAllSystematics(TQFolder * systematics, TList* allSamples) {
  // loop over all systematics and include them for all samples
  if(!systematics) return true;

  info("includeAllSystematics(): Start including systematics ...");
  
  TQFolderIterator itr(systematics->getListOfFolders("?"), "!.*", true);
  bool ok = true;
  while (itr.hasNext()) {
    TQFolder* f = itr.readNext();
    DEBUGclass("including %s",f->GetName());
    if(!includeSystematics(allSamples, f)){
      ok = false;
    }
  }
  
  return ok;
}


 TSSystematicsManager.cxx:1
 TSSystematicsManager.cxx:2
 TSSystematicsManager.cxx:3
 TSSystematicsManager.cxx:4
 TSSystematicsManager.cxx:5
 TSSystematicsManager.cxx:6
 TSSystematicsManager.cxx:7
 TSSystematicsManager.cxx:8
 TSSystematicsManager.cxx:9
 TSSystematicsManager.cxx:10
 TSSystematicsManager.cxx:11
 TSSystematicsManager.cxx:12
 TSSystematicsManager.cxx:13
 TSSystematicsManager.cxx:14
 TSSystematicsManager.cxx:15
 TSSystematicsManager.cxx:16
 TSSystematicsManager.cxx:17
 TSSystematicsManager.cxx:18
 TSSystematicsManager.cxx:19
 TSSystematicsManager.cxx:20
 TSSystematicsManager.cxx:21
 TSSystematicsManager.cxx:22
 TSSystematicsManager.cxx:23
 TSSystematicsManager.cxx:24
 TSSystematicsManager.cxx:25
 TSSystematicsManager.cxx:26
 TSSystematicsManager.cxx:27
 TSSystematicsManager.cxx:28
 TSSystematicsManager.cxx:29
 TSSystematicsManager.cxx:30
 TSSystematicsManager.cxx:31
 TSSystematicsManager.cxx:32
 TSSystematicsManager.cxx:33
 TSSystematicsManager.cxx:34
 TSSystematicsManager.cxx:35
 TSSystematicsManager.cxx:36
 TSSystematicsManager.cxx:37
 TSSystematicsManager.cxx:38
 TSSystematicsManager.cxx:39
 TSSystematicsManager.cxx:40
 TSSystematicsManager.cxx:41
 TSSystematicsManager.cxx:42
 TSSystematicsManager.cxx:43
 TSSystematicsManager.cxx:44
 TSSystematicsManager.cxx:45
 TSSystematicsManager.cxx:46
 TSSystematicsManager.cxx:47
 TSSystematicsManager.cxx:48
 TSSystematicsManager.cxx:49
 TSSystematicsManager.cxx:50
 TSSystematicsManager.cxx:51
 TSSystematicsManager.cxx:52
 TSSystematicsManager.cxx:53
 TSSystematicsManager.cxx:54
 TSSystematicsManager.cxx:55
 TSSystematicsManager.cxx:56
 TSSystematicsManager.cxx:57
 TSSystematicsManager.cxx:58
 TSSystematicsManager.cxx:59
 TSSystematicsManager.cxx:60
 TSSystematicsManager.cxx:61
 TSSystematicsManager.cxx:62
 TSSystematicsManager.cxx:63
 TSSystematicsManager.cxx:64
 TSSystematicsManager.cxx:65
 TSSystematicsManager.cxx:66
 TSSystematicsManager.cxx:67
 TSSystematicsManager.cxx:68
 TSSystematicsManager.cxx:69
 TSSystematicsManager.cxx:70
 TSSystematicsManager.cxx:71
 TSSystematicsManager.cxx:72
 TSSystematicsManager.cxx:73
 TSSystematicsManager.cxx:74
 TSSystematicsManager.cxx:75
 TSSystematicsManager.cxx:76
 TSSystematicsManager.cxx:77
 TSSystematicsManager.cxx:78
 TSSystematicsManager.cxx:79
 TSSystematicsManager.cxx:80
 TSSystematicsManager.cxx:81
 TSSystematicsManager.cxx:82
 TSSystematicsManager.cxx:83
 TSSystematicsManager.cxx:84
 TSSystematicsManager.cxx:85
 TSSystematicsManager.cxx:86
 TSSystematicsManager.cxx:87
 TSSystematicsManager.cxx:88
 TSSystematicsManager.cxx:89
 TSSystematicsManager.cxx:90
 TSSystematicsManager.cxx:91
 TSSystematicsManager.cxx:92
 TSSystematicsManager.cxx:93
 TSSystematicsManager.cxx:94
 TSSystematicsManager.cxx:95
 TSSystematicsManager.cxx:96
 TSSystematicsManager.cxx:97
 TSSystematicsManager.cxx:98
 TSSystematicsManager.cxx:99
 TSSystematicsManager.cxx:100
 TSSystematicsManager.cxx:101
 TSSystematicsManager.cxx:102
 TSSystematicsManager.cxx:103
 TSSystematicsManager.cxx:104
 TSSystematicsManager.cxx:105
 TSSystematicsManager.cxx:106
 TSSystematicsManager.cxx:107
 TSSystematicsManager.cxx:108
 TSSystematicsManager.cxx:109
 TSSystematicsManager.cxx:110
 TSSystematicsManager.cxx:111
 TSSystematicsManager.cxx:112
 TSSystematicsManager.cxx:113
 TSSystematicsManager.cxx:114
 TSSystematicsManager.cxx:115
 TSSystematicsManager.cxx:116
 TSSystematicsManager.cxx:117
 TSSystematicsManager.cxx:118
 TSSystematicsManager.cxx:119
 TSSystematicsManager.cxx:120
 TSSystematicsManager.cxx:121
 TSSystematicsManager.cxx:122
 TSSystematicsManager.cxx:123
 TSSystematicsManager.cxx:124
 TSSystematicsManager.cxx:125
 TSSystematicsManager.cxx:126
 TSSystematicsManager.cxx:127
 TSSystematicsManager.cxx:128
 TSSystematicsManager.cxx:129
 TSSystematicsManager.cxx:130
 TSSystematicsManager.cxx:131
 TSSystematicsManager.cxx:132
 TSSystematicsManager.cxx:133
 TSSystematicsManager.cxx:134
 TSSystematicsManager.cxx:135
 TSSystematicsManager.cxx:136
 TSSystematicsManager.cxx:137
 TSSystematicsManager.cxx:138
 TSSystematicsManager.cxx:139
 TSSystematicsManager.cxx:140
 TSSystematicsManager.cxx:141
 TSSystematicsManager.cxx:142
 TSSystematicsManager.cxx:143
 TSSystematicsManager.cxx:144
 TSSystematicsManager.cxx:145
 TSSystematicsManager.cxx:146
 TSSystematicsManager.cxx:147
 TSSystematicsManager.cxx:148
 TSSystematicsManager.cxx:149
 TSSystematicsManager.cxx:150
 TSSystematicsManager.cxx:151
 TSSystematicsManager.cxx:152
 TSSystematicsManager.cxx:153
 TSSystematicsManager.cxx:154
 TSSystematicsManager.cxx:155
 TSSystematicsManager.cxx:156
 TSSystematicsManager.cxx:157
 TSSystematicsManager.cxx:158
 TSSystematicsManager.cxx:159
 TSSystematicsManager.cxx:160
 TSSystematicsManager.cxx:161
 TSSystematicsManager.cxx:162
 TSSystematicsManager.cxx:163
 TSSystematicsManager.cxx:164
 TSSystematicsManager.cxx:165
 TSSystematicsManager.cxx:166
 TSSystematicsManager.cxx:167
 TSSystematicsManager.cxx:168
 TSSystematicsManager.cxx:169
 TSSystematicsManager.cxx:170
 TSSystematicsManager.cxx:171
 TSSystematicsManager.cxx:172
 TSSystematicsManager.cxx:173
 TSSystematicsManager.cxx:174
 TSSystematicsManager.cxx:175
 TSSystematicsManager.cxx:176
 TSSystematicsManager.cxx:177
 TSSystematicsManager.cxx:178
 TSSystematicsManager.cxx:179
 TSSystematicsManager.cxx:180
 TSSystematicsManager.cxx:181
 TSSystematicsManager.cxx:182
 TSSystematicsManager.cxx:183
 TSSystematicsManager.cxx:184
 TSSystematicsManager.cxx:185
 TSSystematicsManager.cxx:186
 TSSystematicsManager.cxx:187
 TSSystematicsManager.cxx:188
 TSSystematicsManager.cxx:189
 TSSystematicsManager.cxx:190
 TSSystematicsManager.cxx:191
 TSSystematicsManager.cxx:192
 TSSystematicsManager.cxx:193
 TSSystematicsManager.cxx:194
 TSSystematicsManager.cxx:195
 TSSystematicsManager.cxx:196
 TSSystematicsManager.cxx:197