// Renata Kopecna
 
#ifndef CONSTANTS_HH
#define CONSTANTS_HH

#include <sys/stat.h>
#include <iostream>
#include <vector>
#include <TMath.h>

//general constnats
const double MY_PI = TMath::Pi();
const double C_PWAVE = 9.0/32.0/MY_PI;
const double C_SWAVE = 3.0/16.0/MY_PI;

const double ONE_SIGMA = 0.683;
const double TWO_SIGMAS = 0.9773;
const double THREE_SIGMAS = 0.9987;

const int    DEFAULT_TREE_INT = -1; //Used when initializing doubles in trees
const double DEFAULT_TREE_VAL = -100.0; //Used when initializing doubles in trees
const double DEFAULT_TREE_ERR = 0.0; //Used when initializing error of doubles in trees

//Set binning scheme
const double Q2_MIN_RANGE = 0.25; //Not necesarilly connected to get_TheQ2binsmin, used only when the full q2 range is used, eg for plotting
const double Q2_MAX_RANGE = 18.0;
const double Q2_MAX_RANGE_B0 = 19.0;
 //Not necesarilly connected to get_TheQ2binsmax, used only when the full q2 range is used, eg for plotting
std::vector<double> get_TheQ2binsmin(int nBins, bool Reference);
std::vector<double> get_TheQ2binsmax(int nBins, bool Reference);

//List excluded Q2 regions
const std::vector<std::vector<double>> EXCLUDED_Q2 ={
    {0.98,1.1}, //meaning events with q^2 in 0.98-1.1 will not be considered
    {8.0,11.0},
    {12.5,15}
};

const int NBINS_DEFAULT = 4; //used as a default number of q2 bins

//Set resolution
std::vector<std::vector<double>> get_resolution();

//Set limits of the angles
const double CTL_MIN = -1.0;
const double CTL_MAX = +1.0;
const double CTK_MIN = -1.0;
const double CTK_MAX = +0.8;
const double PHI_MIN = -TMath::Pi();
const double PHI_MAX = +TMath::Pi();

//Set the maximum number of folding ID, useful for loops
const double MAX_FOLDING = 5;

//Ranges of the angles, always max-min
double CTL_RANGE();
double CTK_RANGE();
double PHI_RANGE();
double Q2_RANGE_FULL();
double RANGE_3D(); //ctl*ctk*phi range
double RANGE_4D(); //ctl*ctk*phi*q2 range


const int nANGLES = 3;
const std::vector<std::string> ANGLES = {"ctl", "ctk", "phi"};
//This *could* be in design.hh, but then it has to be sourced everywhere and this is just easier
const std::vector<std::string> latex_angles = {"cos(#Theta_{L})", "cos(#Theta_{K})", "#phi"};
const std::vector<std::string> latex_2angles = {"\\ctl", "\\ctk", "$\\phi$"};

//////////////////////////////////
//        Fitter options        //
//////////////////////////////////

//Set number of used cores
const int NCORES = 8;

const double MIG_MAX_CALLS = 100000000.0;
const double MIG_TOLERANCE = 0.1; //TODO
// The default tolerance in TMinuit is 0.1
// The minimization will stop when the estimated vertical distance to the minimum (EDM) is less than 0.001*[tolerance]*UP(see SET ERR)


//////////////////////////////////
//         Basic paths          //
//////////////////////////////////

//Set decay string and main path
const std::string DECAY_NAME  = "KplusPi0Resolved";//"KshortPiplus"
const std::string CONFIG_PHSP_WEIGHT = "config/phspweightq2.root";

//////////////////////////////////
//          plotting            //
//////////////////////////////////
const bool PLOT_THISTHESIS_TAG = true;
const std::string THISTHESIS_TAG = "this thesis";
const int PLOT_NBINS_MB = 100;
const int PLOT_NBINS_MKSTAR = 50;
const int PLOT_NBINS_ANGLES = 20;
//When plotting, the pdf is plotted as a very fine TH1D,
//PLOT_NBINS_RATIO says how many times more bins is there in the pdf compared to the data bins
const int PLOT_NBINS_RATIO = 20;


//////////////////////////////////
//         PDG masses           //
//////////////////////////////////

const Double_t PDGMASS_B_PLUS   = 5279.29;
const Double_t PDGMASS_B_ZERO   = 5279.61;
const Double_t PDGMASS_J_PSI    = 3096.90;
const Double_t PDGMASS_PSI_2S   = 3686.10;
const Double_t PDGMASS_K_STAR_PLUS = 891.66;
const Double_t K_ONE_PLUS       = 1272.0;
const Double_t PDGMASS_K_PLUS   = 493.68;
const Double_t PDGMASS_K_SHORT  = 497.61;
const Double_t PDGMASS_PI_PLUS  = 139.57;
const Double_t PDGMASS_PI_ZERO  = 134.98;
const Double_t PDGMASS_MU       = 105.66;
const Double_t PDGMASS_GAMMA    = 0.0;

//Decay specific PDG masses
const Double_t PDGMASS_K_STAR   = PDGMASS_K_STAR_PLUS;
const Double_t PDGMASS_KST_KAON = PDGMASS_K_PLUS;
const Double_t PDGMASS_KST_PION = PDGMASS_PI_ZERO;
const Double_t PDGMASS_B        = PDGMASS_B_PLUS;

//Set mass range and window of the B mass
const double B_MASS_LOW  = 5150.0;
const double B_MASS_HIGH = 5800.0;
//CAREFUL when initializing the m_b parameter:
//the min and max set also the fit range, so it should be always
//set to B_MASS_LOW and B_MASS_HIGH

//The tight window is used for plotting the very signal only region
const double B_MASS_TIGHT_WINDOW = 100; //David had 50

//Set the cuts from where we have only background
const double B_MASS_HIGH_BKG = PDGMASS_B_PLUS + 100;
const double B_MASS_LOW_BKG  = PDGMASS_B_PLUS - 100;
const double B_MASS_HIGH_BKG_REF = PDGMASS_B_PLUS + 350;
const double B_MASS_LOW_BKG_REF  = 5150;

const double KPI_MASS_MIN = PDGMASS_K_STAR-100.;
const double KPI_MASS_MAX = PDGMASS_K_STAR+100.;

//////////////////////////////////
//         PARTICLE IDs         //
//////////////////////////////////
const int ID_B_PLUS     = +521;
const int ID_B_ZERO     = +511;

const int ID_K_STAR_PLUS = +323;
const int ID_K_STAR_ZERO = +313;

const int ID_K_PLUS  = +321;
const int ID_K_SHORT = +310;

const int ID_PI_PLUS = +211;
const int ID_PI_ZERO = +111;
const int ID_GAMMA   = +22;

const int ID_MU_PLUS    = -13;
const int ID_MU_MINUS   = +13;
const int ID_J_PSI    = +443;
const int ID_RHO_ZERO = +113;

const int ID_K_ONE_PLUS      = +10323;  // K1(1270)+
const int ID_K_ONE_PLUS_1400 = +20323;  // K1(1400)+
const int ID_K_ONE_PLUS_1410 = +100323; // K1(1410)+
const int ID_K_ONE_ZERO = 10313; // K0(1270)+
const int ID_ELECTRON = -11;

//////////////////////////////////
//      Angular correction      //
//////////////////////////////////

//Modify this after being done with scannig the corrections
const bool IS_PHI_EVEN = true;
const int ORDER_COSTHETAL = 3;
const int ORDER_COSTHETAK = 6;
const int ORDER_PHI       = 1;
const int ORDER_Q2        = 7;

//////////////////////////
//      Reweighting     //
//////////////////////////

//Descides at what 1/weight you reject events
//Large weights result in large errorbars and can be a source of fluctuations
const double EFF_CUTOFF = 0.01;


//////////////////////////////////
//  Idk why, but here are pies  //
//////////////////////////////////
const double M_4_PI     = 1.2732395447351626861510701069801;   // 4/Pi
const double M_SQRTPI   = 1.7724538509055160272981674833411;   // sqrt(Pi)
const double M_SQRT2PI  = 2.5066282746310005024157652848111;   // sqrt(2Pi)
const double M_SQRT_PI_2= 1.2533141373155002512078826424055;   // sqrt(Pi/2)
const double M_SQRT_2_PI= 0.79788456080286535587989211986876;  // sqrt(2/Pi)
const double M_1_SQRTPI = 0.56418958354775628694807945156077;  // 1/sqrt(Pi)
const double m_2_SQRTPI = 1.1283791670955125738961589031216;   // 2/sqrt(Pi)
//M_2_SQRTPI is defined in math.h, see https://stackoverflow.com/questions/52796736/why-does-c-define-m-2-sqrtpi-constant-in-math-h
const double M_SQRT_2PI = 0.39894228040143267793994605993438;  // 1/sqrt(2Pi)
const double M_SQRT_2   = 0.70710678118654752440084436210485;  // sqrt(1/2)
const double M_2PI      = 6.2831853071795864769252867665590;   // 2Pi
const double M_4PI      = 12.5663706143591729538505735331180;  //4Pi



//////////////////////////
//    Fit parameters    //
//////////////////////////

//Set default values for most parameters
//These values can be set individually, but it is good to have some default starting points

//Check the definitions in bu2kstarmumu_parameters!

const double PAR_ANG_RANGE = 1.0; //Default range for all angular observables
const double PAR_SIGMA = 30.0; //[MeV]
const double PAR_SIGMA_LOW = 25.0;  //[MeV]
const double PAR_SIGMA_HIGH  = 50.0; //[MeV]
const double PAR_TAU = 100.0;
const double PAR_TAU_SCALE = 100.0; //Tau range is then par_tau/scale to par_tau*scale
const double PAR_LAMBDA = -0.0001;
const double PAR_LAMBDA_SCALE = 100.0; //Lambda range is then par_lambda*scale to par_lambda/scale
const double PAR_NTRESHOLD = 1.5;
const double PAR_KSTAR_WIDTH = 50.0; //[MeV]
const double PAR_K1_WIDTH = 270.0; //[MeV]
const double PAR_N_SIG = 150.0;
const double PAR_N_BKG = 500.0; //f_sig is init as PAR_N_SIG/(PAR_N_SIG+PAR_N_BKG)

//If you want to have only 1 exponential in bkg, set to false
const double FIX_FM = true;
const double DOUBLE_CB = true; //Just always use double CB, it is not like anyone is going to switch this halfway through the code

//This string contains parameters that are varied when fitting bkg
//TODO: optimize at some point
std::vector<std::string> PAR_BKG_STRING(int folding, int nCtl, int nCtk);
//Init values of said parameters
//CAREFUL!!!! HAS TO BE THE SAME AS PAR_BKG_STRING!!!!
std::vector<double> init_bkg(int folding, int nCtl, int nCtk);

//////////////////////////////////
//      Main Fit Parameters     //
//////////////////////////////////

//Number of angular terms: 12 for P wave, 6 for S wave
const int NTERMS_P = 12;
const int NTERMS_S = 6;
const int NTERMS = NTERMS_S + NTERMS_P; //If no s Wave ever, one can also set it to 12 and save some memory

//Fraction of events in each subset
std::vector<std::vector<double> > fracs(int nBins);

//Init default parameters
std::vector<double> init_n_signal(int nBins);
std::vector<double> init_n_bckgnd(int nBins);
std::vector<double> init_f_lambda(int nBins);
std::vector<double> get_f_subset(int nPDFs);

//Used in EventNumbers
const std::vector<std::vector<double> > sig_unblinded = { //Set only for 8 bins and 4 pdfs //TODO
        {5.86168, 13.9418, 54.4478, 27.3012},
        {2.36522, 1.09800, 31.7908, 13.7227},
        {8.99630, 6.53635, 14.4187, 12.2178},
        {14.0240, 8.82742, 62.4731, 23.5189},
        {5.11878, 7.85420, 59.2977, 32.3194},
        {17.7802, 12.8009, 39.0769, 40.8969},
        {19.8873, 12.7440, 81.8400, 29.7622},
        {3.73514, 7.56100, 32.8754, 31.5777}
};

const std::vector<std::vector<double> > bkg_unblinded = { //Set only for 8 bins and 4 pdfs //TODO
        {18.6849, 10.7306, 130.508, 26.1523},
        {28.8699, 11.4018, 152.795, 26.1676},
        {36.0865, 7.24722, 196.480, 35.0536},
        {39.2519, 22.7192, 163.944, 61.0158},
        {65.1688, 19.2037, 165.299, 48.0148},
        {19.5884, 16.5293, 88.6190, 46.0676},
        {17.2658, 14.1666, 42.6978, 34.5553},
        {17.6887, 20.2719, 41.7393, 26.3643}
};

std::vector<std::vector<double>> init_angular_params(int nBins, bool NP, bool isReference);

std::vector<std::vector<double>> init_angular_params_MC(int nBins);
std::vector<std::vector<double>> init_angular_params_zeros(int nBins);

std::vector<std::vector<double>> init_mass_params_MC(int nBins, int nPDF);

//Jpsi results from B+->K*(Kspi+)mumu
std::vector<double> init_angular_params_RefFromDavid();

//obtain parameter ranges and stepsize for (most) parameters
double GetParamStepsize(std::string);
std::vector<double> GetParamRange(std::string);

#endif // CONSTANTS_HH
