#'Function to create all single system/reference scorecards
#' 
#'@description Scorecards function to create scorecard tables for one system and 
#'  one reference combination (types 1 to 4).
#'@param data is an array of spatially aggregated metrics containing the
#'   following dimensions; system, reference, metric, time, sdate, region.
#'@param sign is an array with the same dimensions as data indicting the 
#'   significance of the metrics, with either true, false or null.
#'@param system a vector of character strings defining the systems following the
#'   archive.yml format from verification suite 
#'@param reference a vector of character strings defining the references 
#'  following the archive.yml format from verification suite 
#'@param var a character string following the format from 
#'  variable-dictionary.yml from verification suite 
#'@param start.year a numeric indicating the start year of the reference period
#'@param end.year a numeric indicating the end year of the reference period
#'@param start.date a vector of character strings indicating the start months
#'@param forecast.month a vector of numeric indicating the forecast months
#'@param region.names a vector of character strings containing names of the 
#'  regions corresponding to the input data
#'@param metrics a vector of character strings containing the metrics.
#'@param table.label a character string containing additional information to 
#'  include in the scorecard title
#'@param fileout.label a character string containing additional information to 
#'  include in the output png file when saving the scorecard.
#'@param plot.legend A logical value to determine if the legend is plotted.
#'@param legend.breaks A vector of numerics or a list of vectors of numerics,
#'  containing the breaks for the legends. If a vector is given as input, then 
#'  these breaks will be repeated for each legend.dim. A list of vectors can be 
#'  given as input if the legend.dims require different breaks. This parameter 
#'  is required even if the legend is not plotted, to define the colors in the 
#'  scorecard table.
#'@param legend.white.space A numeric value defining the initial starting 
#'  position of the legend bars, the white space infront of the legend is 
#'  calculated from the left most point of the table as a distance in cm.
#'@param legend.width A numeric value to define the width of the legend bars.
#'@param legend.height A numeric value to define the height of the legend bars.
#'@param label.scale A numeric value to define the size of the legend labels.
#'@param col1.width A numeric value defining the width of the first table column
#'  in cm.
#'@param col2.width A numeric value defining the width of the second table 
#'  column in cm.
#'@param columns.width A numeric value defining the width all columns within the 
#'  table in cm (excluding the first and second columns containing the titles).
#'@param font.size A numeric indicating the font size on the scorecard table.
#'@param round.decimal A numeric indicating to which decimal point the data 
#'  is to be displayed in the scorecard table. Default is 2.
#'@param output.path A path of the location to save the scorecard plots
#'
#'@return
#' This function returns 4 scorecards images, saved in the directory output.path
#'@examples
#' scorecard_single <- ScorecardsSingle(data = aggregated_metrics,
#'                                     system.name = c('ECMWF-SEAS5','DWD-GFCS2.1'),
#'                                     reference.name = 'ERA5',
#'                                     var = 'tas', 
#'                                     start.year = 1993,
#'                                     end.year = 2016,
#'                                     start.months = 1:12,
#'                                     forecast.months = 1:6,
#'                                     region.names = c('Tropics', 'Extra-tropical NH', 'Extra-tropical SH')
#'                                     metrics = c('mean_bias', 'enscorr', 'rpss','crpss', 'enssprerr'),
#'                                     table.label = '(Interpolation = to system, Aggregation level = skill, Cross-validation = terciles)',
#'                                     fileout.label = '_crossval-terciles_agg-skill',
#'                                     output.path = '/esarchive/scratch/nmilders/scorecards_images/test'
#'                                     )
#'@export
ScorecardsSingle <- function(data, sign, system, reference, var, start.year, 
                             end.year, start.months, forecast.months, 
                             region.names, metrics, plot.legend = TRUE, 
                             legend.breaks = NULL, legend.white.space = NULL, 
                             legend.width = 550, legend.height = 50,
                             table.label = NULL, fileout.label =  NULL,
                             label.scale =  1.4, font.size = 1.1, 
                             col1.width = NULL, col2.width = NULL, 
                             columns.width = 1.2,
                             round.decimal = 2, output.path){

    ## Checks to apply:
  # First dimension in aggregated_metrics is system and second dimension is reference
  # To allow 1 region - if region = 1 --> only scorecards 1 & 3 need to be plotted
  # If any dimension of input dat is 1, make sure dimension is still present in array
  
  ## Initial checks
  # data
  if (!is.array(data)) {
    stop("Parameter 'data' must be an array with named dimensions.")
  }
  if (!is.array(data)) {
    stop("Parameter 'data' must be an array with named dimensions.")
  }
  if (is.null(names(dim(data)))) {
    stop("Parameter 'data' must have dimenision names.")
  }
  if (!all(c('system','reference','metric','time','sdate','region') %in% 
           names(dim(data)))) {
    stop("Dimension names of 'data' must be: 'system','reference','metric', 
          'time','sdate','region'.")
  }
  if (is.null(table.label)){
    table.label <- ""
  }
  if (is.null(fileout.label)){
    fileout.label <- ""
  }
  
  ## Make sure data is in correct order for using in functions:
  data_order <- c('system', 'reference', 'metric', 'time', 'sdate', 'region')
  data <- Reorder(data, data_order)
  
  ## Identify metrics loaded
  metrics_loaded <-  attributes(data)$metrics

  ## Select only the metrics to visualize from data
  data <- Subset(data, along = 'metric', indices = match(metrics, metrics_loaded))
  attributes(data)$metrics <- metrics

  if(!is.null(sign)){
    sign <- Reorder(sign, data_order)
    sign <- Subset(sign, along = 'metric', indices = match(metrics, metrics_loaded))
    attributes(sign)$metrics <- metrics
  }
  
  ## Transform data for scorecards by forecast month (types 3 & 4)
  if(length(start.months) >= length(forecast.months)){
    
    transformed_data <- SCTransform(data = data,
                                    sdate_dim = 'sdate', 
                                    ftime_dim = 'time')
    
    if(!is.null(sign)){
      transformed_sign <- SCTransform(data = sign, 
                                      sdate_dim = 'sdate', 
                                      ftime_dim = 'time')
    } else {
      transformed_sign <- NULL
    }
  }
  
  ## Load configuration files
  if (is.null(recipe$Run$filesystem)) {
    filesystem <- 'esarchive'
  } else {
    filesystem <- recipe$Run$filesystem
  }
  sys_dict <- read_yaml("conf/archive.yml")[[filesystem]]
  var_dict <- read_yaml("conf/variable-dictionary.yml")$vars
  
  ## Get scorecards table display names from configuration files
  var.name <- var_dict[[var]]$long_name
  
  if ('name' %in% names(recipe$Analysis$Variables)){
    if (recipe$Analysis$Variables$name == var) {
      var.units <- recipe$Analysis$Variables$units
    }
  } else {
    for (i in 1:length(recipe$Analysis$Variables)) {
      if (recipe$Analysis$Variables[[i]]$name == var) { 
        var.units <- recipe$Analysis$Variables[[i]]$units 
      }
     }
    }
  if (is.null(var.units)) {
    var.units <- var_dict[[var]]$units
  }
  
  ## Get metric long names
  metric.names.list <- .met_names(metrics, var.units)
  
  ## format the metric names as character instead of list
  for(met in metrics){
    if(met == metrics[1]){
      metric.names <- metric.names.list[[met]] 
    } else {
      metric.names <- c(metric.names, metric.names.list[[met]])
    }
  }
  
  ## Define table colors 
  palette <- c('#2D004B', '#542789', '#8073AC', '#B2ABD2', '#D8DAEB', '#FEE0B6', '#FDB863', '#E08214', '#B35806', '#7F3B08')
  colorunder <- "#04040E"
  colorsup <- "#730C04"
  
  ## Legend lower limit color
  legend.col.inf <- .legend_col_inf(metrics, colorunder)
  legend.col.inf <- legend.col.inf[metrics]

  ## Legend upper limit color
  legend.col.sup <- .legend_col_sup(metrics, colorsup)
  legend.col.sup <- legend.col.sup[metrics]

  ## Loop over system and reference for each scorecard plot
  for (sys in 1:dim(data)['system']) {
    for (ref in 1:dim(data)['reference']) {
      
      ## TO DO: Apply check to each scorecard function
      ## check dimension 'metric' exists:
      if (!("metric" %in% names(dim(data)))) {
        dim(data) <- c(metric = 1, dim(data))
      }
      
      ## Find position of mean bias metric to calculate breaks
      breaks_bias <- NULL
      if ('mean_bias' %in% metrics){
        stopifnot(identical(names(dim(Subset(data, c('system', 'reference'), list(sys, ref), drop = 'selected'))), c('metric','time','sdate','region')))
        temp_data <- Subset(data, c('system', 'reference'), list(sys, ref), drop = 'selected')
        pos_bias <- which(metrics == 'mean_bias')
        if(var == 'psl'){
          temp_data[pos_bias,,,] <- temp_data[pos_bias,,,]/100
        }
        breaks_bias <- .SCBiasBreaks(Subset(temp_data, along = 'metric',
                                            indices = pos_bias))
      }
      
      ## Define breaks for each metric based of metric position:
      legend.breaks <- .met_breaks(metrics, breaks_bias)
      
      ## Put breaks in same order as metrics
      legend.breaks <- legend.breaks[metrics]
      
      ## Get scorecards table display names from configuration files
      system.name <- sys_dict$System[[system[sys]]]$name
      reference.name <- sys_dict$Reference[[reference[ref]]]$name
      
      ## Define scorecard titles
      table.title <- paste0(var.name, " of ", system.name, " ", table.label)
      table.subtitle <- paste0("(Ref: ", reference.name, " ", start.year, "-", end.year, ")")
      
      #############################################################################     
      
      #### Scorecard_type 1 ####
      ## (no transformation or reorder)
      fileout <- .Filename(system = system[sys], reference = reference[ref], var = var,
                           start.year = start.year, end.year = end.year, scorecard.type = 1,
                           fileout.label = fileout.label, output.path = output.path)
      
      data_sc_1 <- Subset(data, c('system', 'reference'), list(sys, ref), drop = 'selected')
      
      if(!is.null(sign)){
        sign_sc_1 <- Subset(sign, c('system', 'reference'), list(sys, ref), drop = 'selected')
      } else {
        sign_sc_1 <- NULL
      }
      
      VizScorecard(data = data_sc_1,
                   sign = sign_sc_1,
                   row_dim = 'region',
                   subrow_dim = 'time',
                   col_dim = 'metric',
                   subcol_dim = 'sdate',
                   legend_dim = 'metric',
                   row_names = region.names,
                   subrow_names = forecast.months,
                   col_names = metric.names,
                   subcol_names = month.abb[as.numeric(start.months)],
                   table_title = table.title,
                   table_subtitle = table.subtitle,
                   row_title = 'Region',
                   subrow_title = 'Forecast Month',
                   col_title = 'Start date',
                   legend_breaks = legend.breaks,
                   plot_legend = plot.legend,
                   label_scale = label.scale,
                   legend_width = legend.width,
                   legend_height = legend.height,
                   palette = palette,
                   colorunder = legend.col.inf,
                   colorsup = legend.col.sup,
                   round_decimal = round.decimal,
                   font_size = font.size,
                   legend_white_space = legend.white.space, 
                   col1_width = col1.width,
                   col2_width = col2.width,
                   columns_width = columns.width,
                   fileout = fileout)
      
      
      #### Scorecard_type 2 ####
      ## (reorder only)
      ## Scorecard type 2 is same as type 1 for only one region, therefore is
      ## only plotted if more that one region is requested
      if(dim(data)['region'] > 1) {
        
        fileout <- .Filename(system = system[sys], reference = reference[ref], var = var,
                             start.year = start.year, end.year = end.year, scorecard.type = 2,
                             fileout.label = fileout.label, output.path = output.path)
        
        new_order <- c('metric', 'region', 'sdate', 'time')
        
        data_sc_2 <- Reorder(Subset(data, c('system', 'reference'), list(sys, ref), drop = 'selected'), new_order)
        
        if(!is.null(sign)){
          sign_sc_2 <- Reorder(Subset(sign, c('system', 'reference'), list(sys, ref), drop = 'selected'), new_order)
        } else {
          sign_sc_2 <- NULL
        }
        
        VizScorecard(data = data_sc_2,
                     sign = sign_sc_2,
                     row_dim = 'time',
                     subrow_dim = 'region',
                     col_dim = 'metric',
                     subcol_dim = 'sdate',
                     legend_dim = 'metric',
                     row_names = forecast.months,
                     subrow_names = region.names,
                     col_names = metric.names,
                     subcol_names = month.abb[as.numeric(start.months)],
                     table_title = table.title,
                     table_subtitle = table.subtitle,
                     row_title = 'Forecast Month',
                     subrow_title = 'Region',
                     col_title = 'Start date',
                     legend_breaks = legend.breaks,
                     plot_legend = plot.legend,
                     label_scale = label.scale,
                     legend_width = legend.width,
                     legend_height = legend.height,
                     palette = palette,
                     colorunder = legend.col.inf,
                     colorsup = legend.col.sup,
                     round_decimal = round.decimal,
                     font_size = font.size,
                     legend_white_space = legend.white.space, 
                     col1_width = col1.width,
                     col2_width = col2.width,
                     columns_width = columns.width,
                     fileout = fileout)
      } ## close if


      #### Scorecard_type 3 ####
      ## (transformation only)
      
      if(length(start.months) >= length(forecast.months)){
        fileout <- .Filename(system = system[sys], reference = reference[ref], var = var,
                             start.year = start.year, end.year = end.year, scorecard.type = 3,
                             fileout.label = fileout.label, output.path = output.path)
        
        data_sc_3 <- Subset(transformed_data, c('system', 'reference'), list(sys, ref), drop = 'selected')
        
        if(!is.null(sign)){
          sign_sc_3 <- Subset(transformed_sign, c('system', 'reference'), list(sys, ref), drop = 'selected')
        } else {
          sign_sc_3 <- NULL
        }
        
        VizScorecard(data = data_sc_3,
                     sign = sign_sc_3,
                     row_dim = 'region',
                     subrow_dim = 'time',
                     col_dim = 'metric',
                     subcol_dim = 'sdate',
                     legend_dim = 'metric',
                     row_names = region.names,
                     subrow_names = forecast.months,
                     col_names = metric.names,
                     subcol_names = month.abb[as.numeric(start.months)],
                     table_title = table.title,
                     table_subtitle = table.subtitle,
                     row_title = 'Region',
                     subrow_title = 'Forecast Month',
                     col_title = 'Target month',
                     legend_breaks = legend.breaks,
                     plot_legend = plot.legend,
                     label_scale = label.scale,
                     legend_width = legend.width,
                     legend_height = legend.height,
                     palette = palette,
                     colorunder = legend.col.inf,
                     colorsup = legend.col.sup,
                     round_decimal = round.decimal,
                     font_size = font.size,
                     legend_white_space = legend.white.space, 
                     col1_width = col1.width,
                     col2_width = col2.width,
                     columns_width = columns.width,
                     fileout = fileout)
      }

      #### Scorecard_type 4 ####
      ## (transformation and reorder)
      ## Scorecard type 4 is same as type 3 for only one region, therefore is
      ## only plotted if more that one region is requested
      if(dim(data)['region'] > 1 & length(start.months) >= length(forecast.months)){
        
        fileout <- .Filename(system = system[sys], reference = reference[ref], var = var,
                             start.year = start.year, end.year = end.year, scorecard.type = 4,
                             fileout.label = fileout.label, output.path = output.path)
        
        new_order <- c('metric', 'region', 'sdate', 'time')
        
        data_sc_4 <- Reorder(Subset(transformed_data, c('system', 'reference'), list(sys, ref), drop = 'selected'), new_order)
        
        if(!is.null(sign)){
          sign_sc_4 <- Reorder(Subset(transformed_sign, c('system', 'reference'), list(sys, ref), drop = 'selected'), new_order)
        } else {
          sign_sc_4
        }
        
        VizScorecard(data = data_sc_4,
                     sign = sign_sc_4,
                     row_dim = 'time',
                     subrow_dim = 'region',
                     col_dim = 'metric',
                     subcol_dim = 'sdate',
                     legend_dim = 'metric',
                     row_names = forecast.months,
                     subrow_names = region.names,
                     col_names = metric.names,
                     subcol_names = month.abb[as.numeric(start.months)],
                     table_title = table.title,
                     table_subtitle = table.subtitle,
                     row_title = 'Forecast Month',
                     subrow_title = 'Region',
                     col_title = 'Target month',
                     legend_breaks = legend.breaks,
                     plot_legend = plot.legend,
                     label_scale = label.scale,
                     legend_width = legend.width,
                     legend_height = legend.height,
                     palette = palette,
                     colorunder = legend.col.inf,
                     colorsup = legend.col.sup,
                     round_decimal = round.decimal,
                     font_size = font.size,
                     legend_white_space = legend.white.space, 
                     col1_width = col1.width,
                     col2_width = col2.width,
                     columns_width = columns.width,
                     fileout = fileout)
      } ## close if
      
    } ## close loop on ref
  } ## close loop on sys
  
  print("All single system scorecard plots created")
  
} ## close function      



