//Renata Kopecna

#ifndef HELPERS_HH
#define HELPERS_HH

#include <string>
#include <vector>
#include <TF1.h>
#include <TH1D.h>
#include <TStopwatch.h>
#include <parse.hh>

//indexed auto looping over vectors
#define for_indexed(...) for_indexed_v(i, __VA_ARGS__)
#define for_indexed_v(v, ...) for(bool _i_ = true, _break_ = false; _i_;) for(size_t v = 0; _i_; _i_ = false) for(__VA_ARGS__) if(_break_) break; else for(bool _j_ = true; _j_;) for(_break_ = true; _j_; _j_ = false) for(bool _k_ = true; _k_; v++, _k_ = false, _break_ = false)
/// usage:
///  std::vector<int> v{1, 2, 3};
///for_indexed (auto const& item : v) { //the index is always i
///    if (i > 0) std::cout << ", ";
///    std::cout << i << ": " << item;
///}
/// for_indexed_v (my_counter, auto const& item : v) //the index is v here


//TODO: work on more forward declarations, it reduces the compiler time as cross-referencing is not recompiled 400 times anymore
//TODO: simirarly move your includes into .cpp in order to avoid this

namespace fcnc { //Forward declaration, fully defined in options.hh
    class options;
    class parameters;
    class bu2kstarmumu_parameters;
    class event;
}


//----------------------//
//     Print utils      //
//----------------------//
std::string boolToString(bool isTrue);

//reset the spdlog into my default
void reset_spdlog();

//set spdlog level
void set_spdlog_level(int verboseLvl);

//what lever is the spdlog?
bool spdlog_trace();
bool spdlog_debug();
bool spdlog_info();
bool spdlog_warn();
bool spdlog_error();

//Get job_id and turn it in a string
std::string get_sample_from_jobID(int job_id);

//Make pretty outputs with given precision (feault is two)
std::string format_double(double value, unsigned int digits=2);
std::string format_value(double value, double error, unsigned int digits=2);
std::string format_error(double error, unsigned int digits=2);

//----------------------//
//      Year utils      //
//----------------------//

//Get years according to a run
std::vector<int> get_years(int Run, bool MCsig, bool MCref);
//Check if year makes sense
void check_year(int year);
int get_yearFromRun(int year);

int MC_dataset(bool Reference, bool PHSP);
//--------------------------------------//
//            General helpers           //
//--------------------------------------//

//Copy file
int copyFile(std::string from, std::string to);
//Check if file/folder exists
bool existsTest (const std::string& name);
//Create new folder
void makeFolder (const std::string& name);

//Convert vector into number-space-number... string
std::string convert_vector_to_string(std::vector<int> myVector);
std::string convert_vector_to_string(std::vector<double> myVector);
std::string convert_vector_to_string(std::vector<std::string> myVector);

//Merge two vectors
std::vector<double> merge_two_vecs(std::vector<double> one, std::vector<double> two);
std::vector<int> merge_two_vecs(std::vector<int> one, std::vector<int> two);
std::vector<std::string> merge_two_vecs(std::vector<std::string> one, std::vector<std::string> two);

//Replace a part of a string
bool replace(std::string& str, const std::string& from, const std::string& to);

//Sum a vectors
int sum_vector(std::vector<int> vec);
double sum_vector(std::vector<double> vec);

//Return the center of a bin
double bin_center(double low, double high);
//Return the center of a q2 bin
double bin_center_q2(fcnc::options opts, int b);
double bin_center_q2(fcnc::options *opts, int b);
double bin_center_q2(std::vector<double> q2min, std::vector<double> q2max , int b);

//Return half of the width (useful for errors)
double bin_halfWidth(double low, double high);
double bin_halfWidth_q2(fcnc::options opts, int b);
double bin_halfWidth_q2(fcnc::options *opts, int b);
double bin_halfWidth_q2(std::vector<double> q2min, std::vector<double> q2max, int b);

//Check if the angles are in the correct range given by options
bool isEvtInAngleRange(fcnc::event *evt, fcnc::options *opts);
//Check if the angles are in the correct range given by default
bool isEvtInAngleRange(fcnc::event *evt);
//For now filter out events that are dumb dumb for folding four
bool filterFldFour(fcnc::event *evt, fcnc::options *opts);

//Check if value is in a vector
bool isInVec(int key, std::vector<int>vec);
bool isInVec(double key, std::vector<double>vec);
bool isInVec(std::string key, std::vector<std::string>vec);


//--------------------------------------//
//  Helpers for converting the tuples   //
//--------------------------------------//

//Return's OG tuple name
std::string get_inputTree_name(int job_id);

//--------------------------------------//
//   Helpers for angular corrections    //
//--------------------------------------//

TF1 *fitStraightLine(TH1D* hist, std::string lineName, double lowEdge, double highEdge);

//--------------------------------------//
//     Helpers for bu2kstarmumu_pdf     //
//--------------------------------------//

//Returns a vector with the {p wave observables, obervable in tex}, useful for histograms in a loop
const std::vector<std::vector<std::string>> get_angObser_withTeX_vec();


//Returns a vector with the p wave observables
std::vector<std::string> get_angObser_vec();

//Returns a vector with the p wave observables in tex
std::vector<std::string> get_angObserTeX_vec();

//--------------------------------------//
//      Helpers for time measuring      //
//--------------------------------------//

struct runTime{
    //Measure the time for the fit:
    std::vector<Double_t> real_times;
    std::vector<Double_t> cpu_times;
    std::vector<Double_t> cpp_times;
    TStopwatch * sw;// = new TStopwatch();
    runTime(){
        sw = new TStopwatch();
    }
    void print(unsigned int nBins);
    void start();
    void stop(time_t startTime);
};

//--------------------------------------//
//       Helpers for fit scripts        //
//--------------------------------------//

//get a vector of all available angle bkg parameters
std::vector<std::string> param_string_bkg();
//get a vector of all available angle mkpi parameters
std::vector<std::string> param_string_bkg_mkpi();
//get a string vector of all effectivelly used parameters
std::vector<std::string> param_string(fcnc::options opts, bool MC);
//get a string vector of mass parameters
std::vector<std::string> params_string_mass(fcnc::options opts);
//Reads MC fit files (massFitOnly) and gets the sigma ratio of ref/MC for given bin and pdf
double get_sigmaRatio_fromMC(basic_params params, int nBins, int bin, int pdf);

//---------------------------------------------//
// Helpers for printing and saving fit results //
//---------------------------------------------//

void print_all_parameters(unsigned int nBins, fcnc::bu2kstarmumu_parameters *theParams[],
                          int spdlog_level, std::string savePath);
void print_all_parameters(unsigned int nBins, std::vector<UInt_t> pdf_idx,
                          std::vector<fcnc::parameters*> theParams[],
                          int spdlog_level);

void tex_all_parameters(unsigned int nBins, std::vector<UInt_t> pdf_idx,
                        std::vector<fcnc::parameters*> theParams[]);

void print_fit_results(unsigned int nBins, std::vector<Int_t> fitresults);
void print_fit_results(unsigned int nBins, std::vector<UInt_t> pdf_idx, std::vector<Int_t> fitresults[], bool simFit);
void print_sig_yields(unsigned int nBins, std::vector<UInt_t> pdf_idx,
                     std::vector<UInt_t> *evts_cntr, std::vector<double> *f_sigs, std::vector<double> *f_sigserr);
void print_bkg_yields(unsigned int nBins, std::vector<UInt_t> pdf_idx,
                     std::vector<UInt_t> *evts_cntr, std::vector<double> *f_sigs, std::vector<double> *f_sigserr);
void print_bkgOnly_yields(unsigned int nBins, std::vector<UInt_t> pdf_idx,
                          std::vector<fcnc::bu2kstarmumu_parameters*> theParams[],
                          std::vector<double> bkg_int_full_range[], std::vector<UInt_t> *evts_cntr);
void print_sig_yields_tex(std::string texFiletag,
                          unsigned int nBins, std::vector<UInt_t> pdf_idx,
                          fcnc::options *theOptions,
                          std::vector<UInt_t> *evts_cntr, std::vector<double> *f_sigs, std::vector<double> *f_sigserr);

int save_results(std::string results_file, unsigned int nBins, std::vector<UInt_t> pdf_idx, std::vector<int>*fit_results, std::vector<fcnc::parameters*> *theParams, bool simFit, fcnc::options *opts);
int save_results(std::string results_file,  unsigned int nBins, int n_pdf, std::vector<int> fit_results, fcnc::bu2kstarmumu_parameters **theParams, fcnc::options *opts);
//--------------------------------------//
//   Helpers for writting latex stuff   //
//--------------------------------------//

int clear_Latex_noteFile(std::string tag); //Deletes the old file
int open_Latex_noteFile(std::string tag, std::ofstream &myfile); //Appends output at the end of the file


//--------------------------------------//
//   Helpers for reading the parameters //
//--------------------------------------//

std::vector<double> load_param_values_into_vector(std::string paramName, std::string fileName);
#endif // HELPERS_HH
