#include "QFramework/TQNFUncertaintyScaler.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"

////////////////////////////////////////////////////////////////////////////////////////////////
//
// TQNFUncertaintyScaler
//
// work in progress
////////////////////////////////////////////////////////////////////////////////////////////////

ClassImp(TQNFUncertaintyScaler)


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

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

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

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


int TQNFUncertaintyScaler::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 (config->hasTag("relvalue") && config->hasTag("absvalue")) {
    WARNclass("Config folder %s has both value tags (\"relvalue\" and \"absvalue\"). This is ambiguous, defaulting to use \"relvalue\"!",config->GetName());
  } else if (!config->hasTag("relvalue") && !config->hasTag("absvalue")) {
    WARNclass("Config folder %s has no value tag (neither \"relvalue\" nor \"absvalue\").",config->GetName());
    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;
    }
  }
  */
  
  TString path = config->getTagStringDefault("path","");
  if (path.IsNull()) {
    WARNclassargs(TQStringUtils::concat(3,name.Data(),TQListUtils::makeCSV(startAtCutNames).Data(),(config->getTagBoolDefault("overwrite",true) ? "true":"false")),"cannot modify NF uncertainty, no path given!",this->status);
    return -1;
  }
  DEBUGclass("modifying NF unertainty for %s at {%s} ",name.Data(),TQListUtils::makeCSV(startAtCutNames).Data());
  
  int retval = 0;
  
  //this is duplicate code, "name" and "path" should contain the same data... 
  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)
  std::vector<TString> writeScaleSchemes = config->getTagVString("writeScaleScheme");
  std::vector<TString> tmp = config->getTagVString("scaleScheme");
  writeScaleSchemes.insert(writeScaleSchemes.end(),tmp.begin(),tmp.end());
  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;
      
      for(size_t k=0; k<writeScaleSchemes.size(); k++){
        TQCounter* counter = s->getScaleFactorCounterInternal(cutName,writeScaleSchemes[k]); //this returns the internal pointer, so handle with care!
        if (!counter){
          ERRORclass("unable to modify scale factor uncertainty for cut '%s' on path '%s' with scheme '%s'",cutName.Data(),s->getPath().Data(),writeScaleSchemes[k].Data());
        } 
        double modifier;
        if (config->getTagDouble("relvalue",modifier)) {
          counter->setError(counter->getError()+counter->getCounter()*modifier);
        } else if (config->getTagDouble("absvalue",modifier)){
          counter->setError(counter->getError()+modifier);
        }
        retval++;
      } 
    }
  }
  /*
  // 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 TQNFUncertaintyScaler::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));
    retval += this->deployNF(config->getTagStringDefault("path",""), config->getTagVString("applyToCut"), config->getTagVString("stopAtCut"), config);
  }
  return retval;
}

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


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

bool TQNFUncertaintyScaler::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 TQNFUncertaintyScaler::getStatus(){
  // retrieve the status
  return this->status;
}

TString TQNFUncertaintyScaler::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 TQNFUncertaintyScaler::printStatus(){
  // print the status
  INFOclass("current status of instance '%s' is '%d': %s",this->GetName(),(int)(this->status),this->getStatusMessage().Data());
}

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

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

bool TQNFUncertaintyScaler::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 TQNFUncertaintyScaler");
    return false;
  }
  this->initialized = true;
  this->status = 0;
  
  return true;
}

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