# Full-cross-val workflow
## This code should be valid for individual months and temporal averages
source("modules/Crossval/R/tmp/GetProbs.R")
  
Crossval_anomalies_for <- function(recipe, data) {
  cross.method <- recipe$Analysis$cross.method
  # TODO move check
  if (is.null(cross.method)) {
    cross.method <- 'leave-one-out'
  }
  categories <- recipe$Analysis$Workflow$Probabilities$percentiles
  categories <- lapply(categories, function (x) { 
                       sapply(x, function(y) {
                              eval(parse(text = y))})})
  ncores <- recipe$Analysis$ncores
  na.rm <- recipe$Analysis$remove_NAs 
  ## data dimensions 
  sdate_dim <- dim(data$hcst$data)['syear']
  orig_dims <- names(dim(data$hcst$data))
  # spatial dims
  if ('latitude' %in% names(dim(data$hcst$data))) {
    nlats <- dim(data$hcst$data)['latitude']
    nlons <- dim(data$hcst$data)['longitude']
    agg = 'global'
  } else if  ('region' %in% names(dim(data$hcst$data))) {
    agg = 'region'
    nregions <- dim(data$hcst$data)['region']
  }
  # output_dims from loop base on original dimensions
  ## ex: 'dat', 'var', 'sday', 'sweek', 'ensemble', 'time', 
  ##     'latitude', 'longitude', 'unneeded', 'syear'
  ev_dim_names <-  c(orig_dims[-which(orig_dims %in% 'syear')],
                     names(sdate_dim))
  orig_dims[orig_dims %in% 'ensemble'] <- 'unneeded'
  orig_dims[orig_dims %in% 'syear'] <- 'ensemble'
  tr_dim_names <-c(orig_dims,
                     names(sdate_dim))
  # TODO fix it to use new version https://earth.bsc.es/gitlab/external/cstools/-/blob/dev-cross-indices/R/CST_Calibration.R#L570
  cross <- CSTools:::.make.eval.train.dexes(eval.method = cross.method,
                                            amt.points = sdate_dim,
                                            amt.points_cor = NULL) # k = ?

  ## output objects
  ano_hcst_ev_res <- NULL
  ano_obs_ev_res <- NULL
  ano_obs_tr_res <- NULL
  # as long as probs requested in recipe:
  lims_ano_hcst_tr_res <- lapply(categories, function(X) {NULL})
  lims_ano_obs_tr_res <- lapply(categories, function(X) {NULL})

  fcst_probs <- lapply(categories, function(x){NULL})
  hcst_probs_ev <- lapply(categories, function(x){NULL})
  obs_probs_ev <- lapply(categories, function(x){NULL})

  for (t in 1:length(cross)) {
    info(recipe$Run$logger, paste("crossval:", t))

    # subset years: Subset works at BSC not at Athos
    ## training indices
    obs_tr <- Subset(data$obs$data, along = 'syear',
   		     indices = cross[[t]]$train.dexes)
    hcst_tr <- Subset(data$hcst$data, along = 'syear', 
  		      indices = cross[[t]]$train.dexes)
    ## evaluation indices
    hcst_ev <- Subset(data$hcst$data, along = 'syear',
  		      indices = cross[[t]]$eval.dexes, drop = 'selected')
    obs_ev <- Subset(data$obs$data, along = 'syear',
  		     indices = cross[[t]]$eval.dexes, drop = 'selected')
    if (tolower(recipe$Analysis$Horizon) == 'subseasonal') {
      central_day <- (dim(data$hcst$data)['sday'] + 1)/2
      hcst_tr <- MergeDims(hcst_tr, merge_dims = c('sday', 'syear'), 
                          rename_dim = 'syear', na.rm = FALSE) 

      obs_tr <- MergeDims(obs_tr, merge_dims = c('sday', 'syear'),
                          rename_dim = 'syear', na.rm = FALSE)
      # 'sday' dim to select the central day
      hcst_ev <- Subset(hcst_ev, along = 'sday', indices = central_day) 

    }
    # compute climatology:
    clim_obs_tr <- MeanDims(obs_tr, 'syear')
    clim_hcst_tr <- MeanDims(hcst_tr, c('syear', 'ensemble'))
    # compute anomalies:
    ano_obs_tr <- s2dv::Ano(obs_tr, clim_obs_tr,
                            ncores = ncores)
    ano_hcst_tr <- s2dv::Ano(hcst_tr, clim_hcst_tr,
                             ncores = ncores)
    ano_hcst_ev <- s2dv::Ano(hcst_ev, clim_hcst_tr,
                             ncores = ncores)
    ano_obs_ev <- s2dv::Ano(obs_ev, clim_obs_tr,
                            ncores = ncores)
    # compute category limits
    lims_ano_hcst_tr <- Apply(ano_hcst_tr, target_dims = c('syear', 'ensemble'),
                              fun = function(x, prob_lims) {
                                lapply(prob_lims, function(ps) {
                                  as.array(quantile(as.vector(x), ps,
                                                    na.rm = na.rm))})},
                              prob_lims = categories,
                              ncores = ncores)
    lims_ano_obs_tr <- Apply(ano_obs_tr, target_dims = c('syear'),#, 'ensemble'),
                             fun = function(x, prob_lims) {
                               lapply(prob_lims, function(ps) {
                                 as.array(quantile(as.vector(x), ps,
                                                   na.rm = na.rm))})},
                             prob_lims = categories,
                             ncores = ncores)
    if (tolower(recipe$Analysis$Horizon) == 'subseasonal') {
     ano_hcst_tr <- SplitDim(ano_hcst_tr, split_dim = 'syear',
                             new_dim_name = 'sday',
                             indices = rep(1:dim(data$hcst$data)['sday'],
                                           length(cross[[t]]$train.dexes)))
     ano_obs_tr <- SplitDim(obs_tr, split_dim = 'syear', new_dim_name = 'sday',
                        indices = rep(1:dim(data$hcst$data)['sday'],
                                      length(cross[[t]]$train.dexes)))
    }

    #store results
    ano_hcst_ev_res <- abind(ano_hcst_ev_res, ano_hcst_ev,
                             along = length(dim(ano_hcst_ev)) + 1)
    ano_obs_ev_res <- abind(ano_obs_ev_res, ano_obs_ev,
                            along = length(dim(ano_obs_ev)) + 1)
    ano_obs_tr_res <- abind(ano_obs_tr_res, ano_obs_tr,
                            along = length(dim(ano_obs_tr)) + 1)
    for(ps in 1:length(categories)) {
      lims_ano_hcst_tr_res[[ps]] <- abind(lims_ano_hcst_tr_res[[ps]], lims_ano_hcst_tr[[ps]],
                                along = length(dim(lims_ano_hcst_tr[[ps]])) + 1)
      lims_ano_obs_tr_res[[ps]] <- abind(lims_ano_obs_tr_res[[ps]], lims_ano_obs_tr[[ps]],
                                 along = length(dim(lims_ano_obs_tr[[ps]])) + 1)
    }
  }
  info(recipe$Run$logger,
       "#### Anomalies Cross-validation loop ended #####")
  return(list(lims_ano_hcst_tr_res = lims_ano_hcst_tr_res,
              lims_ano_obs_tr_res = lims_ano_obs_tr_res,
              ano_hcst_ev_res = ano_hcst_ev_res,
              ano_obs_ev_res = ano_obs_ev_res))
}


## The result contains the inputs for Skill_full_crossval.
## this is a list with the required elements:
  ## probs is a list with
    ## probs$hcst_ev and probs$obs_ev 
    ## probs$hcst_ev will have as many elements in the $Probabilities$percentiles
    ## each element will be an array with 'cat' dimension
    ## the same for probs$obs_ev
  ## hcst is a s2dv_cube for the post-processed hindcast for the evalutaion indices
    ## in this case cross validated anomalies
  ## obs is a s2dv_cube for the post-processed obs 
    ## in this case cross validated anomalies
  ## fcst is a s2dv_cube for the post-processed fcst
    ## in this case cross anomalies with the full hindcast period
    ## this object is not required for skill assessment
  ## hcst.full_val and obs.full_val are the original data to compute mean bias
  ## cat_lims used to compute the probabilities
    ## this object is not required for skill assessment
  ## ref_obs_tr is an array with the cross-validate observed anomalies
    ## to be used as reference forecast in the CRPSS and CRPS_clim
    ## it is computed from the training indices

