suppressPackageStartupMessages(library(spant))
suppressPackageStartupMessages(library(optparse))

if (ver != utils::packageVersion("spant")) {
  warning("c/l script and spant version missmatch. Reinstall the c/l scripts with : sudo Rscript -e \"spant::install_cli()\"")
}

parser <- OptionParser(prog = "spant_fit_svs", description = "Command-line interface for the fit_svs function in the spant R package",
                       formatter = IndentedHelpFormatter)

parser <- add_option(parser, c("-i", "--input"), action = "store", type = "character",
                     help="Path to input MRS data file (required).")

parser <- add_option(parser, c("-w", "--w_ref"), action = "store", type = "character",
                     help="Path to input MRS water reference data file.")

parser <- add_option(parser, c("-o", "--output_dir"), action = "store", type = "character",
                     help="Path to output directory.")

parser <- add_option(parser, c("--mri"), action = "store", type = "character",
                     help="Filepath containing anatomical MRI data.")

parser <- add_option(parser, c("--mri_seg"), action = "store", type = "character",
                     help="Filepath containing segmented MRI data.")

parser <- add_option(parser, c("-b", "--external_basis"), action = "store", type = "character",
                     help="Precompiled basis set to use for analysis.")

parser <- add_option(parser, c("--append_external_basis"), action = "store", default = FALSE,
                     help="Append the external basis with the internally generated one.\n\t\tUseful for adding experimentally acquired baseline signals to\n\t\tinternally simulated basis sets. Defaults to FALSE - meaning\n\t\tonly signals from the external basis will be used in analysis.")

parser <- add_option(parser, c("-p", "--p_vols"), action = "store", type = "character",
                     help="A numeric vector of partial volumes expressed as percentages.\n\t\tDefaults to 100% white matter. A voxel containing 100% gray\n\t\tmatter tissue would use : p_vols = c(WM = 0, GM = 100, CSF = 0).")

parser <- add_option(parser, c("--format"), action = "store", type = "character",
                     help="String describing the data format. Must be one of the\n\t\tfollowing : \"spar_sdat\", \"rda\", \"dicom\", \"twix\", \"pfile\",\n\t\t\"list_data\", \"paravis\", \"dpt\", \"lcm_raw\", \"rds\", \"nifti\",\n\t\t\"varian\", \"jmrui_txt\". If not specified, the format will be\n\t\tguessed from the filename extension, or will be assumed to be a\n\t\tSiemens ima dynamic data if the path is a directory.")

parser <- add_option(parser, c("-s", "--pul_seq"), action = "store", type = "character",
                     help="Pulse sequence type for simulating the basis set. Can be one\n\t\tof : 'press', 'press_ideal', 'press_shaped', 'steam' or\n\t\t'slaser'.")

parser <- add_option(parser, c("--TE"), action = "store", type = "double",
                     help="Metabolite mrs data echo time in seconds. If not supplied this\n\t\twill be guessed from the metabolite data file.")

parser <- add_option(parser, c("--TR"), action = "store", type = "double",
                     help="Metabolite mrs data repetition time in seconds. If not supplied\n\t\tthis will be guessed from the metab data file.")

parser <- add_option(parser, c("--TE1"), action = "store", type = "double",
                     help="PRESS or sLASER sequence timing parameter in seconds.")

parser <- add_option(parser, c("--TE2"), action = "store", type = "double",
                     help="PRESS or sLASER sequence timing parameter in seconds.")

parser <- add_option(parser, c("--TE3"), action = "store", type = "double",
                     help="sLASER sequence timing parameter in seconds.")

parser <- add_option(parser, c("--TM"), action = "store", type = "double",
                     help="STEAM mixing time parameter in seconds.")

parser <- add_option(parser, c("-a", "--append_basis"), action = "store", type = "character",
                     help="Names of extra signals to add to the default basis. Eg\n\t\tappend_basis = c(\"peth\", \"cit\"). Cannot be used with precompiled\n\t\tbasis sets.")

parser <- add_option(parser, c("-r", "--remove_basis"), action = "store", type = "character",
                     help="grep expression to match names of signals to remove from the\n\t\tbasis. For example: use \"*\" to remove all signals, \"^mm|^lip\"\n\t\tto remove all macromolecular and lipid signals, \"^lac\" to remove\n\t\tlactate. This operation is performed before signals are added\n\t\twith append_basis. Cannot be used with precompiled basis sets.")

parser <- add_option(parser, c("--pre_align"), action = "store", default = TRUE,
                     help="Perform simple frequency alignment to known reference peaks.")

parser <- add_option(parser, c("--dfp_corr"), action = "store", default = TRUE,
                     help="Perform dynamic frequency and phase correction using the RATS\n\t\tmethod.")

parser <- add_option(parser, c("--output-ratio"), action = "store", type = "character",
                     help="String to specify a metabolite ratio to output. Defaults to\n\t\t\"tCr\". Multiple metabolites may be specified for multiple\n\t\toutputs. Set to NA to omit.")

parser <- add_option(parser, c("--ecc"), action = "store", default = FALSE,
                     help="Option to perform water reference based eddy current correction,\n\t\tdefaults to FALSE.")

parser <- add_option(parser, c("--hsvd_width"), action = "store", type = "double",
                     help="Set the width of the HSVD filter in Hz. Note the applied width\n\t\tis between -width and +width Hz, with 0 Hz being defined at the\n\t\tcentre of the spectral width. Default is disabled (set to NULL),\n\t\t30 Hz is a reasonable value.")

parser <- add_option(parser, c("--decimate"), action = "store", default = FALSE,
                     help="Option on decimate the data by a factor of 2 before analysis.\n\t\tDefaults to FALSE.")

parser <- add_option(parser, c("--trunc_fid_pts"), action = "store", type = "integer",
                     help="Number of points to truncate the input data by in the\n\t\ttime-domain. E.g. setting to 1024 will ensure data with more\n\t\ttime-domain points will be truncated to a length of 1024.\n\t\tDefaults to NULL, where truncation is not performed.")

parser <- add_option(parser, c("-f", "--fit_method"), action = "store", type = "character",
                     help="Fitting method, can be 'ABFIT-REG' or 'LCMODEL'. Defaults to\n\t\t'ABFIT-REG'.")

parser <- add_option(parser, c("--fit_opts"), action = "store", type = "character",
                     help="Options to pass to the fitting method.")

parser <- add_option(parser, c("--fit_subset"), action = "store", type = "character",
                     help="Specify a subset of dynamics to analyse, for example 1:16 would\n\t\tonly fit the first 16 dynamic scans.")

parser <- add_option(parser, c("--legacy_ws"), action = "store", default = FALSE,
                     help="Perform and output legacy water scaling compatible with default\n\t\tLCModel and TARQUIN behaviour. See w_att and w_conc arguments\n\t\tto change the default assumptions. Default value is FALSE.")

parser <- add_option(parser, c("--w_att"), action = "store", default = 0.7, type = "double",
                     help="Water attenuation factor (default = 0.7) for legacy water\n\t\tscaling. Assumes water T2 of 80ms and a TE = 30 ms.\n\t\texp(-30ms / 80ms) ~ 0.7.")

parser <- add_option(parser, c("--w_conc"), action = "store", default = 35880, type = "double",
                     help="Assumed water concentration (default = 35880) for legacy water\n\t\tscaling. Default value corresponds to typical white matter.\n\t\tSet to 43300 for gray matter, and 55556 for phantom\n\t\tmeasurements.")

parser <- add_option(parser, c("--use_basis_cache"), action = "store", default = "auto", type = "character",
                     help="Pre-cache basis sets to reduce analysis speed. Can be one of\n\t\tthe following : \"auto\", \"all\" or \"none\". The default value of\n\t\t\"auto\" will only use the cache for 3T PRESS - which generally\n\t\trequires more detailed simulation due to high CSD.")

parser <- add_option(parser, c("--summary_measures"), action = "store", type = "character",
                     help="Output an additional table with a subset of metabolite levels,\n\t\teg c(\"tNAA\", \"tNAA/tCr\", \"tNAA/tCho\", \"Lac/tNAA\").")

parser <- add_option(parser, c("--dyn_av_block_size"), action = "store", type = "integer",
                     help="Perform temporal averaging with the specified block size.\n\t\tDefaults to NULL, eg average across all dynamic scans.")

parser <- add_option(parser, c("--dyn_av_scheme"), action = "store", type = "character",
                     help="A numeric vector of sequential integers starting at 1,\n\t\twith the same length as the number of dynamic scans in the\n\t\tmetabolite data. For example: c(1, 1, 2, 1, 1, 3, 1, 1).")

parser <- add_option(parser, c("--dyn_av_scheme_file"), action = "store", type = "character",
                       help="A file path containing a single column of sequential integers\n\t\t(starting at 1) with the same length as the number of dynamic\n\t\tscans in the metabolite data. File may be formatted as .xlsx,\n\t\t.xls, text or csv format.")

parser <- add_option(parser, c("--lcm_bin_path"), action = "store", type = "character",
                     help="Set the path to LCModel binary.")

parser <- add_option(parser, c("--plot_ppm_xlim"), action = "store", type = "character",
                     help="Plotting ppm axis limits in the html results.")

parser <- add_option(parser, c("--extra_output"), action = "store", default = FALSE,
                     help="Write extra output files for generating custom plots. Defaults\n\t\tto FALSE.")

parser <- add_option(parser, c("-v", "--verbose"), action = "store", default = FALSE,
                     help="Output potentially useful information.")

opt <- parse_args(parser)

if (is.null(opt[["input"]])) {
    print_help(parser)
    stop("Input MRS file needed, specify with -i or --input arguments.")
}

# convert p_vols to numeric vector
if (!is.null(opt[["p_vols"]])) {
  opt[["p_vols"]] <- eval(parse(text = opt[["p_vols"]]))
}

# convert fit_subset to numeric vector
if (!is.null(opt[["fit_subset"]])) {
  opt[["fit_subset"]] <- eval(parse(text = opt[["fit_subset"]]))
}

# convert dyn_av_scheme to numeric vector
# n.b. needs to be indexed differently to avoid clashing with dyn_av_scheme_file
# due to default of partial matching when using dollar notation
if (!is.null(opt[["dyn_av_scheme"]])) {
  opt[["dyn_av_scheme"]] <- eval(parse(text = opt[["dyn_av_scheme"]]))
}

# convert plot_ppm_xlim to numeric vector
if (!is.null(opt[["plot_ppm_xlim"]])) {
  opt[["plot_ppm_xlim"]] <- eval(parse(text = opt[["plot_ppm_xlim"]]))
}

fit_res <- fit_svs(input = opt[["input"]],
                   w_ref = opt[["w_ref"]],
                   output_dir = opt[["output_dir"]],
                   mri = opt[["mri"]],
                   mri_seg = opt[["mri_seg"]],
                   external_basis = opt[["external_basis"]],
                   append_external_basis = opt[["append_external_basis"]],
                   p_vols = opt[["p_vols"]],
                   format = opt[["format"]],
                   pul_seq = opt[["pul_seq"]],
                   TE = opt[["TE"]],
                   TR = opt[["TR"]],
                   TE1 = opt[["TE1"]],
                   TE2 = opt[["TE2"]],
                   TE3 = opt[["TE3"]],
                   TM = opt[["TM"]],
                   append_basis = opt[["append_basis"]],
                   remove_basis = opt[["remove_basis"]],
                   pre_align = opt[["pre_align"]],
                   dfp_corr = opt[["dfp_corr"]],
                   output_ratio = opt[["output_ratio"]],
                   ecc = opt[["ecc"]],
                   hsvd_width = opt[["hsvd_width"]],
                   decimate = opt[["decimate"]],
                   trunc_fid_pts = opt[["trunc_fid_pts"]],
                   fit_method = opt[["fit_method"]],
                   fit_opts = opt[["fit_opts"]],
                   fit_subset = opt[["fit_subset"]],
                   legacy_ws = opt[["legacy_ws"]],
                   w_att = opt[["w_att"]],
                   w_conc = opt[["w_conc"]],
                   use_basis_cache = opt[["use_basis_cache"]],
                   summary_measures = opt[["summary_measures"]],
                   dyn_av_block_size = opt[["dyn_av_block_size"]],
                   dyn_av_scheme = opt[["dyn_av_scheme"]],
                   dyn_av_scheme_file = opt[["dyn_av_scheme_file"]],
                   lcm_bin_path = opt[["lcm_bin_path"]],
                   plot_ppm_xlim = opt[["plot_ppm_xlim"]],
                   extra_output = opt[["extra_output"]],
                   verbose = opt[["verbose"]])
