# Compute the hcst, obs and fcst anomalies with or without cross-validation
# and return them, along with the hcst and obs climatologies.

compute_anomalies <- function(recipe, data) {

  if (is.null(recipe$Analysis$Workflow$Anomalies$compute)) {
    error(recipe$Run$logger, 
          paste("The anomaly module has been called, but the element",
                "'Workflow:Anomalies:compute' is missing from the recipe."))
    stop()
  }

  if (recipe$Analysis$Workflow$Anomalies$compute) {
    if (recipe$Analysis$Workflow$Anomalies$cross_validation) {
      cross <- TRUE
      cross_msg <- "with"
    } else {
      cross <- FALSE
      cross_msg <- "without"
    }
    original_dims <- data$hcst$dim

    # Compute anomalies
    anom <- CST_Anomaly(data$hcst, data$obs,
                        cross = cross,
                        memb = TRUE,
                        memb_dim = 'ensemble',
                        dim_anom = 'syear',
                        dat_dim = c('dat', 'ensemble'),
                        ftime_dim = 'time',
                        ncores = recipe$Analysis$ncores)
    # Reorder dims
    anom$exp$data <- Reorder(anom$exp$data, names(original_dims))
    anom$obs$data <- Reorder(anom$obs$data, names(original_dims))

    # Save full fields
    hcst_fullvalue <- data$hcst
    obs_fullvalue <- data$obs
    
    # Hindcast climatology 

    data$hcst <- anom$exp
    data$obs <- anom$obs
    remove(anom)
    # Change variable metadata
    for (var in data$hcst$attrs$Variable$varName) {
      # Change hcst longname
      data$hcst$attrs$Variable$metadata[[var]]$long_name <-
        paste(data$hcst$attrs$Variable$metadata[[var]]$long_name, "anomaly")
      # Change obs longname
      data$obs$attrs$Variable$metadata[[var]]$long_name <- 
	paste(data$obs$attrs$Variable$metadata[[var]]$long_name, "anomaly")
    }
    # Compute forecast anomaly field
    if (!is.null(data$fcst)) {
      # Compute hindcast climatology ensemble mean
      clim <- s2dv::Clim(hcst_fullvalue$data, obs_fullvalue$data,
                         time_dim = "syear",
                         dat_dim = c("dat", "ensemble"),
                         memb = FALSE,
                         memb_dim = "ensemble",
                         ftime_dim = "time",
                         ncores = recipe$Analysis$ncores)
      clim_hcst <- InsertDim(clim$clim_exp, posdim = 1, lendim = 1,
                             name = "syear")
      # Store original dimensions
      dims <- dim(clim_hcst)
      # Repeat the array as many times as ensemble members
      clim_hcst <- rep(clim_hcst, data$fcst$dim[['ensemble']])
      # Rename and reorder dimensions
      dim(clim_hcst) <- c(dims, ensemble = data$fcst$dim[['ensemble']])
      clim_hcst <- Reorder(clim_hcst, order = names(data$fcst$dim))
      # Get fcst anomalies
      data$fcst$data <- data$fcst$data - clim_hcst
      # Change metadata
      for (var in data$fcst$attrs$Variable$varName) {
	data$fcst$attrs$Variable$metadata[[var]]$long_name <-
	  paste(data$fcst$attrs$Variable$metadata[[var]]$long_name, "anomaly")
      }
    }

    info(recipe$Run$logger,
         paste("The anomalies have been computed,", cross_msg,
               "cross-validation. The original full fields are returned as",
               "$hcst.full_val and $obs.full_val."))

    info(recipe$Run$logger, "##### ANOMALIES COMPUTED SUCCESSFULLY #####")
    # Save outputs
    recipe$Run$output_dir <- paste0(recipe$Run$output_dir,
                                    "/outputs/Anomalies/")
    # Save forecast
    if ((recipe$Analysis$Workflow$Anomalies$save %in% 
         c('all', 'exp_only', 'fcst_only')) && !is.null(data$fcst)) {
      save_forecast(recipe = recipe, data_cube = data$fcst, type = 'fcst')
    }
    # Save hindcast
    if (recipe$Analysis$Workflow$Anomalies$save %in%
        c('all', 'exp_only')) {
      save_forecast(recipe = recipe, data_cube = data$hcst, type = 'hcst')
    }
    # Save observation
    if (recipe$Analysis$Workflow$Anomalies$save == 'all') {
      save_observations(recipe = recipe, data_cube = data$obs)
    }
  } else {
    warn(recipe$Run$logger, paste("The Anomalies module has been called, but",
         "recipe parameter Analysis:Variables:anomaly is set to FALSE.",
         "The full fields will be returned."))
    hcst_fullvalue <- NULL
    obs_fullvalue <- NULL
    info(recipe$Run$logger, "##### ANOMALIES NOT COMPUTED #####")
  }

  ## TODO: Return fcst full value?
  .log_memory_usage(recipe$Run$logger, "After computing anomalies")

  return(list(hcst = data$hcst, obs = data$obs, fcst = data$fcst,
              hcst.full_val = hcst_fullvalue, obs.full_val = obs_fullvalue))

}
