//Renata Kopecna

#include <paths.hh>
#include <sstream>
#include <spdlog.h>
#include "Helpers/helpers.hh"

//=====================================//
//         Paths for datsets           //
//=====================================//

std::string datapath(){ //Returns the path where the data is stored based on the server/user
    char cwd[256];
    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        spdlog::debug("CURRENT DATA DIRECTORY: "+std::string(cwd));
        if(strstr(cwd, "kopecna")){
            if(strstr(cwd, "cern")) return "TODO/ADD/PATH/TO/FILES/ON/LXPLUS";//for lxplus //TODO @Renata
            if(strstr(cwd, "home")) return "/home/lhcb/kopecna/B2KstarMuMu_clean/Data/Tuples/";//for HD servers
        }
        if(strstr(cwd, "dgerick")){
            if(strstr(cwd, "cern")) return "/afs/cern.ch/work/d/dgerick/b2kmm/data/";//for lxplus
            if(strstr(cwd, "work")) return "/home/lhcb/kopecna/B2KstarMuMu_clean/Data/Tuples/";//for HD servers
        }
        if(strstr(cwd, "condor")) return "/afs/cern.ch/work/d/dgerick/b2kmm/data/";//for condor
    }
    //default value:
    spdlog::warn("None of the expected data paths are found! Setting workpath to the default \n /home/lhcb/kopecna/B2KstarMuMu_clean/Data/Tuples/");
    return "/home/lhcb/kopecna/B2KstarMuMu_clean/Data/Tuples/";
}

std::string workpath(){ //Returns the path where the program is executed based on the server/user
    char cwd[256];
    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        spdlog::debug("CURRENT WORKING DIRECTORY: "+std::string(cwd));
        if(strstr(cwd, "kopecna")){
            if(strstr(cwd, "cern")) return "TODO/ADD/PATH/TO/FCNCFITTER/ON/LXPLUS";//for lxplus //TODO @Renata
            if(strstr(cwd, "home")) return "/home/lhcb/kopecna/B2KstarMuMu_clean/Code/FCNCFitter/";//for HD servers
        }
        if(strstr(cwd, "dgerick")){
            if(strstr(cwd, "cern")) return "/afs/cern.ch/work/d/dgerick/b2kmm/";//for lxplus
            if(strstr(cwd, "work")) return "/home/lhcb/kopecna/B2KstarMuMu_clean/Code/FCNCFitter/";//for HD servers
        }
        if(strstr(cwd, "condor")) return "/afs/cern.ch/work/d/dgerick/b2kmm/";//for condor
    }
    //default value
    spdlog::warn("None of the expected workpaths are found! Setting workpath to the default \n /home/lhcb/kopecna/B2KstarMuMu_clean/Code/FCNCFitter/");
    return "/home/lhcb/kopecna/B2KstarMuMu_clean/Code/FCNCFitter/";
}

std::string get_folderName_from_jobID(int dataset, std::string decayName){
    if(dataset == 0)      return "Data/"+ decayName+ "_";
    else if(dataset == 1) return "MC/"+ decayName + "_MC";
    else if(dataset == 2) return "MC/"+ decayName + "_RefMC";
    else if(dataset == 3) return "PHSP/"+ decayName + "_PHSP";
    else if(dataset == 4 || dataset == 5) return "";
    else {
        spdlog::error("Invalid index for conversion function given: {0:d}", dataset);
        assert(0);
    }
}

std::string getSelectedTuplePath(int dataset, int run, int year){
    if (dataset==4)       return "/home/lhcb/kopecna/B2KstarMuMu_clean/Data/Tuples/PHSP/EvtGen/AtRest/MCTruth_PHSP.root";
    else if (dataset ==5) return "/home/lhcb/kopecna/B2KstarMuMu_clean/Data/Tuples/MC/EvtGen/AtRest/MCTruth.root";
    else                  return DATA_PATH + get_folderName_from_jobID(dataset, DECAY_NAME) +"_BDToutputSelection_Run"+std::to_string(run)+"_" +std::to_string(year)+".root";
}

std::string get_theFCNCpath(int dataset, int run){
    //standard output for [0]: data, [1]: signal MC, [2]: reference channel MC, [3]: phase-space MC, [4]: genLevelMC

    UInt_t loadingRun = (run > 20) ? 2 : run;
    std::string theFCNCpath = DATA_PATH
                            + DECAY_NAME
                            + "_Run"+std::to_string(loadingRun);
    if (dataset == 0) return theFCNCpath + "_FCNC.root";
    if (dataset == 1) return theFCNCpath + "_MC_FCNC.root";
    if (dataset == 2) return theFCNCpath + "_RefMC_FCNC.root";
    if (dataset == 3) return theFCNCpath + "_PHSP_FCNC.root";
    if (dataset == 4) return theFCNCpath + "_PHSP_EvtGen_FCNC.root";
    if (dataset == 5) return theFCNCpath + "_MC_EvtGen_FCNC.root";
    return "";
}

std::string get_finalToySamplePath(int nPDF, int job_id, bool fitReference){
    return std::string("FinalToySample_")+(fitReference ? "Jpsi_" : "")+std::to_string(job_id)+"_PDF"+std::to_string(nPDF)+".root";

}

//=====================================//
//  Paths for angular parametrization  //
//=====================================//

std::string get_angCorrPath(bool test){
    if (test) return PLOTS_PATH + "/angular/test/";
    else      return PLOTS_PATH + "/angular/";
}
std::string coeffs_eff_phsp_4D(fcnc::options *opts){
    std::string filename = COEFFS_PATH+"Coeffs_"
            + DECAY_NAME + "_"
            + "Run" + std::to_string(opts->run)
            + ((opts->angacccorrperyear && opts->year != -1) ? "_"+std::to_string(opts->year) : "")
            //                      + (opts->full_angular ? "" : "_folding"+std::to_string(opts->folding))
            + (opts->systematic == 1 ? "_bs"+std::to_string(opts->job_id) : "")
            + (opts->systematic == 2 ? "_sym_ctl" : "")
            + (opts->systematic == 3 ? "_"+std::to_string(opts->orderincrease)+"moreOrders" : "")
            + (opts->systematic == 4 ? "_dw"+std::to_string(opts->job_id) : "")
            + (opts->systematic == 9 ? "_trg" : "")
            + (opts->systematic == 10 ? "_ksPT" : "")
            +".txt";
    return filename;
}

//=====================================//
//    Paths for angular resolution     //
//=====================================//

std::string get_angResoFolder_path(){
    return PLOTS_PATH+"angReso/";
}
std::string get_angResoPlot_path(std::string angle, int year, std::string format){
    return get_angResoFolder_path() + "/Reso_"+angle+"_"+std::to_string(year) + "." + format;
}

//=====================================//
//        Paths for fit results        //
//=====================================//
std::string subfolder_path(bool Ref){
    if (Ref)   return "Jpsi/";
    else       return "Signal/";
}

std::string get_MainFitPlot_path(){
    return PLOTS_PATH+"MainFit/";
}

std::string get_MCfitPlot_path(){
    return PLOTS_PATH+"MCfit/";
}

std::string get_scan_path(){
    return PLOTS_PATH+"Scans/";
}

std::string get_MCfitPlot_path(bool Ref, bool PHSP){
    if (PHSP){
        return get_MCfitPlot_path()+"/PHSP/" + subfolder_path(Ref);
    }
    else{
        return get_MCfitPlot_path() + subfolder_path(Ref);
    }
}
std::string get_genLvlFitPlot_path(bool PHSP){
    if (PHSP) return PLOTS_PATH+"GenLvlFit/PHSP/";
    else      return PLOTS_PATH+"GenLvlFit/";
}

std::string get_MoMPlot_path(){
    return PLOTS_PATH+"MoMFit/";
}

std::string get_GenLvlPlot_path(){
    return PLOTS_PATH+"GenLvlFit/";
}
std::string get_PullPlot_path(){
    return PLOTS_PATH+"Pulls/";
}

std::string get_JpsiSimFit2D_path(int idx, bool pPrimes){ //TODO
    return  FIT_RESULTS_PATH+"fitresult_JpsiFit_SimultaneousFit_2Dfit_pdf"+std::to_string(idx)+
            std::string(pPrimes ? "_Pprimes" : "") + ".txt";
}

std::string get_SigMCSimFit2D_path(int idx, int bin){ //TODO
    return FIT_RESULTS_PATH+"/fitresult_SignalFit_MC_SimultaneousFit_2Dfit_bin"+std::to_string(bin)+"_pdf"+std::to_string(idx)+".txt";
}

std::string get_param_scan_path(std::string name, bool error){
    return get_scan_path()
            + std::string(error ? "error_" : "value_")
            + name + ".eps";
}

//=====================================//
//          Fit result tags            //
//=====================================//
std::string tag_bin(int nBinsToFit){
    std::ostringstream label;
    if(nBinsToFit==1)  label << "_1BIN";
    else if(nBinsToFit==NBINS_DEFAULT) label << "_ALLBINS";
    else                label << "_" << nBinsToFit << "BINS";
    return label.str();
}
std::string tag_bin(int nBinsToFit, int bin){
    std::ostringstream label;
    label << tag_bin(nBinsToFit);
    label << std::string(bin == -1 ? "" : ("_bin" + std::to_string(bin)));
    //TODO: check what bin == -1 does
    return label.str();
}
std::string tag_Run(int Run){
    return "_Run" + std::to_string(Run);
}
std::string tag_OnlyOneRun(int Run){
    if (Run == 1) return "_OnlyRun1";
    if (Run == 2) return "_OnlyRun2";
    else return tag_Run(Run);
}
std::string tag_Run(int Run, int effRun){
    if (effRun == Run) return tag_OnlyOneRun(Run);
    else return tag_Run(effRun);
}
std::string tag_OnlyOnePolarity(int polarity){
    if(polarity==-1) return "_OnlyMagDown";
    if(polarity==+1) return "_OnlyMagUp";
    else return "";
}
std::string tag_massSideband(bool lowMass, bool highMass){
    if(lowMass)  return ("_LowBmass");
    if(highMass) return ("_HighBmass");
    else return "";
}
std::string tag_sample_blind(basic_params params){
    return  tag_OnlyOneRun(params.Run)+
            tag_OnlyOnePolarity(params.polarity);
}
std::string tag_sample_blind(int Run, int polarity){
    return  tag_OnlyOneRun(Run)+
            tag_OnlyOnePolarity(polarity);
};
std::string tag_datasample(bool fitReference, bool fitMC, bool fitPHSP){
    std::ostringstream label;
    if(fitMC)        label << "_MC";
    if(fitPHSP)      label << "_PHSP";
    if(fitReference) label << "_JpsiFit";
    else             label << "_SignalFit";
    return label.str();
}

std::string tag_folding(int folding){
    if(folding!=-1) return "_folding" + std::to_string(folding);
    else            return "";
}
std::string tag_observables(bool usePprime){
    if(usePprime) return "_Pprimes";
    else          return "";
}
std::string tag_simFit(bool SimultaneousFit){
    if(SimultaneousFit) return "_SimultaneousFit";
    else                return "_IndividualFit";
}
std::string tag_splitFit(bool splitRuns){
    if(splitRuns) return "";
    else          return "_BothRuns";
}
std::string tag_partialFit(bool onlyAng, bool onlyMass){
    if (onlyAng)       return "_OnlyAngles";
    else if (onlyMass) return "_OnlyMass";
    else               return "";
}
std::string tag_onlyBkgSig(bool onlySig, bool onlyBkg){
    if (onlySig)      return "_OnlySignal";
    else if (onlyBkg) return "_OnlyBackground";
    else              return "";
}
std::string tag_jobID(int jobID){
    if (jobID == -1) return "";
    else             return "_"  + std::to_string(jobID) + "_"; //Add _ for easy identification of the id in case of some script needed
}

std::string tag_systematics(int systematics, int moreOrders = 0){
    switch (systematics){
        case -1: return  "";
        case 1: return  "_bs";
        case 2: return  "_sym_ctl";
        case 3: return  "_"+std::to_string(moreOrders)+"moreOrders";
        case 4: return  "_dw";
        case 5: return  "_rndFS";
        case 6: return  "_angreso";
        case 7: return  "_mm";
        case 8: return  "_angbkg";
        case 9: return  "_trggr";
        case 10: return  "_kspt";
        case 11: return  "_bkg_veto";
    }
    return "_WrongSystematics"; //If nada, return an emergency name (and not empty string, because that means no systematics
}

std::string tag_statFraction(double frac){
    if (frac==1.0) return "";
    else return "_statFrac" + std::to_string(frac);
    //TODO: add Jpsi with rare stats
}

//----------------------------------------------------------------------------
//          Paths for main fit
//----------------------------------------------------------------------------
std::string get_MainFitResult_path(){
    return FIT_RESULTS_PATH+"MainFit/";
}

std::string final_result_name(bool fitReference, bool fitSignalMC, basic_params params,
                              bool simFit, int nBinsToFit, int effRun,
                              bool FitFinalToySamples, double statFrac,
                              bool NP, int systematics){
    return get_MainFitResult_path() + "fitresult"
            + tag_datasample(fitReference, fitSignalMC, false)
            + tag_bin(nBinsToFit,-1)
            + tag_simFit(simFit)
            + tag_folding(params.folding)
            + tag_observables(params.usePprime)
            + tag_Run(params.Run, effRun)
            + tag_OnlyOnePolarity(params.polarity)
            + tag_systematics(systematics)
            + tag_statFraction(statFrac)
            + std::string(FitFinalToySamples ? "_FinalToys" : "")
            + tag_jobID(params.jobID)
            + std::string(NP ? "_NP" : "")
            + ".root";

}


std::string get_eps_label(bool fitReference, bool fitSignalMC, bool fitPHSP,
                           bool FitFinalToySamples,
                      int nBinsToFit, int bin,
                      int polarity,
                      bool SimultaneousFit, fcnc::options opts){
    return tag_datasample( fitReference, fitSignalMC, fitPHSP).erase(0,1)
           + std::string(FitFinalToySamples ? "_FinalToys" : "")
           + tag_bin(nBinsToFit,bin)
           + tag_simFit(SimultaneousFit)
           + tag_folding(opts.folding)
           + tag_observables(opts.fit_pprimes)
           + tag_sample_blind(opts.run, polarity);

}

std::string get_eps_label(bool fitReference, bool fitSignalMC, bool fitPHSP,
                          bool FitFinalToySamples,
                      int nBinsToFit, int bin,
                      bool SimultaneousFit, basic_params params){
    return tag_datasample( fitReference, fitSignalMC, fitPHSP).erase(0,1)
           + std::string(FitFinalToySamples ? "_FinalToys" : "")
           + tag_bin(nBinsToFit,bin)
           + tag_simFit(SimultaneousFit)
           + tag_folding(params.folding)
           + tag_observables(params.usePprime)
           + tag_sample_blind(params);
}


//----------------------------------------------------------------------------
//          Paths for MC fit
//----------------------------------------------------------------------------
std::string get_MCfit_label(bool fitReference, bool fitPHSP,
                                int nBinsToFit, int bin,
                                bool simFit,
                                basic_params params, int effRun,
                            bool onlyAng, bool onlyMass){
    //eff Run is there in case of plotting the results separately for each run when doing a simultaneous fit in ti

    return tag_datasample(fitReference,true,fitPHSP).erase(0,1)
           + tag_bin(nBinsToFit,bin)
           + tag_simFit(simFit)
           + tag_folding(onlyMass ? -1 : params.folding)
           + tag_observables(params.usePprime)
           + tag_Run(params.Run, effRun)
           + tag_OnlyOnePolarity(params.polarity)
           + tag_partialFit(onlyAng,onlyMass);
}

std::string finalResult_MCfit_txt(int nPDF, bool fitReference, bool fitPHSP,
                              int nBinsToFit, int bin,
                              bool simFit,
                              basic_params params, int effRun,
                              bool onlyAng, bool onlyMass){
    return FIT_RESULTS_PATH +
            "MCfit/fitresult_" +
            get_MCfit_label(fitReference, fitPHSP,
                            nBinsToFit, bin,
                            simFit, params, effRun,
                            onlyAng, onlyMass) +
            "_pdf" + std::to_string(nPDF) + ".txt";
}


std::string final_result_name_MC(basic_params params, int nBins, bool fitReference, bool fitPHSP, bool simFit, bool onlyAng, bool onlyMass){
    return FIT_RESULTS_PATH
           +"MCfit/finalresult_"
           + get_MCfit_label(fitReference, fitPHSP,
                            nBins, -1,
                            simFit, params, params.Run,
                            onlyAng,onlyMass)
            + ".root";
}
//----------------------------------------------------------------------------
//          Paths for GenLvl MC fit
//----------------------------------------------------------------------------
std::string get_genLvlFit_label(bool fitPHSP, int nBinsToFit, int bin, basic_params params,
                                bool onlyAng, bool onlyMass){
    return "genLvl" + tag_datasample(false,true,fitPHSP)
           + tag_bin(nBinsToFit,bin)
           + tag_folding(params.folding)
           + tag_observables(params.usePprime)
           + tag_partialFit(onlyAng,onlyMass);
}

std::string finalResult_genLvlMCfit_txt(bool fitPHSP,
                                        int nBinsToFit, int bin,
                                        basic_params params,
                                        bool onlyAng, bool onlyMass){
    return FIT_RESULTS_PATH +
            "GenLvlFit/fitresult_" +
            get_genLvlFit_label(fitPHSP,nBinsToFit, bin, params, onlyAng, onlyMass) +
            "_pdf.txt";
}

std::string final_result_name_genLvlMC(basic_params params, int nBins, bool fitPHSP,
                                       bool onlyAng, bool onlyMass){
    return FIT_RESULTS_PATH
           +"GenLvlFit/finalresult_"
           + get_genLvlFit_label(fitPHSP, nBins, -1, params, onlyAng,onlyMass)
           + ".root";
}


//----------------------------------------------------------------------------
//          Paths for bkg fit
//----------------------------------------------------------------------------
std::string get_bkgFitPlot_path(){
    return PLOTS_PATH+"bkgFit/";
}

std::string get_bkgFitResult_path(){
    return FIT_RESULTS_PATH+"bkgFit/";
}

std::string get_bkg_tag(int bin, int nBins, bool fitReference, bool lowMass, bool highMass, bool fitKpi, basic_params params){
    return "Bckgnd"
            + tag_datasample(fitReference,false, false)
            + tag_bin(nBins,bin)
            + tag_Run(params.Run)
            + tag_OnlyOnePolarity(params.polarity)
            + tag_massSideband(lowMass,highMass)
            + tag_folding(params.folding)
            + std::string(fitKpi ? "_Kpi" : "");
}

std::string get_bkgCorrPlot_path(std::string ang1, std::string ang2, int bin, int nBins, bool fitReference, bool lowMass, bool highMass, bool fitKpi, basic_params params){
    return get_bkgFitPlot_path()
            +"Background_Correlation_"+ang1+"_"+ang2+"_"
            +get_bkg_tag(bin, nBins,fitReference, lowMass, highMass, fitKpi, params)
            +".eps";
}

std::string final_result_name_bkg(int nBins, bool fitReference, bool lowMass, bool highMass, bool fitKpi, basic_params params){

    return get_bkgFitResult_path() + "finalresult_"
           +get_bkg_tag(-1, nBins,fitReference, lowMass, highMass, fitKpi, params)
           + ".root";

}

//----------------------------------------------------------------------------
//          Paths for mass fit
//----------------------------------------------------------------------------
std::string get_MassFitPlot_path(){
    return PLOTS_PATH+"MassFit/";
}
std::string get_MassFitResult_path(){
    return FIT_RESULTS_PATH+"MassFit/";
}

std::string get_MassFit_label(bool fitReference, int bin, int nBins,  bool splitRuns, basic_params params, int effRun){
    //eff Run is there in case of plotting the results separately for each run when doing a simultaneous fit in ti
    return "massfit" + tag_datasample(fitReference,false, false)
            + tag_bin(nBins,bin)
            + tag_splitFit(splitRuns)
            + tag_observables(params.usePprime)
            + tag_Run(params.Run, effRun)
            + tag_OnlyOnePolarity(params.polarity);
}

std::string final_result_name_mass(bool fitReference, int nBins,  bool splitRuns, basic_params params, int effRun){

    return get_MassFitResult_path() + "finalresult_"
           +get_MassFit_label(fitReference, -1, nBins, splitRuns, params, effRun)
           + ".root";
}

//----------------------------------------------------------------------------
//          Paths for toys fit
//----------------------------------------------------------------------------

std::string get_ToysFitPlot_path(basic_params params){
    if(params.index > -1){
      std::string name = PLOTS_PATH + "Toys/" + std::to_string(params.index) + "/";
      if(!existsTest(name))makeFolder(name);
      return name;
    }
    return PLOTS_PATH+"Toys/";
}

std::string get_ToysFitResult_path(basic_params params){
    //create a subfolder in fitResults/Toys/ whenever the index option is set:
    if(params.index > -1){
      std::string name = FIT_RESULTS_PATH + "ToysFit/" + std::to_string(params.index) + "/";
      if(!existsTest(name))makeFolder(name);
      return name;
    }
    return FIT_RESULTS_PATH+"ToysFit/";
}


std::string get_ToysFit_label(int jobID, bool fitReference, int bin, int nBins, bool simFit, basic_params params, int effRun, bool onlyAng, bool onlyMass, bool onlySig, bool onlyBkg, bool lowMass, bool highMass){

    //eff Run is there in case of plotting the results separately for each run when doing a simultaneous fit
    return "toyfit_"
            + tag_jobID(jobID)
            + tag_datasample(fitReference,false, false)
            + tag_onlyBkgSig(onlySig,onlyBkg)
            + tag_partialFit(onlyAng,onlyMass)
            + tag_bin(nBins,bin)
            + tag_Run(params.Run, effRun)
            + tag_simFit(simFit)            
            + tag_folding(params.folding)
            + tag_observables(params.usePprime)
            + tag_massSideband(lowMass,highMass)
            + tag_OnlyOnePolarity(params.polarity);
}

std::string final_result_name_toys(int jobID, bool fitReference, int nBins, bool simFit, basic_params params, int effRun, bool onlyAng, bool onlyMass, bool onlySig, bool onlyBkg, bool lowMass, bool highMass){

    return get_ToysFitResult_path(params) + "finalresult_"
           +get_ToysFit_label(jobID, fitReference, -1, nBins, simFit, params, effRun, onlyAng, onlyMass, onlySig, onlyBkg, lowMass, highMass)
           + ".root";
}

std::string init_params_name_toys(int jobID, bool fitReference, int nBins, bool simFit, basic_params params, int effRun, bool onlyAng, bool onlyMass, bool onlySig, bool onlyBkg, bool lowMass, bool highMass){

    return get_ToysFitResult_path(params) + "initParams_"
           +get_ToysFit_label(jobID, fitReference, -1, nBins, simFit, params, effRun, onlyAng, onlyMass, onlySig, onlyBkg, lowMass, highMass)
           + ".root";
}


std::string get_finalToys_file(bool fitReference, int nBins, bool simFit, basic_params params, int effRun){
    return TOYS_PATH + "Toy_"
           +get_ToysFit_label(-1, fitReference, -1, nBins, simFit, params, effRun, false, false, false, false, false, false)
           + ".root";
}

std::string get_ToyPullPlot_folder( basic_params params){
    return get_ToysFitPlot_path(params)
           +"/"+std::to_string(params.jobID)+"/";
}

std::string get_ToyPullPlot_tag(int bin, std::string varName, basic_params params, bool dist, bool pull){
    return  get_ToyPullPlot_folder(params)
            + varName
            + "_bin"+std::to_string(bin) //FUCKING KILL ME
            + (dist ? "_dist" : (pull ? "_Pulls" : "_Res"));
}


//=====================================//
//        Paths for Latex couts        //
//=====================================//
//THIS IS TODO, BIG TIME

std::string get_Latex_noteFile(std::string tag){
    return LATEX_PATH + "latex_couts"+tag+".tex";
}

std::string latex_fitterFile(std::string index){
    return "_fit_" + index;
}
std::string latex_toyFile(){
    return "_toy";
}
std::string latex_params(){
    return "_params";
}
std::string latex_paramScan(){
    return "_paramsScan";
}
std::string latex_bkgFit(){
    return "_bkgFit";
}
std::string latex_massFit(){
    return "_massFit";
}

