## This function is to calculate a percentile threshold of an input variable
## The function accepts daily data and gives the output as the amount of days 
## which exceed the threshold for the defined forecast period.

## Limitation: function currently requires an input of minimum 2 forecast times.

percentile_threshold <- function(data, percentile, operator, spell, 
                                 forecast_periods, return.percent = TRUE, 
                                 indicator, ncores) {
  
  library(CSIndicators)
  
  if(is.null(spell)){
    spell <- 1
  }
  
  time_dim <- 'time'
  memb_dim <- 'ensemble'
  sdate_dim <- 'syear'
  
  if (!is.null(data$obs)) {
    result_obs <- c()
    result_aux <- c()
    ## Loop over forecast time
    for(ftime in 1:length(forecast_periods)){
    
    ## need to subset data by forecast time
    data_ftime <- CST_SelectPeriodOnData(data = data$obs, 
                                         start = list(1, forecast_periods[[ftime]]), 
                                         end = list(31, forecast_periods[[ftime]]),
                                         ncores = ncores)
    
    ## Calculate percentiles
    data_threshold <- CST_Threshold(data = data$obs, threshold = percentile,
                                    start = list(1, forecast_periods[[ftime]]), 
                                    end = list(31, forecast_periods[[ftime]]),
                                    time_dim = time_dim, memb_dim = memb_dim,
                                    sdate_dim = sdate_dim, na.rm = TRUE)
    
    if(spell == 1){
      ## Calculate number of days exceeding threshold
      time_exceeded <- CST_TotalTimeExceedingThreshold(
        data = data_ftime, threshold = data_threshold$data,
        start = list(1, forecast_periods[[ftime]]),
        end = list(31, forecast_periods[[ftime]]),
        op = operator, na.rm = TRUE, ncores = ncores)
    } else if(spell > 1){
      ## calculate number of days part of a spell
      time_exceeded <- CST_TotalSpellTimeExceedingThreshold(
        data = data_ftime, threshold = data_threshold$data,
        start = list(1, forecast_periods[[ftime]]), 
        end = list(31, forecast_periods[[ftime]]),
        spell = spell, op = operator, ncores = ncores)
    }
    ## return percentage of days instead of number
    if (return.percent) {
      days_per_month <- as.numeric(dim(data_ftime$data)['time'])
      time_exceeded$data <- round((time_exceeded$data/days_per_month)*100, 
                                  digits = 1)
    }
    ## Combine results in list for each forecast month
    result_aux[[ftime]] <- time_exceeded
  }
  ## bind list of forecast times
  result_obs <- CST_Bind(x = result_aux, along = 'time', 
                         var_dim = 'var', dat_dim = 'dat')
 }

  if (!is.null(data$hcst)) {
    result_hcst <- c()
    result_aux <- c()
    ## Loop over forecast time
    for(ftime in 1:length(forecast_periods)){
      
      ## need to subset data by forecast time
      data_ftime <- CST_SelectPeriodOnData(data = data$hcst, 
                                           start = list(1, forecast_periods[[ftime]]), 
                                           end = list(31, forecast_periods[[ftime]]),
                                           ncores = ncores)
      
      ## Calculate percentiles
      data_threshold <- CST_Threshold(data = data$hcst, threshold = percentile,
                                      start = list(1, forecast_periods[[ftime]]), 
                                      end = list(31, forecast_periods[[ftime]]),
                                      time_dim = time_dim, memb_dim = memb_dim,
                                      sdate_dim = sdate_dim, na.rm = TRUE)
      
      if(spell == 1){
        ## Calculate number of days exceeding threshold
        time_exceeded <- CST_TotalTimeExceedingThreshold(
          data = data_ftime, threshold = data_threshold$data,
          start = list(1, forecast_periods[[ftime]]), 
          end = list(31, forecast_periods[[ftime]]),
          op = operator, na.rm = TRUE, ncores = ncores)
      } else if (spell > 1){
        ## calculate number of days part of a spell
        time_exceeded <- CST_TotalSpellTimeExceedingThreshold(
          data = data_ftime, threshold = data_threshold$data,
          start = list(1, forecast_periods[[ftime]]), 
          end = list(31, forecast_periods[[ftime]]),
          spell = spell, op = operator, ncores = ncores)
      }
      ## return percentage of days instead of number
      if (return.percent) {
        days_per_month <- as.numeric(dim(data_ftime$data)['time'])
        time_exceeded$data <- round((time_exceeded$data/days_per_month)*100, 
                                    digits = 1)
      }
      result_aux[[ftime]] <- time_exceeded
    }
    result_hcst <- CST_Bind(x = result_aux, along = 'time', 
                            var_dim = 'var', dat_dim = 'dat')
 }
  
  if (!is.null(data$fcst)) {
    result_fcst <- c()
    result_aux <- c()
    ## Loop over forecast time
    for(ftime in 1:length(forecast_periods)){
      
      ## need to subset data by forecast time
      data_ftime <- CST_SelectPeriodOnData(data = data$fcst, 
                                           start = list(1, forecast_periods[[ftime]]), 
                                           end = list(31, forecast_periods[[ftime]]),
                                           ncores = ncores)
      
      ## Calculate percentiles
      data_threshold <- CST_Threshold(data = data$fcst, threshold = percentile,
                                      start = list(1, forecast_periods[[ftime]]), 
                                      end = list(31, forecast_periods[[ftime]]),
                                      time_dim = time_dim, memb_dim = memb_dim,
                                      sdate_dim = sdate_dim, na.rm = TRUE)
      
      if(spell == 1){
        ## Calculate number of days exceeding threshold
        time_exceeded <- CST_TotalTimeExceedingThreshold(
          data = data_ftime, threshold = data_threshold$data,
          start = list(1, forecast_periods[[ftime]]), 
          end = list(31, forecast_periods[[ftime]]),
          op = operator, na.rm = TRUE, ncores = ncores)
      } else if (spell > 1){
        ## calculate number of days part of a spell
        time_exceeded <- CST_TotalSpellTimeExceedingThreshold(
          data = data_ftime, threshold = data_threshold$data,
          start = list(1, forecast_periods[[ftime]]), 
          end = list(31, forecast_periods[[ftime]]),
          spell = spell, op = operator, ncores = ncores)
      }
      ## return percentage of days instead of number
      if (return.percent) {
        days_per_month <- as.numeric(dim(data_ftime$data)['time'])
        time_exceeded$data <- round((time_exceeded$data/days_per_month)*100, 
                                    digits = 1)
      }
      result_aux[[ftime]] <- time_exceeded
    }
    result_fcst <- CST_Bind(x = result_aux, along = 'time', 
                            var_dim = 'var', dat_dim = 'dat')
  } else {
    result_fcst <- NULL
  }
  
  rm(result_aux)
  
  result <- list(hcst = result_hcst,
                 obs = result_obs,
                 fcst = result_fcst)

  for (element in names(result[!is.null(result)])) {
    old_var_name <- data[[element]]$attrs$Variable$varName
    old_metadata <- data[[element]]$attrs$Variable$metadata[[old_var_name]]
    
    result[[element]]$coords$var <- indicator
    result[[element]]$attrs$Variable$varName <- indicator
    result[[element]]$attrs$Variable$metadata[[indicator]] <- old_metadata
    result[[element]]$attrs$Variable$metadata[[indicator]]$long_name <- indicator ## temporarily setting to short name
    if (return.percent){
      result[[element]]$attrs$Variable$metadata[[indicator]]$units <- '% days'
    } else {
      result[[element]]$attrs$Variable$metadata[[indicator]]$units <- 'days'
    }
  }
  
  return(result)
  
}
