# recipe
## Time_aggregation$execute YES/NO
## Time_aggregation$method accumulated or average
## Time_aggregation$user_def for decadal
## Time_aggregation$ini based on forecast time
## Time_aggregation$end based on forecast time
# For date definition of period aggregation consider using Indicators module
## ini = 2, end = 3 with monthly freq would be a 2 months agg
Aggregation <- function(recipe, data) {

## Do we need this checks here?
  ncores <- recipe$Analysis$ncores # is it already checked? NULL or number
  na.rm <- ifelse(is.null(recipe$Analysis$remove_NAs), 
                  TRUE, recipe$Analysis$remove_NAs) # is it already checked? TRUE/FALSE
  if (recipe$Analysis$Workflow$Time_aggregation$execute) {
    # original freq
    raw_freq <- tolower(recipe$Analysis$Variable$freq)
    custom <- recipe$Analysis$Workflow$Time_aggregation$user_def
    ini <- recipe$Analysis$Workflow$Time_aggregation$ini
    end <- recipe$Analysis$Workflow$Time_aggregation$end
    method <- tolower(recipe$Analysis$Workflow$Time_aggregation$method)
## Instead of raw freq may be better to use ini/end
##    if (raw_freq %in% c('daily', 'daily_mean', 'weekly', 'weekly_mean')) {
    if (!is.null(ini) && !is.null(end)) {
      # calculate aggregations from fday1 to fday2
      # calculate aggregations from fweek1 to fweek2
      # other cases could be indicators or other original freq
      if (length(ini) == length(end)) {
        res <- sapply(1:length(data), function(x) {
                      if (!is.null(data[[x]])) {
                        result <- agg_ini_end(data[x], method = method,
                                              na.rm = na.rm, ncores = ncores,
                                              ini = ini, end = end, indices = NULL)
                      } else {
                        result <- data[x]
                      }}, simplify = TRUE)
      }                   
    } else if (!is.null(custom)) {
      # caluclate aggreagtions from fmonth1 to ftmonth2
      # for decadal, it makes sense to get all seasons and annual means too
      ## Ex: January, February, March for decadal simulations aggregation
      ## custom <- sort(c(seq(1,120, 12), seq(2,120,13), seq(3, 120, 14)))
      if (is.list(custom)) {
        res <- sapply(1:length(data), function(x) {
                      if (!is.null(data[[x]])) {
                        result <- agg_ini_end(data[x], method, na.rm, ncores,
                                              indices = custom, ini = NULL, end = NULL)
                      } else {
                        result <- data[x]}}, simplify = TRUE)
      } else {
        stop("Why Time_aggregation$user_def is not a list?")
      }
    } else {
      # higher frequencies are typically used to compute indicators
      # lower frequencies are not typically stored in esarchive
      stop("Temporal aggregation not implemented yet")
    }
  }
}

agg_ini_end <- function(x, ini, end, indices = NULL, method, na.rm , ncores) {
  # to make the code work with both options:
  if (!is.null(ini) && is.null(indices)) {
    # list of vectors for the indices from ini to end pairs
    indices <- lapply(1:length(ini), function(x) { 
                    ini[x]:end[x]})
    plotting_attr <- list(ini_ftime = ini, end_ftime = end)
  } else {
    # take the firs and las element of each indices list for time_bounds saving
    ini <- unlist(lapply(indices, function(x){x[1]}))
    end <- unlist(lapply(indices, function(x){x[length(x)]}))
    plotting_attr <- list(names(indices))
  }
  original_dims <- names(dim(x[[1]]$data))
  if (method == 'average') { 
    x[[1]]$data <- Apply(x[[1]]$data, target_dim = 'time',
                                    function(y, ind) {
                                    sapply(1:length(indices), function(z) {
                                      mean(y[indices[[z]]], na.rm = na.rm)})},                                                                    ind = indices, output_dims = 'time',
                                    ncores = ncores)$output1
  } else if (method == 'accumulated') {
    x[[1]]$data <- Apply(x[[1]]$data, target_dim = 'time',
                                   function(y, ind) {
                                    sapply(1:length(indices), function(z) {
                                      sum(y[indices[[z]]], na.rm = na.rm)})},                                                                    ind = indices, output_dims = 'time',
                                    ncores = ncores)$output1
  } else {
    stop("Unknown method")
  }
  # Check in case only 1 aggregation only is requested to add time dim back:
  if (!('time' %in% names(dim(data[[1]]$data)))) {
    dim(x[[1]]$data) <- c( dim(x[[1]]$data), time = 1)
  }
  x[[1]]$data <- Reorder(x[[1]]$data, original_dims)
  x[[1]]$dims <- dim(x[[1]]$data)
  x[[1]]$coords$time <- 1:length(ini) 
  attr(x[[1]]$coords$time, "indices") <- TRUE
  tmp_dates <- Subset(x[[1]]$attrs$Dates, along = 'time',
                               indices = ini) 
  x[[1]]$attrs$time_bounds$start <- tmp_dates
  x[[1]]$attrs$time_bounds$end <- Subset(x[[1]]$attrs$Dates, along = 'time',
                                         indices = end)
  attributes(x[[1]]$attrs$time_bounds)$plotting_attr <- plotting_attr
  x[[1]]$attrs$Dates <- tmp_dates 
  return(x)
}
