#include "QFramework/TQPCAAnalysisJob.h"
#include "QFramework/TQCompiledCut.h"
#include "QFramework/TQAnalysisJob.h"
#include "QFramework/TQCounter.h"
#include "QFramework/TQSample.h"
#include "QFramework/TQUtils.h"

#include <QFramework/TQLibrary.h>

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

////////////////////////////////////////////////////////////////////////////////////////////////
//
// TQPCAAnalysisJob
//
// The TQPCAAnalysisJob allow to schedule the creation of PCA objects
// for each and every sample visitied during the analysis
// This information can later be retrieved from a .pca subfolder 
// of the analysis root file folder structure
// to perform a linear decorrelation of a set of variables via a PCA
//
////////////////////////////////////////////////////////////////////////////////////////////////

ClassImp(TQPCAAnalysisJob)

//______________________________________________________________________________________________

TQPCAAnalysisJob::TQPCAAnalysisJob() : 
TQAnalysisJob("PCA"), 
  weightCutoff(std::numeric_limits<double>::epsilon())
{
  // default constructor
}


//______________________________________________________________________________________________

TQPCAAnalysisJob::TQPCAAnalysisJob(TString name_) : 
  TQAnalysisJob(name_),
  weightCutoff(std::numeric_limits<double>::epsilon())
{
  // create a new TQPCAAnalysisJob
  // take care of choosing an appropriate name (default "PCA")
  // as this will determine the name under which the resulting grids
  // will be saved in the folder structure

}

//______________________________________________________________________________________________

TQPCAAnalysisJob::TQPCAAnalysisJob(TQPCAAnalysisJob &job) : 
  TQAnalysisJob(job.GetName()),
  poolAt(job.poolAt),
  weightCutoff(job.weightCutoff)
{
  // copy constructor
  for(size_t i=0; i<job.fObservables.size(); i++){
    this->fObservables.push_back(fObservables[i]);
  }
}

//______________________________________________________________________________________________

TQPCAAnalysisJob::TQPCAAnalysisJob(TQPCAAnalysisJob *job) : 
  TQAnalysisJob(job ? job->GetName() : "PCA"),
  poolAt(job ? job->poolAt : NULL),
  weightCutoff(job ? job->weightCutoff : std::numeric_limits<double>::epsilon())
{
  // copy constructor
  if(job){
    for(size_t i=0; i<job->fObservables.size(); i++){
      this->fObservables.push_back(fObservables[i]);
    }
  }
}

//______________________________________________________________________________________________

TQPCAAnalysisJob* TQPCAAnalysisJob::copy(){
  // creates an exact copy of this job
  // neglecting temporary data members
  return new TQPCAAnalysisJob(this);
}

//______________________________________________________________________________________________

TQPCAAnalysisJob* TQPCAAnalysisJob::getClone(){
  // creates an exact copy of this job
  // neglecting temporary data members
  return new TQPCAAnalysisJob(this);
}

//______________________________________________________________________________________________

bool TQPCAAnalysisJob::initializePCA() {
  // initialize the PCA object properly
  if(this->fPCA) delete this->fPCA;
  int nVars = this->fObservables.size();
  if(!this->fValues){
    this->fValues = (double*)calloc(nVars,sizeof(double));
  }
  this->fPCA = new TQPCA(this->GetName(),nVars);
  for(size_t i=0; i<this->fNames.size(); i++){
    this->fPCA->setTagString(TString::Format("varname.%lu", (long unsigned int)i),fNames[i].Data());
    this->fPCA->setTagString(TString::Format("vartitle.%lu", (long unsigned int)i),fTitles[i].Data());
    this->fPCA->setTagString(TString::Format("varexpression.%lu",(long unsigned int)i),fExpressions[i].Data());
  }
  return true;
}

//______________________________________________________________________________________________

bool TQPCAAnalysisJob::finalizePCA() {
  // initialize the PCA object properly
  // and write it to the pool folder
  if(!this->poolAt) return false;
 
  /* get the cutflow folder */
  TString folderName = TString::Format(".pca/%s+",this->getCut()->GetName());
  TQFolder * cfFolder = this->poolAt->getFolder(folderName);
 
  /* stop if we failed to get the folder */
  if (!cfFolder) { return false; }
 
  /* remove existing grid */ 
  TObject* o = cfFolder->FindObject(this->GetName());
  if(o){
    cfFolder->Remove(o);
  } 

  /* add the pca object */
  if(!cfFolder->addObject(this->fPCA)){
    return false;
  }

  this->fPCA = NULL;

  return true;
}

//______________________________________________________________________________________________

bool TQPCAAnalysisJob::initializeSelf() {
  // initialize the job on the given sample

  if(!this->fPCA) this->initializePCA();
 
  /* initialize TQObservables */
  for (unsigned int i = 0; i < fNames.size(); i++) {
    TQObservable* obs = TQObservable::getObservable(this->fExpressions[i],this->fSample);
    if (!obs->initialize(this->fSample)) {
      ERRORclass("Failed to initialize observable obtained from expression '%s' in TQPCAAnalysisJob '%s' for sample '%s'",this->fExpressions[i].Data(),this->GetName(),this->fSample->getPath().Data());
      return false;
    }
    this->fObservables.push_back(obs);
  }
  return true;
}

//______________________________________________________________________________________________

bool TQPCAAnalysisJob::finalizeSelf() {
  // finalize the job, writing all results to the pool folder
 
  if(this->fSample == this->poolAt)
    this->finalizePCA();

  /* initialize TQObservables */
  for (unsigned int i = 0; i < fObservables.size(); i++) {
    this->fObservables[i]->finalize();
  }

  this->fObservables.clear();

  /* finalize this analysis job */
  return true;
}

//______________________________________________________________________________________________

bool TQPCAAnalysisJob::initializeSampleFolder(TQSampleFolder * sf) {
  // initalize the job on a sample folder
  // check for pool tag

  bool pool = false;
  sf->getTagBool(".aj.pool.pca",pool);
 
  if(pool && !this->fPCA){
    this->poolAt = sf;
  }
 
  return true;
 
}




//______________________________________________________________________________________________

bool TQPCAAnalysisJob::finalizeSampleFolder(TQSampleFolder* sf) {
  // finalize the job on a sample folder
  // check for pool tag 

  bool pool =(sf == this->poolAt);
 
  /* stop if we no sample is defined */
  if (!sf) { return false; }
 
  if(pool)
    return this->finalizePCA();
 
  return true;
}


//______________________________________________________________________________________________

bool TQPCAAnalysisJob::execute(double weight) {
  // execute the job on a given event
 
  if(weight < this->weightCutoff) return true;
  // std::cout << "filling with weight " << weight << " (cutoff = " << this->weightCutoff << ")" << std::endl;

  for(size_t i=0; i<this->fObservables.size(); i++){
    this->fValues[i] = this->fObservables[i]->getValue();
  }

  if(this->checkValues()){
    this->fPCA->fill(weight,this->fValues);
  }

  return true;
}



//______________________________________________________________________________________________

bool TQPCAAnalysisJob::checkValues() {
  // check if the values are valid to avoid inf/NaN
  // being propagated to the PCA object

  for(size_t i=0; i<this->fObservables.size(); i++){
    if(!TQUtils::isNum(this->fValues[i])) return false;
  }
 
  return true;
}



//______________________________________________________________________________________________

TQPCAAnalysisJob::~TQPCAAnalysisJob() {
  // destructor
  if(this->fPCA)
    delete this->fPCA;
  for(size_t i=0; i<this->fObservables.size(); i++){
    delete this->fObservables[i];
  }
  if(this->fValues)
    free(this->fValues);
}


//______________________________________________________________________________________________

TObjArray * TQPCAAnalysisJob::getBranchNames() {
  // Return all used TTree branches in a TObjArray* 
  // The strings should include all used branch names,
  // but can also include formulas, number, etc.
 
  TObjArray * bNames = new TObjArray();
 
  for(size_t i=0; i<this->fObservables.size(); i++){
    TObjArray* branchNames = this->fObservables[i]->getBranchNames();
    bNames->AddAll(branchNames);
    delete branchNames;
  }
 
  return bNames;
}

//______________________________________________________________________________________________

void TQPCAAnalysisJob::bookVariable(const TString& name, const TString& title, const TString& expression){
  // book a variable with the given name, title and expression
  this->fNames.push_back(name);
  this->fTitles.push_back(title);
  this->fExpressions.push_back(expression);
}


//______________________________________________________________________________________________

void TQPCAAnalysisJob::bookVariable(const TString& expression){
  // book a variable with the given expression
  // it will also be used as name and title of variable
  this->fNames.push_back(expression);
  this->fTitles.push_back(expression);
  this->fExpressions.push_back(expression);
}

//______________________________________________________________________________________________

void TQPCAAnalysisJob::setWeightCutoff(double cutoff){
  this->weightCutoff = cutoff;
}

//______________________________________________________________________________________________

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