#include "QFramework/TQHistComparer.h"
#include "QFramework/TQLibrary.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQROOTPlotter.h"
#include "TFile.h"
#include "TCanvas.h"
#include "THStack.h"
#include <algorithm>

////////////////////////////////////////////////////////////////////////////////////////////////
//
// TQHistComparer:
//
// TODO: write documentation
//
////////////////////////////////////////////////////////////////////////////////////////////////

ClassImp(TQHistComparer)

TQHistComparer::TQHistComparer(TQSampleFolder* sf) : TQPresenter(sf) {
  // constructor using a sample folder
  fHists = new TObjArray();
  fSummaryHists = new TObjArray();
  fDistNames = new TObjArray();
}

TQHistComparer::TQHistComparer(TQSampleDataReader* reader) : TQPresenter(reader) {
  // constructor using a sample data reader
  fHists = new TObjArray();
  fDistNames = new TObjArray();
}

bool TQHistComparer::resetDistributions()
{
  this->fDistNames->Clear();
  return true;
}

void TQHistComparer::addDistribution(TString name, TString title)
{
  if (title == "")
    title = name;
  TQNamedTaggable* dist = new TQNamedTaggable(name);
  dist->setTagString(".title",title);
  dist->setTagString(".name",name);
  this->fDistNames->Add(dist);
}


bool TQHistComparer::writeToFile(const TString& filename, const TString& filename_summary, const TString& tags) {
  // write the plot to a file
  TQTaggable tmp(tags);
  return this->writeToFile(filename, filename_summary, tmp);
}

bool TQHistComparer::writeToFile(const TString& filename, const TString& filename_summary, TQTaggable& tags){
  // write the plot to a file
  tags.importTags(this);
  if (this->fProcesses->GetEntries() != 2)
    {
      ERRORclass("TQHistComparer needs exactly 2 processes but found %i !",this->fProcesses->GetEntries());
      return false;
    }
  if (this->fDistNames->GetEntries() < 1)
    {
      ERRORclass("TQHistComparer needs at least one distribution");
      return false;
    }
  if (this->fCuts->GetEntries() < 1)
    {
      ERRORclass("TQHistComparer needs at least one cut");
      return false;
    }
  TH1 * h1, *h2;
  h1 = h2 = 0;
  TQTaggableIterator cuts(this->fCuts);
  TQTaggableIterator processes(this->fProcesses);
  TQNamedTaggable *process = 0;
  int i = 0;
  TQTaggableIterator dists(this->fDistNames);
  int bin;
  std::vector<float> *vals = new std::vector<float>;
  while(cuts.hasNext()){
    bin=0;
    TQNamedTaggable* cut = cuts.readNext();
    TString name = cut->getName();
    TH1D *h = new TH1D(name,name,this->fDistNames->GetEntries(),-0.5,fDistNames->GetEntries()-0.5);
    TH1D *h_sum = 0;
    dists.reset();

    while(dists.hasNext()){
      ++bin;
      TQNamedTaggable *dist = dists.readNext();
      //@tag: [.title] Distribution tag used to set the lable of the corresponding bin. Default: "none"
      h->GetXaxis()->SetBinLabel(bin,dist->getTagStringDefault(".title","none"));
      i=0;
      processes.reset();
      while (processes.hasNext()){
        process = processes.readNext();
        if (i==0)
          h1 = this->fReader->getHistogram(process->getName(),cut->getTagStringDefault(".name","non")+"/"+dist->getTagStringDefault(".name","non"));
        else
          h2 = this->fReader->getHistogram(process->getName(),cut->getTagStringDefault(".name","non")+"/"+dist->getTagStringDefault(".name","non"));
        ++i;
      }
      if (h1==0 || h2 == 0)
        {
          ERRORclass("Couldn't find both %s histograms for cut %s ", dist->getName().Data(),cut->getName().Data());
          return false;
        }
      double val = -999;
      if(tags.getTagBoolDefault("useChi2",false))
        val = h1->Chi2Test(h2,"UW CHI2/NDF");
      else
        val = h1->KolmogorovTest(h2);
      h->SetBinContent(bin,val);
      vals->push_back(val);

 
      INFOclass("Cut: %s , distribution: %s - %f",cut->getName().Data(),dist->getName().Data(), val);
    }
    if(tags.getTagBoolDefault("useChi2",false))
      h_sum = new TH1D(name+"_summary",name+"_summary",this->fDistNames->GetEntries()/2,0,*(std::max_element(vals->begin(),vals->end()))*1.1);
    else
      h_sum = new TH1D(name+"_summary",name+"_summary",this->fDistNames->GetEntries()/2,0,1);
    for (unsigned int i=0; i<vals->size(); ++i)
      h_sum->Fill(vals->at(i));
    vals->clear();
    fSummaryHists->Add(h_sum);
    fHists->Add(h);
  }
  TQTH1Iterator itr(fHists->MakeIterator(kIterForward),true);
  TFile * of = 0;
  TCanvas *c1 = new TCanvas("c1","c1",this->fDistNames->GetEntries()*60,600);
  THStack *s = new THStack("s","stack");
  if (filename.Contains("root"))
    {
      of = new TFile(filename,"RECREATE");
    }
  i = 0;
  while(itr.hasNext() != 0)
    {
      TH1 *h = itr.readNext();
      h->SetLineColor(kRed+i*4);
      h->SetLineWidth(2);
      if (of)
        h->Write();
      else
        {
          TQROOTPlotter::setStyleAtlas();
          s->Add(h);
        }
      ++i;
    }
  if (of)
    of->Close();
  else
    {
      s->Draw("nostack");
      if(tags.getTagBoolDefault("useChi2",false))
        s->GetHistogram()->GetYaxis()->SetTitle("#chi^{2}/ndf");
      else
        s->GetHistogram()->GetYaxis()->SetTitle("KS");
      s->GetHistogram()->GetYaxis()->SetTitleOffset(0.7);
      s->Draw("nostacksame");
      this->makeLegend(tags,fHists)->Draw("same");
      c1->SaveAs(filename);
    }

  TQTH1Iterator itr2(fSummaryHists->MakeIterator(kIterForward),true);
  TCanvas *c2 = new TCanvas("c2","c2",800,600);
  THStack *s2 = new THStack("s2","stack");
  i = 0;
  while(itr2.hasNext() != 0)
    {
      TH1 *h = itr2.readNext();
      h->SetLineColor(kRed+i*4);
      h->SetLineWidth(2);
      if (of)
        h->Write();
      else
        {
          TQROOTPlotter::setStyleAtlas();
          s2->Add(h);
        }
      ++i;
    }
  if (of)
    of->Close();
  else
    {
      s2->Draw("nostack");
      if(tags.getTagBoolDefault("useChi2",false))
        s2->GetHistogram()->GetXaxis()->SetTitle("#chi^{2}/ndf");
      else
        s2->GetHistogram()->GetXaxis()->SetTitle("KS");
      s2->GetHistogram()->GetYaxis()->SetTitle("Entries");
      s2->Draw("nostacksame");
      this->makeLegend(tags,fHists)->Draw("same");
      c2->SaveAs(filename_summary);
    }
  return true;
}
 
TLegend * TQHistComparer::makeLegend(TQTaggable& tags, TObjArray* histos){
  int nLegendCols = tags.getTagIntegerDefault ("style.nLegendCols",1);
  double legendHeight = tags.getTagDoubleDefault ("style.legendHeight",1. );

  /* the nominal coordinates of the legend */
  double x1 = tags.getTagDoubleDefault("legend.xMin",0.9);
  double y1 = tags.getTagDoubleDefault("legend.yMin",0.70) - tags.getTagDoubleDefault("geometry.main.additionalTopMargin",0.);
  double x2 = tags.getTagDoubleDefault("legend.xMax",0.50);
  double y2 = tags.getTagDoubleDefault("legend.yMax",0.92) - tags.getTagDoubleDefault("geometry.main.additionalTopMargin",0.);

  /* ===== scale the hight of the legend depending on the number of entries ===== */
  /* calculate the number of entries */
  int nEntries = histos->GetEntries();

  /* calculate the height of the legend */
  int nLegendRows = (int)nEntries / nLegendCols + ((nEntries % nLegendCols) > 0 ? 1 : 0);
  legendHeight *= (y2 - y1) * (double)nLegendRows / 5.;

  /* set the height of the legend */
  y1 = y2 - legendHeight;
  /* create the legend and set some attributes */
  double tmpx1 = x1; 
  double tmpx2 = x2; 
  double tmpy1 = y1; 
  double tmpy2 = y2; 
 
  TLegend* legend = new TLegend(tmpx1, tmpy1, tmpx2, tmpy2);
  legend->SetBorderSize(0);
  legend->SetNColumns(nLegendCols);
  double textsize = tags.getTagDoubleDefault("legend.textSize",0.032);
  legend->SetTextSize(textsize);
 
  TQTH1Iterator itr(fHists->MakeIterator(kIterForward),true);
  while(itr.hasNext() != 0)
    {
      TH1 *h = itr.readNext();
      legend->AddEntry(h,h->GetName(),"l");
    }
  return legend;
}
 TQHistComparer.cxx:1
 TQHistComparer.cxx:2
 TQHistComparer.cxx:3
 TQHistComparer.cxx:4
 TQHistComparer.cxx:5
 TQHistComparer.cxx:6
 TQHistComparer.cxx:7
 TQHistComparer.cxx:8
 TQHistComparer.cxx:9
 TQHistComparer.cxx:10
 TQHistComparer.cxx:11
 TQHistComparer.cxx:12
 TQHistComparer.cxx:13
 TQHistComparer.cxx:14
 TQHistComparer.cxx:15
 TQHistComparer.cxx:16
 TQHistComparer.cxx:17
 TQHistComparer.cxx:18
 TQHistComparer.cxx:19
 TQHistComparer.cxx:20
 TQHistComparer.cxx:21
 TQHistComparer.cxx:22
 TQHistComparer.cxx:23
 TQHistComparer.cxx:24
 TQHistComparer.cxx:25
 TQHistComparer.cxx:26
 TQHistComparer.cxx:27
 TQHistComparer.cxx:28
 TQHistComparer.cxx:29
 TQHistComparer.cxx:30
 TQHistComparer.cxx:31
 TQHistComparer.cxx:32
 TQHistComparer.cxx:33
 TQHistComparer.cxx:34
 TQHistComparer.cxx:35
 TQHistComparer.cxx:36
 TQHistComparer.cxx:37
 TQHistComparer.cxx:38
 TQHistComparer.cxx:39
 TQHistComparer.cxx:40
 TQHistComparer.cxx:41
 TQHistComparer.cxx:42
 TQHistComparer.cxx:43
 TQHistComparer.cxx:44
 TQHistComparer.cxx:45
 TQHistComparer.cxx:46
 TQHistComparer.cxx:47
 TQHistComparer.cxx:48
 TQHistComparer.cxx:49
 TQHistComparer.cxx:50
 TQHistComparer.cxx:51
 TQHistComparer.cxx:52
 TQHistComparer.cxx:53
 TQHistComparer.cxx:54
 TQHistComparer.cxx:55
 TQHistComparer.cxx:56
 TQHistComparer.cxx:57
 TQHistComparer.cxx:58
 TQHistComparer.cxx:59
 TQHistComparer.cxx:60
 TQHistComparer.cxx:61
 TQHistComparer.cxx:62
 TQHistComparer.cxx:63
 TQHistComparer.cxx:64
 TQHistComparer.cxx:65
 TQHistComparer.cxx:66
 TQHistComparer.cxx:67
 TQHistComparer.cxx:68
 TQHistComparer.cxx:69
 TQHistComparer.cxx:70
 TQHistComparer.cxx:71
 TQHistComparer.cxx:72
 TQHistComparer.cxx:73
 TQHistComparer.cxx:74
 TQHistComparer.cxx:75
 TQHistComparer.cxx:76
 TQHistComparer.cxx:77
 TQHistComparer.cxx:78
 TQHistComparer.cxx:79
 TQHistComparer.cxx:80
 TQHistComparer.cxx:81
 TQHistComparer.cxx:82
 TQHistComparer.cxx:83
 TQHistComparer.cxx:84
 TQHistComparer.cxx:85
 TQHistComparer.cxx:86
 TQHistComparer.cxx:87
 TQHistComparer.cxx:88
 TQHistComparer.cxx:89
 TQHistComparer.cxx:90
 TQHistComparer.cxx:91
 TQHistComparer.cxx:92
 TQHistComparer.cxx:93
 TQHistComparer.cxx:94
 TQHistComparer.cxx:95
 TQHistComparer.cxx:96
 TQHistComparer.cxx:97
 TQHistComparer.cxx:98
 TQHistComparer.cxx:99
 TQHistComparer.cxx:100
 TQHistComparer.cxx:101
 TQHistComparer.cxx:102
 TQHistComparer.cxx:103
 TQHistComparer.cxx:104
 TQHistComparer.cxx:105
 TQHistComparer.cxx:106
 TQHistComparer.cxx:107
 TQHistComparer.cxx:108
 TQHistComparer.cxx:109
 TQHistComparer.cxx:110
 TQHistComparer.cxx:111
 TQHistComparer.cxx:112
 TQHistComparer.cxx:113
 TQHistComparer.cxx:114
 TQHistComparer.cxx:115
 TQHistComparer.cxx:116
 TQHistComparer.cxx:117
 TQHistComparer.cxx:118
 TQHistComparer.cxx:119
 TQHistComparer.cxx:120
 TQHistComparer.cxx:121
 TQHistComparer.cxx:122
 TQHistComparer.cxx:123
 TQHistComparer.cxx:124
 TQHistComparer.cxx:125
 TQHistComparer.cxx:126
 TQHistComparer.cxx:127
 TQHistComparer.cxx:128
 TQHistComparer.cxx:129
 TQHistComparer.cxx:130
 TQHistComparer.cxx:131
 TQHistComparer.cxx:132
 TQHistComparer.cxx:133
 TQHistComparer.cxx:134
 TQHistComparer.cxx:135
 TQHistComparer.cxx:136
 TQHistComparer.cxx:137
 TQHistComparer.cxx:138
 TQHistComparer.cxx:139
 TQHistComparer.cxx:140
 TQHistComparer.cxx:141
 TQHistComparer.cxx:142
 TQHistComparer.cxx:143
 TQHistComparer.cxx:144
 TQHistComparer.cxx:145
 TQHistComparer.cxx:146
 TQHistComparer.cxx:147
 TQHistComparer.cxx:148
 TQHistComparer.cxx:149
 TQHistComparer.cxx:150
 TQHistComparer.cxx:151
 TQHistComparer.cxx:152
 TQHistComparer.cxx:153
 TQHistComparer.cxx:154
 TQHistComparer.cxx:155
 TQHistComparer.cxx:156
 TQHistComparer.cxx:157
 TQHistComparer.cxx:158
 TQHistComparer.cxx:159
 TQHistComparer.cxx:160
 TQHistComparer.cxx:161
 TQHistComparer.cxx:162
 TQHistComparer.cxx:163
 TQHistComparer.cxx:164
 TQHistComparer.cxx:165
 TQHistComparer.cxx:166
 TQHistComparer.cxx:167
 TQHistComparer.cxx:168
 TQHistComparer.cxx:169
 TQHistComparer.cxx:170
 TQHistComparer.cxx:171
 TQHistComparer.cxx:172
 TQHistComparer.cxx:173
 TQHistComparer.cxx:174
 TQHistComparer.cxx:175
 TQHistComparer.cxx:176
 TQHistComparer.cxx:177
 TQHistComparer.cxx:178
 TQHistComparer.cxx:179
 TQHistComparer.cxx:180
 TQHistComparer.cxx:181
 TQHistComparer.cxx:182
 TQHistComparer.cxx:183
 TQHistComparer.cxx:184
 TQHistComparer.cxx:185
 TQHistComparer.cxx:186
 TQHistComparer.cxx:187
 TQHistComparer.cxx:188
 TQHistComparer.cxx:189
 TQHistComparer.cxx:190
 TQHistComparer.cxx:191
 TQHistComparer.cxx:192
 TQHistComparer.cxx:193
 TQHistComparer.cxx:194
 TQHistComparer.cxx:195
 TQHistComparer.cxx:196
 TQHistComparer.cxx:197
 TQHistComparer.cxx:198
 TQHistComparer.cxx:199
 TQHistComparer.cxx:200
 TQHistComparer.cxx:201
 TQHistComparer.cxx:202
 TQHistComparer.cxx:203
 TQHistComparer.cxx:204
 TQHistComparer.cxx:205
 TQHistComparer.cxx:206
 TQHistComparer.cxx:207
 TQHistComparer.cxx:208
 TQHistComparer.cxx:209
 TQHistComparer.cxx:210
 TQHistComparer.cxx:211
 TQHistComparer.cxx:212
 TQHistComparer.cxx:213
 TQHistComparer.cxx:214
 TQHistComparer.cxx:215
 TQHistComparer.cxx:216
 TQHistComparer.cxx:217
 TQHistComparer.cxx:218
 TQHistComparer.cxx:219
 TQHistComparer.cxx:220
 TQHistComparer.cxx:221
 TQHistComparer.cxx:222
 TQHistComparer.cxx:223
 TQHistComparer.cxx:224
 TQHistComparer.cxx:225
 TQHistComparer.cxx:226
 TQHistComparer.cxx:227
 TQHistComparer.cxx:228
 TQHistComparer.cxx:229
 TQHistComparer.cxx:230
 TQHistComparer.cxx:231
 TQHistComparer.cxx:232
 TQHistComparer.cxx:233
 TQHistComparer.cxx:234
 TQHistComparer.cxx:235
 TQHistComparer.cxx:236
 TQHistComparer.cxx:237
 TQHistComparer.cxx:238
 TQHistComparer.cxx:239
 TQHistComparer.cxx:240
 TQHistComparer.cxx:241
 TQHistComparer.cxx:242
 TQHistComparer.cxx:243
 TQHistComparer.cxx:244