
plot_deterministic_forecast <- function(obs, fcst, title = NULL,
                                        xlabs = NULL, ylab = '', ylims = NULL,
                                        xlabs_pos = NULL, ylabs_pos = NULL,
                                        style = 'shading', col_obs = 'black',
                                        col_hcst = 'blue', col_fcst = 'red', 
                                        member_dim = 'member',
                                        time_dim = 'year',
                                        logo = NULL, caption = NULL,
                                        caption_line = NULL,
                                        legend_text = c('Observations', 'Hindcast',
                                                        'Forecast'),
                                        width = 1010, height = 510, res = NA,
                                        fileout = NULL) {
  n_obs <- as.numeric(dim(obs)[time_dim])
  n_fcst <- as.numeric(dim(fcst)[time_dim])
  
  if (is.null(ylims)) {
    if (all(is.na(fcst)) && all(is.na(obs))) {
      # No data, return random ylims
      ylims <- c(-1, 1)
    } else {
      ylims <- c(-max(abs(fcst) + 0.1, abs(obs) + 0.1, na.rm = TRUE),
                 max(abs(fcst) + 0.1, abs(obs) + 0.1, na.rm = TRUE))
    }
  }
  if (is.null(xlabs)) {
    xlabs <- 1:n_fcst
  }
  if (is.null(xlabs_pos)) {
    xlabs_pos <- -2 + seq(from = 1, to = n_fcst, by = 5)
  }
  if (is.null(ylabs_pos)) {
    ylabs_pos <- ylims[1] - 0.045 + par('usr')[3]
  }
  ## Opening the output file
  if (!is.null(fileout)) {
    png(filename = fileout, width = width, height = height, res = res)
  }
  if (identical(style, 'boxplot')) {
    if (!is.null(legend_text)) {
      right_mar <- max(c(nchar(legend_text), 8)) + 1 
    } else {
      right_mar <- 8
    }
    par(mar = c(7, 4.1, 4.1, right_mar))
  }
  ## Empty figure with the labs
  plot(x = 1:n_fcst, y = rep(0,n_fcst), col = col_obs, type = 'l', lwd = 1,
       xlab = '', ylab = ylab, main = title, xlim = c(1,n_fcst), ylim = ylims,
       cex.lab = 1.2, cex.main = 1.2, cex.axis = 1.2, frame.plot = TRUE,
       xaxt = 'n')
  axis(1, at = 1:n_fcst, labels = xlabs, cex = 1.5)
  #text(cex = 1.2, x = xlabs_pos, y = ylabs_pos, labels = xlabs[seq(from = 1, to = n_fcst, by = 5)], srt = 45, pos = 1, xpd = TRUE)
  
  ## Auxiliary lines
  abline(h = 0, lw = 1)
  abline(v = seq(from = 1, to = n_fcst, by = 5), lty = 2, lwd = 1, col = 'grey')
  #abline(h = seq(from = floor(ylims[1]), to = ceiling(ylims[2]), by = 1), lty = 2, col = 'grey')
  ## Ensemble spread
  if (identical(style, 'boxplot')) {
    ## Hindcast
    for (y in 1:n_obs) {
      boxplot(x = ClimProjDiags::Subset(x = fcst,
                                        along = time_dim,
                                        indices = y,
                                        drop = 'selected'),
              at = y, notch = FALSE, range = 0, add = TRUE,
              col = adjustcolor(col_hcst, alpha.f = 0.60),
              boxwex = 1, axes = F)
    }
    ## Forecast
    if (n_fcst > n_obs) {
      for (y in (n_obs+1):n_fcst) {
        boxplot(x = ClimProjDiags::Subset(x = fcst,
                                          along = time_dim,
                                          indices = y,
                                          drop = 'selected'),
                at = y, notch = FALSE, range = 0, add = TRUE,
                col = adjustcolor(col_fcst, alpha.f = 0.60),
                boxwex = 1, axes = F)
      }
    }
  } else if (identical(style, 'shading')) {
    fcst_quantiles <- multiApply::Apply(data = fcst, target_dims = member_dim,
                                        fun = function(x) {quantile(x = as.vector(x), type = 8, na.rm = FALSE)},
                                        ncores = 1)$output1
    ## Hindcast
    polygon(x = c(1:n_obs, rev(1:n_obs)),
            y = c(fcst_quantiles[4,1:n_obs], rev(fcst_quantiles[5,1:n_obs])),
            col = adjustcolor(col_hcst, alpha.f = 0.10),
            border = NA)
    polygon(x = c(1:n_obs, rev(1:n_obs)),
            y = c(fcst_quantiles[2,1:n_obs], rev(fcst_quantiles[4,1:n_obs])),
            col = adjustcolor(col_hcst, alpha.f = 0.30),
            border = NA)
    polygon(x = c(1:n_obs, rev(1:n_obs)),
            y = c(fcst_quantiles[1,1:n_obs],
                  rev(fcst_quantiles[2,1:n_obs])),
            col = adjustcolor(col_hcst, alpha.f = 0.10),
            border = NA)
    ## Forecast
    if (n_fcst > n_obs){
      polygon(x = c((n_obs):n_fcst, rev((n_obs):n_fcst)),
              y = c(fcst_quantiles[4,(n_obs):n_fcst],
                    rev(fcst_quantiles[5,(n_obs):n_fcst])),
              col = adjustcolor(col_fcst, alpha.f = 0.10),
              border = NA)
      polygon(x = c((n_obs):n_fcst, rev((n_obs):n_fcst)),
              y = c(fcst_quantiles[2,(n_obs):n_fcst],
                    rev(fcst_quantiles[4,(n_obs):n_fcst])),
              col = adjustcolor(col_fcst, alpha.f = 0.30),
              border = NA)
      polygon(x = c((n_obs):n_fcst, rev((n_obs):n_fcst)),
              y = c(fcst_quantiles[1,(n_obs):n_fcst],
                    rev(fcst_quantiles[2,(n_obs):n_fcst])),
              col = adjustcolor(col_fcst, alpha.f = 0.10), 
              border = NA)
    }
    ## NOTEV: What is 'fsct_stype'?
  } else {stop('fcst_stype must be either boxplot or shading')}
  
  ## Observations
  lines(x = 1:n_obs, y = obs, col = col_obs, lty = 'solid', lwd = 5)
  
  ## Ensemble mean
  ## Hindcast
  lines(x = 1:n_obs,
        y = multiApply::Apply(data = fcst,
                              target_dims = member_dim, 
                              fun = mean,
                              na.rm = FALSE,
                              ncores = 1)$output1[1:n_obs],
        col = col_hcst, type = 'l', lwd = 5)
  ## Forecast
  if (n_fcst > n_obs) {
    lines(x = (n_obs):n_fcst,
          y = multiApply::Apply(data = fcst,
                                target_dims = member_dim,
                                fun = mean,
                                na.rm = FALSE,
                                ncores = 1)$output1[(n_obs):n_fcst],
          col = col_fcst, type = 'l', lwd = 5)
  }
  
  ## Legend with the skill scores
  if (!is.null(legend)) {
    par(xpd = TRUE)
    legend(par('usr')[2], par('usr')[4],#x = 1, y = ylims[2], 
           text.col = c(col_obs, col_hcst), cex = 1.2, 
           legend = legend_text[1:2], lty = 1, lwd = 3, 
           col = c(col_obs, col_hcst, bg="transparent"), bty = 'n')
  }
  if (!is.null(caption)) {
    if (is.null(caption_line)) {
      caption_line <- 4.5
     }
     mtext(caption, side = 1, line = caption_line, cex = 1.2, adj = 0)
  }


  if (identical(style, 'boxplot')){
    if (!is.null(logo)) {
      rasterImage(logo, ybottom = par('usr')[3] - 2, ytop = par('usr')[3] - 1.1, #ylims[2] + 2, 
                  xleft = par('usr')[2] - 1.5 , 
                  xright = par('usr')[2] + dim(logo)[2]/dim(logo)[1] * width/height, xpd = T)
    }
    data_samp <- 1:100
    data_samp <- (data_samp - mean(data_samp))/ sqrt(var(data_samp))
    par(xpd = T)
    box_params <- boxplot(data_samp,  add = T, at = par('usr')[2] + n_fcst * 0.1, ylab ='', yaxt = 'n')
    text(x = par('usr')[2] + n_fcst * 0.1 + .5, y = box_params$stats[1,], "Minimum", adj = c(0,0))
    text(x = par('usr')[2] + n_fcst * 0.1 + .5, y = box_params$stats[2,], "Q1", adj = c(0,0))
    text(x = par('usr')[2] + n_fcst * 0.1 + .5, y = box_params$stats[3,], "Median", adj = c(0,0))
    text(x = par('usr')[2] + n_fcst * 0.1 + .5, y = box_params$stats[4,], "Q3", adj = c(0,0))
    text(x = par('usr')[2] + n_fcst * 0.1 + .5, y = box_params$stats[5,], "Maximum", adj = c(0,0))
  }
  
  ## Closing the output file
  if (!is.null(fileout)){dev.off()}
  
}

