#include "QFramework/TQNFManualSetter.h"
#include "QFramework/TQStringUtils.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQUtils.h"
#include "QFramework/TQFolder.h"
#include "TMath.h"
#include "TRandom.h"
#include "QFramework/TQHistogramUtils.h"
#include "QFramework/TQNFChainloader.h"


#include <limits>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <fstream>

//#define _DEBUG_

#include "QFramework/TQLibrary.h"

////////////////////////////////////////////////////////////////////////////////////////////////
//
// TQNFManualSetter
//
// This class allows to manually set a normalization scale factor (NF).
// While, in principle, this class can be used on its own, it is highly recommended
// to use the TQNFChainloader instead. An example for a configuration to run the 
// TQNFManualSetter via the TQNFChainloader is provided in the HWWlvlv2015 package
// under HWWlvlv2015/share/normalization/example.cfg
////////////////////////////////////////////////////////////////////////////////////////////////

ClassImp(TQNFManualSetter)


TQNFManualSetter::TQNFManualSetter(TQSampleFolder* f):
TQNFBase("TQNFManual"),
  status(-999)
{
  // default constructor taking base sample folder
  this->setSampleFolder(f);
}

TQNFManualSetter::TQNFManualSetter(TQSampleDataReader* rd):
  TQNFBase("TQNFManual"),
  status(-999)
{
  // default constructor taking base sample folder
  this->setReader(rd);
}

TQNFManualSetter::~TQNFManualSetter(){
  // default destructor, cleaning up all pointer fields
  this->finalize();
  this->clear();
}

int TQNFManualSetter::deployNF(const TString& name, const TString& cutName, TQFolder* config) {
  std::vector<TString> vecStart;
  vecStart.push_back(cutName);
  return this->deployNF(name, vecStart, std::vector<TString>(), config);
}

int TQNFManualSetter::deployNF(const TString& name, const std::vector<TString>& startAtCutNames, const std::vector<TString>& stopAtCutNames, TQFolder* config, bool applyToStopCut){
  // deploys a selected NF in all known locations
  // stop if this cut is an point of tree of cuts on which to apply the NFs
  if (!config) {
    ERRORclass("Invalid pointer to configuration object!");
    return -1;
  }

  if(!this->success()){
    WARNclassargs(TQStringUtils::concat(3,name.Data(),TQListUtils::makeCSV(startAtCutNames).Data(),(config->getTagBoolDefault("overwrite",true) ? "true":"false")),"cannot deploy NF, no results available, status is %d!",this->status);
    return -1;
  }
  /*
  bool last = false;
  for (size_t i=0; i<stopAtCutNames.size(); ++i) {
    if (TQStringUtils::matches(cutName, stopAtCutNames[i])) {
      last = true;
      break;
    }
  }
  */
  //@tag:[overwrite] This (sub-folder) argument tag determines if the result of the calculator replaces existing values or if it is multiplied with the previously existing value. Default: true
  bool overwrite = config->getTagBoolDefault("overwrite",true);
  DEBUGclass("deploying NF for %s (overwrite=%d)",name.Data(),overwrite?1:0);
  // get the NF
  //@tag:[value,uncertainty] These (sub-folder) argument tags determine the value and the uncertainty of the NF being set (or modified, see "overwrite")
  double nf = config->getTagDoubleDefault("value",1.);
  double sigma = config->getTagDoubleDefault("uncertainty",0.);
  //@tag:[simpleScaleUncertainty] This (sub-folder) argument tag directs the NF machinery to propagate NFs as if they're uncorrelated, bypassing the need to do toy experiments and preserving the exact value of the NF and uncertainty as specified by the user
  double simpleScaleUncertainty = config->getTagBoolDefault("simpleScaleUncertainty", false);
  if (!simpleScaleUncertainty && ! (iterationNumber < 0)) {
    double variation = this->chainLoader->getRelVariation(TQStringUtils::concat(3,"NFManualSetter::",config->getPath().Data(),config->getName().Data()),nf,sigma); //we are using a random variation to propagate the uncertainty of manually set NFs assuming no correlation to anything else. 
    nf *=variation;
  }
  int retval = 0;
  
  TString readScheme;
  bool hasReadScheme = config->getTagString("readScaleScheme",readScheme);

    if (name.IsNull()) {
      ERRORclass("No target path given for config %s",config->getName().Data());
      return -1;
    }
    // set the NF according to the desired scale scheme(s)
    //@tag:[writeScaleScheme] This (sub-folder) argument tag determines the list of scale schemes the results of the NF calculation are written to. Default: ".default"
    std::vector<TString> writeScaleSchemes = config->getTagVString("writeScaleScheme");
    if(writeScaleSchemes.size() < 1){
      writeScaleSchemes.push_back(config->getTagStringDefault("writeScaleScheme",".default"));
    }
    std::vector<TString> targets = this->getTargetCuts(startAtCutNames,stopAtCutNames,applyToStopCut);
    //---------------------------------------------
    for (size_t c=0; c<targets.size(); ++c) {
      TString cutName = targets.at(c);
      TQSampleFolderIterator sItr(this->fReader->getListOfSampleFolders(name),true);
      while(sItr.hasNext()){
        TQSampleFolder* s = sItr.readNext();
        if(!s) continue;
        double readFactor = 1.;
        double readSigma = 0.;
        if (hasReadScheme) {
          if (!s->getScaleFactor(readScheme+":"+cutName,readFactor,readSigma,false)) {
            WARNclass("Failed to read scheme '%s' at cut '%s'",readScheme.Data(),cutName.Data());
            readFactor = 1.;
            readSigma = 0.;
          }
        }
        for(size_t k=0; k<writeScaleSchemes.size(); k++){
          int n = s->setScaleFactor(writeScaleSchemes[k]+":"+cutName+(overwrite>0?"":"<<"), nf*readFactor,sqrt(pow(sigma*readFactor,2) + pow(readSigma*nf,2)) );
          #ifdef _DEBUG_
          if (s->getFolder(".scalefactors")) s->getFolder(".scalefactors")->print();
          #endif
          if(n == 0){
            ERRORclass("unable to set scale factor for cut '%s' on path '%s' with scheme '%s'",cutName.Data(),s->getPath().Data(),writeScaleSchemes[k].Data());
          }
          //keep track where a NF has been written to as required by TQNFBase for use in TQNFChainloader
          this->addNFPath(s->getPath(),cutName,writeScaleSchemes[k]);
          retval += n;
        } 
      }
       
      // if the info folder is set and valid, we should keep track of all the processes that have NFs applied
      if(this->infoFolder){
        // get the folder which contains the list of processes for which we have NFs
        //@tag:[nfListPattern] This object tag determines the format how the existence of NFs for the target paths/cuts is written to the info folder (if present). Default: ".cut.%s+"
        TQFolder * sfProcessList = this->infoFolder->getFolder(TString::Format(this->getTagStringDefault("nfListPattern",".cut.%s+").Data(),cutName.Data()));
        // get the sample folder which contains the samples for this process
        TList* sflist = this->fReader->getListOfSampleFolders(name);
        TQSampleFolder * processSampleFolder = ( sflist && sflist->GetEntries() > 0 ) ? (TQSampleFolder*)(sflist->First()) : NULL;
        if(sflist) delete sflist;
        // retrieve the correct title of the process from this folder
        // if there is no process title set, we will use the process name instead
        TString processTitle = name;
        if (processSampleFolder)
          //@tag:[processTitleKey] This object tag determines the name of the process tag used to retrieve the process title from. Default: "style.default.title".
          processSampleFolder->getTagString(this->getTagStringDefault("processTitleKey","style.default.title"), processTitle);
        // after we have aquired all necessary information, we add a new entry 
        // to the list of processes to which NFs have been applied
        sfProcessList->setTagString(TQFolder::makeValidIdentifier(processTitle),processTitle);
      }
    }
    //---------------------------
  /*
  // if no recursion was required, we can stop here
  if(stopAtCutNames.size() == 0 || !this->cutInfoFolder || last)
    return retval;
  // if stopAtCutNames is set, we need to recurse over the cut structure
  // therefore, we first need to find out how the cuts are structured
  */
  //TList * cuts = this->cutInfoFolder->getListOfFolders(TString::Format("*/%s/?",cutName.Data()));
  /*if(!cuts) return retval;
  TQIterator itr(cuts,true);
  // iterate over all the cuts below the one we are investigating now
  while(itr.hasNext()){
    TQFolder* f = dynamic_cast<TQFolder*>(itr.readNext());
    if(!f) continue;
    // and deploy NFs at the corresponding cuts
    retval += this->deployNF(name,f->GetName(),stopAtCutNames,config);
  }
  */
  return retval;
}

int TQNFManualSetter::deployResult(const std::vector<TString>& startAtCutNames,  const std::vector<TString>& stopAtCutNames, int overwrite, bool applyToStopCut){
  // The arguments are ignored, they are just there to comply with TQNFBase requirements. The individual
  // start/stop cuts and overwrite are read from the sub configs.
  if(!this->success()){
    WARNclassargs(TQStringUtils::concat(3,TQListUtils::makeCSV(startAtCutNames).Data(),TQStringUtils::concat(stopAtCutNames).Data(),TQStringUtils::getStringFromBool(overwrite).Data(),TQStringUtils::getStringFromBool(applyToStopCut).Data()),"cannot deploy NFs, no results available, status is %d!",this->status);
    return -1;
  }
  // deploys all NFs in all known locations
  int retval = 0;
  for(int i=0; i<configs->GetEntries(); i++){
    TQFolder* config = dynamic_cast<TQFolder*> (configs->At(i));
    //@tag:[path,applyToCut,stopAtCut] These sub-folder argument tags determine at which paths and cuts the NF is deployed. "stopAtCut" and applyToCut support list context.
    retval += this->deployNF(config->getTagStringDefault("path",""), config->getTagVString("applyToCut"), config->getTagVString("stopAtCut"), config);
  }
  return retval;
}

void TQNFManualSetter::clear(){
  // clear all names, paths and results
  this->initialized = false;
  this->status = -999;
} 


bool TQNFManualSetter::finalizeSelf(){
  return true;
}

bool TQNFManualSetter::initializeSelf(){
  // initialize the NF Calculator
  // - initializes the data histogram
  // - initializeds the mc histograms
  // will set the initialize flag to true
  // further calls of initialize will have no effect
  // until clear is called
  if(!this->fReader){
    return false;
  }
    
  this->status = 0;
  return true;
}

int TQNFManualSetter::getStatus(){
  // retrieve the status
  return this->status;
}

TString TQNFManualSetter::getStatusMessage(){
  // decode the integer status code
  switch(this->status){
  case -999:
    return "uninitialized";
  case -10:
    return "error during initialization";
  case 0:
    return "all OK";
  default:
    return "unkown error";
  }
}

void TQNFManualSetter::printStatus(){
  // print the status
  INFOclass("current status of instance '%s' is '%d': %s",this->GetName(),(int)(this->status),this->getStatusMessage().Data());
}

int TQNFManualSetter::execute(int itrNumber) {
  //start calculation
  this->iterationNumber = itrNumber;
  return 0; //unless sth. went wrong, then possibly return sth. else
}

bool TQNFManualSetter::success(){
  // return true if calculation was successful
  // false otherwise
  if(this->initialized && (this->status == 0))
    return true;
  return false;
}

bool TQNFManualSetter::readConfiguration(TQFolder* f){ 
  // Sets the configuration folder. The folder is expected to contain subfolders
  // having the following tags applied (* = required)
  // ...to be written
  if(!f) return false;
  this->configs = f->getListOfFolders("?");
  if(!configs || configs->GetEntries()<1) {
    ERRORclass("Invalid configuration for TQNFManualSetter");
    return false;
  }
  this->initialized = true;
  this->status = 0;
  
  return true;
}

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