/*************************************************************************************
 * getKS: Searches through the histograms in the plotter output, adds the MC together
 *        for each field, and compares the MC with the Data histogram using a KS test
 *  input:  the main() arguments array
 *  output: writes to stdout the (human-readable) KS statistics of pairs of histograms
 *
 *  Structure-wise: this is fine, can be implemented into class easily.
 ***********************************/
void getKS(const char* argv[]) {
  //open the input TFile
  TFile *f = new TFile(argv[2]);
  f->cd();

  //get the filesystem information from the file
  TList *alokDirs = (TList*) f->GetListOfKeys();

  //loop through the directories in the input file
  for(int idir=0; alokDirs->At(idir-1) != alokDirs->Last(); idir++) {
    TDirectory *cDir  = (TDirectory*) f->Get(alokDirs->At(idir)->GetName());
    TList *alokHistos = (TList*)      cDir->GetListOfKeys();

    // create the MC histogram and start collecting relevant MC histograms
    // from the current directory
    TList *aloh   = new TList;
    // loop through keys (histograms) in current directory
    for(int ihisto=0; alokHistos->At(ihisto) != alokHistos->Last(); ihisto++) {
      if(TString(alokHistos->At(ihisto)->GetName()).Contains("MC8TeV")) {
        TH1F *cHisto = (TH1F*) cDir->Get(alokHistos->At(ihisto)->GetName());
        aloh->Add(cHisto);
      }
    }
 
    //merge the data histograms into one histogram
    TH1F *MCHisto = (TH1F*) (aloh->Last())->Clone(TString(cDir->GetName()) + TString("MCHisto"));
    aloh->RemoveLast();
    MCHisto->Merge(aloh);

    cout<<"-------------------- "<<cDir->GetName()<<" -----------------------"<<endl;
    //now create the data histogram and run the KS test
    TH1F *DataHisto = (TH1F*) cDir->Get(alokHistos->Last()->GetName());
    cout<<"  ---> KS Test: "<<cDir->GetName()<<" has probability "<<MCHisto->KolmogorovTest(DataHisto, "D")<<"\n"<<endl;
  }
}
/*************************************************************************************
 * createMFOutfile: moves the MLB distributions into an output file for use in 
 *                  R. Nally's MassFit.C code.
 *  input:  the main() arguments array
 *  output: writes to an output file the histograms, in a MassFit.C-readable format 
 *
 *  Structure-wise: can be implemented into class easily.
 ***********************************/
void createMFOutfile(const char* argv[]) {
  TFile *f = new TFile(argv[2]);

  //create the output file we'd like to write histograms to
  TFile *output = new TFile(outfileName, "RECREATE");
  
  //get the filesystem information from the file
  f->cd();
  TList *alokDirs = (TList*) f->GetListOfKeys();

  //create a list of "All" histograms and initialize (TODO)
  TList *allHists = new TList;

  //loop through the directories in the input file
  for(int idir=0; alokDirs->At(idir-1) != alokDirs->Last(); idir++) {
    //if it's not mlb, we don't care
    if(!TString(alokDirs->At(idir)->GetName()).Contains("_Mlb")) continue;
    
    //get the file directory information, its histograms
    TDirectory *cDir  = (TDirectory*) f->Get(alokDirs->At(idir)->GetName());
    TList *alokHistos = (TList*)      cDir->GetListOfKeys();

    //loop through the histograms in the current directory 
    for(int ihisto=0; alokHistos->At(ihisto-1) != alokHistos->Last(); ihisto++) {
      // don't consider the graph objects
      if(TString(alokHistos->At(ihisto)->GetName()).Contains("Graph_")) continue; 

      // clone the histogram, give it a new name
      TString cloneName = formatName(alokHistos->At(ihisto)->GetName(),nominalWidth);
      TH1F *thisto = (TH1F*) cDir->Get(alokHistos->At(ihisto)->GetName());
      TH1F *tclone = (TH1F*) thisto->Clone(cloneName);

      // open the outfile and write the histo in
      output->cd();
      TList *outkeys = (TList*) output->GetListOfKeys();

      // if the histogram already exists, add thisto to the existing one
      // messy, but removes the need for magic
      for(int iout=0; outkeys->At(iout-1) != outkeys->Last(); iout++) {
        if(outkeys->At(iout)->GetName() == cloneName) {
          cout<<" - found another histogram in output with name "<<cloneName<<endl;
          TH1F *theHisto = (TH1F*) output->Get(cloneName);
          cout<<" - got the same histogram from the output file"<<endl;
          TH1F *tHclone  = (TH1F*) theHisto->Clone(cloneName);
          cout<<" - cloned the histogram"<<endl;

          cout<<" - adding in clone"<<endl;
          tclone->Add(tHclone);

          cout<<" - deleting the original histogram from the output file"<<endl;
          output->Delete(cloneName + TString(";1"));
          cout<<" - deleted thing from output file"<<endl;
          cout<<" - tclone looks like "<<tclone<<endl;
        }
      }
      cout<<" - writing the tclone to file"<<endl;
      tclone->Write();

      // reopen the input root file and clean up
      f->cd();
      delete thisto;
      delete tclone;
    }
  }

  f->Close();
  output->cd();
  output->Close();

  // if we want to interpolate, start making more histograms
  if(interpolate) {
    // Have to reopen the outfile because ROOT is odd
    TFile *output2 = new TFile(outfileName, "UPDATE");
    output2->cd();

    std::pair<double,TString> maxPair = *moreFiles.begin();
    double maxWidth = maxPair.first;

    // check that it makes sense to interpolate with our settings
    if(maxWidth <= nominalWidth) {
      cout<<"\n\nERROR: Max width is less than or equal to the nominal width! Exiting."<<endl;
      exit(EXIT_FAILURE);
    }

    // open the input file and loop through the relevant directories
    TFile *maxFile = new TFile(maxPair.second);
    for(int i=0; i<lepsSize; i++) {
      // change directory and get the name of the folder we want to access
      maxFile->cd();
      char a[128];
      sprintf(a, "mlbwa_%s_Mlb", leps[i]);
      TDirectory *tDir = (TDirectory*) maxFile->Get(a);
      TList *alok = tDir->GetListOfKeys();

      // get the maxWidth histogram in this folder, clone and rename it
      TString maxHName = alok->First()->GetName();
      TString maxCloneName = formatName(maxHName, maxWidth);
      TH1F *maxHisto = (TH1F*) tDir->Get(maxHName);
      TH1F *maxClone = (TH1F*) maxHisto->Clone(maxCloneName);

      // write this max histogram to the outfile
      output2->cd();
      maxClone->Write();

      // get the corresponding nominal histogram from the outfile
      TH1F *nomHisto = (TH1F*) output2->Get(formatName(maxHName,nominalWidth));

      TCanvas *c = new TCanvas("");
      nomHisto->Draw();
      c->SaveAs(formatName(maxHName,nominalWidth)+TString(".pdf"));


      // for each interpolation, create a morphed histogram and write to outfile
      for(int i=interpolations; i>0; i--) {
        double tWidth = nominalWidth + i*(maxWidth - nominalWidth)/(interpolations+1);
        TString interpName = formatName(maxHName, tWidth);
        TH1F *interpHisto = (TH1F*) th1fmorph(interpName, interpName,nomHisto,maxHisto,
                                               nominalWidth,maxWidth,tWidth,nomHisto->Integral(),1);
        interpHisto->Write();
      }
    }

    maxFile->cd();
    maxFile->Close();
    output2->cd();
    output2->Close();

    // Otherwise, we want to collect signal histograms of different weights
  } else {
    // Have to reopen the outfile because ROOT is odd
    TFile *output2 = new TFile(outfileName, "UPDATE");
    output2->cd();

    // Loop through the additional files
    for(std::vector<std::pair<double, TString> >::const_iterator pf=moreFiles.begin();
                                                                 pf!=moreFiles.end();
                                                                 pf++) {

        // This is the current file and width
        TFile *curFile = new TFile(pf->second, "READ");
        double curWid  = pf->first;

        // Loop through lepton final states
        for(int i=0; i<lepsSize; i++) {
            curFile->cd();

            // Get the desired directory
            char dirName[128];
            sprintf(dirName, "mlbwa_%s_Mlb", leps[i]);
            TDirectory *curDir = (TDirectory*) curFile->Get(dirName);

            // Get the names of the first histogram in the directory
            //     (we don't want more than one additional signal histo per extra file)
            // Format it with the usual method
            TString histName   = TString(curDir->GetListOfKeys()->First()->GetName());
            TString cloneName  = formatName(histName,curWid);
            
            // Get the mlb histo
            TH1D *curHisto = (TH1D*) curDir->Get(histName)->Clone(cloneName);

            // Write to the outfile
            output2->cd();
            curHisto->Write();
        }

        curFile->Close();
    }

    output2->cd();
    output2->Close();
  }

}
/*************************************************************************************
 * getYields: Goes through each Counts histogram for every process and subprocess
 *            (i.e., EE & Drell-Yan, E & WJets, etc.) and properly adds the yields
 *            for data and MC. Reports ratios of Data:MC as well.
 *  input:  the main() arguments array
 *  output: writes to stdout the LaTeX-formatted table of yields (pipe the output to 
 *          save)
 ***********************************/
void getYields(const char* argv[]) { 
  //open mlbwidth output file
  TFile *f = new TFile(argv[2]);
  f->cd();

  //very inefficient, but for now it works
  //loop over all procs, leps and figure out the event counts
  for(int i=0; i<lepsSize; i++) {
    char a[128];
    sprintf(a, "mlbwa_%s_Count", leps[i]);
    TDirectory *tDir = (TDirectory*) f->Get(a);
    TList *alok = tDir->GetListOfKeys();

    for(int j=0; j<procsSize; j++) {
      for(int k=0; alok->At(k)->GetName() != alok->Last()->GetName(); k++) {
        if(TString(alok->At(k)->GetName()).Contains(TRegexp(procs[j]))) {
          char b[128];
          sprintf(b, "mlbwa_%s_Count/%s", leps[i], alok->At(k)->GetName());

          TH1F *h = (TH1F*) f->Get(b);
          eCounts[i][j] += h->GetSumOfWeights();
          eErrors[i][j] =  sqrt(pow(eErrors[i][j],2) + pow(h->GetBinError(2),2));

          delete h;
        }
      }
    }

    char d[128];
    sprintf(d, "mlbwa_%s_Count/%s", leps[i], alok->Last()->GetName());
    if(d == "") { exit(EXIT_FAILURE); }

    TH1F *tth = (TH1F*) f->Get(d);
    eCounts[i][procsSize] = tth->GetEntries();
    double integral = tth->GetSumOfWeights();
    eErrors[i][procsSize] = tth->GetBinError(2)*eCounts[i][procsSize]/integral;
    delete tth;
  }

  //Get a string to tell us how many columns we want (size leps + 1)
  char cols[] = "c";
  for(int i=0; i<lepsSize; i++) {
    strcat(cols, "c");
  }

  //print out LaTeX:
  //formatting
  cout<<"\\documentclass[12pt,a4paper,titlepage]{article}"<<endl;
  cout<<"\\usepackage[utf8]{inputenc}"<<endl;
  cout<<"\\usepackage{amsmath}"<<endl;
  cout<<"\\usepackage{amsfonts}"<<endl;
  cout<<"\\usepackage{amssymb}"<<endl;
  cout<<"\\usepackage{hyperref}\n\n"<<endl;
  cout<<"\\usepackage[margin=0.0025in]{geometry}"<<endl;
  cout<<"\\begin{document}"<<endl;
  cout<<"\\begin{tabular}{l|"<<cols<<"} \\\\"<<endl;

  //Print out the table header
  cout<<"Sample & ";
  for(int i=0; i<lepsLaTeXSize; i++) {
    cout<<lepsLaTeX[i]<<" & ";
  }
  cout<<"Sum \\\\ \\hline\\hline"<<endl;

  //Printing out the yields for each process
  for(int i=0; i<procsSize; i++) {
      cout<<yieldLaTeX[i]<<" & ";
    for(int j=0; j<lepsSize; j++) {
      cout<<GetLatex(j,i)<<" & ";
    }
    cout<<GetLatexSum(true,i)<<"\\\\"<<(i==procsSize-1 ? "\\hline" : "")<<endl;
  }
 
  //Print out the total MC yield
  cout<<"Total MC & ";
  for(int i=0; i<lepsSize; i++) {
    cout<<GetLatexSum(false,i)<<" & ";
  }
  cout<<GetLatexSum(false,-1)<<"\\\\"<<endl;

  //Print out the data yield
  cout<<"Data & ";
  for(int i=0; i<lepsSize; i++) {
    cout<<GetLatex(i,lepsSize+1)<<" & ";
  }
  cout<<GetLatexSum(true,lepsSize+1)<<"\\\\\\hline\\hline"<<endl;
  
  //Print out the data:MC ratio
  cout<<"Data/MC & ";
  for(int i=1; i<=procsSize;i++) {
    cout<<GetLatexRatio(i)<<(i==procsSize ? "" : " & ");
  }
  cout<<"\\\\"<<endl;

  //We did it! End the document
  cout<<"\\end{tabular}"<<endl;
  cout<<"\\end{document}"<<endl;
}