#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <iterator>

#include "RooNLLVar.h"
#include "RooAbsPdf.h"
#include "RooDataSet.h"
#include "RooStats/AsymptoticCalculator.h"
#include "RooStats/HypoTestInverter.h"
#include "RooStats/HypoTestPlot.h"
#include "RooStats/HypoTestInverterPlot.h"
#include "TCanvas.h"

#include "QFramework/TQPathManager.h"
#include "QFramework/TQStringUtils.h"
#include "QFramework/TQUtils.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQLibrary.h"

#include "SFramework/TSLimitCalculator.h"
#include "SFramework/TSUtils.h"

ClassImp(TSLimitCalculator)

//__________________________________________________________________________________|___________

TSLimitCalculator::TSLimitCalculator() : TSStatisticsCalculator("TSLimitCalculator") {
}


//__________________________________________________________________________________|___________

TSLimitCalculator::TSLimitCalculator(RooWorkspace * ws) : TSStatisticsCalculator("TSLimitCalculator",ws) {
}


//__________________________________________________________________________________|___________

TSLimitCalculator::~TSLimitCalculator() {
}


//__________________________________________________________________________________|___________

void TSLimitCalculator::info(TString message) {

  std::cout << "SFramework/TSLimitCalculator: " << message.Data() << std::endl;
}

//__________________________________________________________________________________|___________
                 
void TSLimitCalculator::readSnapshot(TQFolder * config, RooArgSet& snsh) {
  TQTaggableIterator itr(config->getListOfKeys());
  while(itr.hasNext()){
    TObject* tag = itr.readNext();
    if(!tag) continue;
    double val = config->getTagDoubleDefault(tag->GetName(),0.);
    RooRealVar* var = fWorkspace->var(tag->GetName());
    if(!var){
      warn(TString::Format("unable to find parameter '%s'",tag->GetName()));
      continue;
    }
    var->setVal(val);
    snsh.add(*var);
  }
}

//__________________________________________________________________________________|___________
                 
TQFolder * TSLimitCalculator::runCalculation(TQFolder * config) {

  if (!fWorkspace || !fModelConfig) {
    return NULL;
  }
  
  // load nominal snapshot
  TString snapshotName = config->getTagStringDefault("fit.initSnapshot","SnSh_AllVars_Nominal");
  if(!fWorkspace->loadSnapshot(snapshotName)){
    error(TString::Format("unable to load snapshot '%s'",snapshotName.Data()));
    return NULL;
  }

  RooArgSet   	nuis(*fModelConfig->GetNuisanceParameters());
  TString dataName = config->getTagStringDefault("dataset","asimovData_1");
	RooDataSet *	data		= (RooDataSet*)fWorkspace->data(dataName);
  if (!data) {
    error(TString::Format("unable to obtain dataset '%s'!",dataName.Data()));
    return NULL;
  }

  TQFolder* parameters = config->getFolder("Parameters");
  if(!parameters){
    error("no parameters given, please specifiy in 'Parameters'");
    return NULL;
  }
  
  RooStats::ModelConfig* bModel = fModelConfig->Clone();
  TSUtils::applySettings(parameters,fWorkspace->allVars(),bModel);
  TQFolder* h0 = parameters->getFolder("H0");
  if(h0){
    RooArgSet snapshot;
    this->readSnapshot(h0,snapshot);
    bModel->SetSnapshot(snapshot);
  } else {
    warn("no parameters given for Null Hypothesis, please specifiy in 'Parameters/H0'");
  }
  RooStats::ModelConfig* sbModel = fModelConfig->Clone();
  TSUtils::applySettings(parameters,fWorkspace->allVars(),sbModel);
  TQFolder* h1 = parameters->getFolder("H1");
  if(h1){
    RooArgSet snapshot;
    this->readSnapshot(h1,snapshot);
    sbModel->SetSnapshot(snapshot);
  } else {
    warn("no parameters given for Null Hypothesis, please specifiy in 'Parameters/H1'");
  }

  bool oneSided = config->getTagBoolDefault("oneSided",true);
  bool useCLs = config->getTagBoolDefault("useCLs",true);
  double confidenceLevel = config->getTagDoubleDefault("confidenceLevel",.9);

  TString outfile;
  bool redirect=config->getTag("fit.logToFile",outfile);
  if(redirect){
    TString fname = config->replaceInText(outfile);
    fname = TQPathManager::getPathManager()->getTargetPath(fname);
    TQUtils::ensureDirectoryForFile(fname);
    info(TString::Format("writing log to '%s'",fname.Data()));
    TQLibrary::redirect(fname,true);
  }  

  RooStats::AsymptoticCalculator  asympCalc(*data, *bModel, *sbModel);
  asympCalc.SetOneSided(oneSided);
  RooStats::HypoTestInverter inverter(asympCalc);
  inverter.SetConfidenceLevel(confidenceLevel);
  inverter.UseCLs(useCLs);

  inverter.SetVerbose(config->getTagBoolDefault("verbose",false));

  if(config->getTagBoolDefault("auto",false)){
    inverter.SetAutoScan();
  } else {
    int nPoints = config->getTagIntegerDefault("nPoints",50);
    double xmin = config->getTagDoubleDefault("poi.min",0.);
    double xmax = config->getTagDoubleDefault("poi.max",6.);
    inverter.SetFixedScan(nPoints,xmin,xmax);
  }

  RooStats::HypoTestInverterResult* htresult =  inverter.GetInterval();
  
  if(redirect){
    TQLibrary::restore();
  }

  TQFolder* result = new TQFolder("Limit");
  result->addFolder(config->copy(".config")); // bookkeeping

  result->setTagDouble("upper",htresult->UpperLimit());
  result->setTagDouble("lower",htresult->LowerLimit());

  result->setTagDouble("exp_upper_med",htresult->GetExpectedUpperLimit(0));
  result->setTagDouble("exp_upper_p1s",htresult->GetExpectedUpperLimit(+1));
  result->setTagDouble("exp_upper_m1s",htresult->GetExpectedUpperLimit(-1));
  result->setTagDouble("exp_upper_p2s",htresult->GetExpectedUpperLimit(+2));
  result->setTagDouble("exp_upper_m2s",htresult->GetExpectedUpperLimit(-2));
  result->setTagDouble("exp_lower_med",htresult->GetExpectedLowerLimit(0));
  result->setTagDouble("exp_lower_p1s",htresult->GetExpectedLowerLimit(+1));
  result->setTagDouble("exp_lower_m1s",htresult->GetExpectedLowerLimit(-1));
  result->setTagDouble("exp_lower_p2s",htresult->GetExpectedLowerLimit(+2));
  result->setTagDouble("exp_lower_m2s",htresult->GetExpectedLowerLimit(-2));

  for(int i=0; i<htresult->ArraySize(); ++i){
    result->setTagDouble(TString::Format("CLb.%d",          i),htresult->CLb          (i));
    result->setTagDouble(TString::Format("CLbError.%d",     i),htresult->CLbError     (i));
    result->setTagDouble(TString::Format("CLs.%d",          i),htresult->CLs          (i));
    result->setTagDouble(TString::Format("CLsError.%d",     i),htresult->CLsError     (i));
    result->setTagDouble(TString::Format("CLsplusb.%d",     i),htresult->CLsplusb     (i));
    result->setTagDouble(TString::Format("CLsplusbError.%d",i),htresult->CLsplusbError(i));
  }  

  // Make test scan plot
  TString writeplot;
  if(config->getTagString("plot",writeplot)){
    RooStats::HypoTestInverterPlot *plot = new RooStats::HypoTestInverterPlot("HTI_Result_Plot", "95% CLs Scan Result", htresult);
    TCanvas *c1 = new TCanvas("Test Scan");
    c1->SetLogy(false);
    plot->Draw("CLb 2CL"); // plot all and Clb
    c1->SaveAs(writeplot);
    delete plot;
    delete c1;
  }
  
  delete sbModel;
  delete bModel;
  delete htresult;

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