#include "FitEfficiency.h"
#include "TH1F.h"
#include "TF1.h"
#include <iostream>
#include <fstream>

using namespace std;

// global function, required by ROOT, to wrap member operator function
//   arg: pointer to variable containing the result
//   par: array of parameters to fit
double func( double* arg, double *par ) {
  // get object instance
  FitEfficiency& f = *FitEfficiency::instance();
  // copy parameters from array(set by ROOT)
  // to members (used by operator function)
  f.setPar( par );
  // compute result
  return f( *arg );
}

FitEfficiency::FitEfficiency() {
}

FitEfficiency::~FitEfficiency() {
}

// function to fit function parameters to represent efficiency
// described by "histo"
void FitEfficiency::fit( TH1F* histo ) {

  // create array of parameters
  double par[4];

  // preliminary fit with linear function
  // TF1 is a ROOT object representing a function:
  //   "lin"      : object name
  //   "pol1"     : set the function to a 1st grade polynomial (predefined)
  //   0.0, wCell : range
  TF1* l = new TF1( "lin", "pol1", 0.0, wCell );
  histo->Fit( l, "" );
  // get preliminary fit result and save into "par" array,
  // being a linear function 2 elements in "par" array are filled
  l->GetParameters( par );

  // create TF1 object for complete fit
  //   "fgau"     : object name
  //   func       : coded global function to be used
  //   0.0, wCell : range
  //   4          : number of parameters
  TF1* s = new TF1( "fgau", func , 0.0, wCell, 4 );

  // set initial values for gaussian parameters
  par[2] = iNorm = -0.5;
  par[3] = width =  0.05;
  s->SetParameters( par );

  // final complete fit
  histo->Fit( s, "" );

  // save fit results int "par" array
  s->GetParameters( par );

  // copy "par" array to member variables
  setPar( par );

  return;

}

// function to get a single object instance
FitEfficiency* FitEfficiency::instance() {
  static FitEfficiency* obj = new FitEfficiency;
  return obj;
}

// functions to copy function parameters to/from array "par", used by ROOT
void FitEfficiency::getPar(       double* par ) const {
  par[0] = efMax;
  par[1] = slope;
  par[2] = iNorm;
  par[3] = width;
  return;
}

void FitEfficiency::setPar( const double* par ) {
  efMax = par[0];
  slope = par[1];
  iNorm = par[2];
  width = par[3];
  return;
}

