## This function is to calculate the max spell days for a define threshold
## The function accepts daily data and gives the output as the amount of 
## maximum spell days corresponding to the the threshold for the defined
## forecast period.


CST_ConsecutiveDays <- function(data, threshold, operator, 
                                start = NULL, end = NULL,
                                time_dim = 'time', ncores = NULL) {
  # Check 's2dv_cube'
  if (!inherits(data, 's2dv_cube')) {
    stop("Parameter 'data' must be of the class 's2dv_cube'.")
  }
  
  # Dates subset
  if (!is.null(start) && !is.null(end)) {
    if (is.null(dim(data$attrs$Dates))) {
      warning("Dimensions in 'data$attrs$Dates' are missing. All data will be used.")
      start <- NULL
      end <- NULL
    }
  }
  
  Dates <- data$attrs$Dates
  
  maxspell <- ConsecutiveDays(data$data, threshold = threshold,
                              operator = operator, 
                              dates = Dates, start = start, end = end,
                              time_dim = time_dim, ncores = ncores)
  
  data$data <- maxspell
  data$dims <- dim(maxspell)
  data$coords[[time_dim]] <- 1:length(data$dims[[time_dim]])
  
  if (!is.null(Dates)) {
    if (!is.null(start) && !is.null(end)) {
      Dates <- SelectPeriodOnDates(dates = Dates, start = start, end = end,
                                   time_dim = time_dim, ncores = ncores)
    }
    
    if (is.null(dim(Dates))) {
      warning("Element 'Dates' has NULL dimensions. They will not be subset and 'time_bounds' will be missed.")
      data$attrs$Dates <- Dates
    } else {
      time_bounds <- NULL
      time_bounds$start <- ClimProjDiags::Subset(Dates, along = time_dim,
                                                 indices = 1, drop = FALSE)
      time_bounds$end <- ClimProjDiags::Subset(Dates, along = time_dim, 
                                               indices = dim(Dates)[time_dim],
                                               drop = FALSE)
      
      data$attrs$Dates <- time_bounds$start
      data$attrs$time_bounds <- time_bounds
    }
  }
  
  return(data)
}




ConsecutiveDays <- function(data, threshold, operator, 
                            dates = NULL, start = NULL, end = NULL,
                            time_dim = 'time', ncores = NULL) {
  
  if (!is.numeric(data)) {
    stop("Parameter 'data' must be numeric.")
  }
  if (!is.array(data)) {
    dim(data) <- length(data)
    names(dim(data)) <- time_dim
  }
  if (is.null(names(dim(data)))) {
    stop("Parameter 'data' must have named dimensions.")
  }
  
  if (!is.character(time_dim)) {
    stop("Parameter 'time_dim' must be a character string.")
  }
  if (!all(time_dim %in% names(dim(data)))) {
    stop("Parameter 'time_dim' is not found in 'data' dimension.")
  }
  
  if (!is.null(start) && !is.null(end) && !is.null(dates)) {
    if (!is.list(start) || !is.list(end)) {
      stop("Parameters 'start' and 'end' must be lists with day and month.")
    }
    data <- SelectPeriodOnData(data, dates, start, end, time_dim, ncores)
  }
  
  max_spell <- Apply(list(data), target_dims = time_dim,
                     fun = .max_consecutive_days, 
                     args = list(threshold = threshold, operator = operator),
                     ncores = ncores)$output1
  
  
  dim(max_spell) <- c(dim(max_spell), setNames(1, time_dim))
  return(max_spell)
}


.max_consecutive_days <- function(x, threshold , operator) {
  x <- unlist(x)
  op_fun <- match.fun(operator)  
  dry <- op_fun(x, threshold)
  rle_out <- rle(dry)
  if (any(rle_out$values)) {
    return(max(rle_out$lengths[rle_out$values], na.rm = TRUE))
  } else {
    return(0)
  }
}
