#' @rdname CST_PDFBest
#' @title Computing the Best Index PDFs combining Index PDFs from two SFSs
#' of a CSTools object.
#' @author Eroteida Sanchez-Garcia - AEMET, \email{esanchezg@aemet.es}
#' @description This function implements the computation to obtain the index PDFs
#' (e.g. NAO index) to improve the index estimate from the forecast of SFSs
#' and accepts a CSTools object (an object of the class 's2dv_cube' as input.
#' @references Regionally improved seasonal forecast of precipitation through
#' Best estimation of winter NAO, Sanchez-Garcia, E. et al.,
#' Adv. Sci. Res., 16, 165174, 2019, https://doi.org/10.5194/asr-16-165-2019
#' @param pdf_exp An object of the class 's2dv_cube'
#' containing the parameters of the Index PDFs from two SFSs for a period
#' to combine and obtain the Best estimation.
#' The index_hind object is expected to have an element named \code{$data}
#' with dimensions (time, dataset = 2, member = 1, statistic = 4, season).
#' @param bc_dataset1 Logical (default = TRUE).
#' If TRUE the Index PDFs for the first SFS or dataset has been computed
#' with bias corrected.
#' @param bc_dataset2 Logical (default = TRUE).
#' If TRUE the Index PDFs for the second SFS or dataset has been computed
#' with bias corrected.
#' @return CST_PDFBest() returns a CSTools object (i.e., of the
#' class 's2dv_cube').
#' This object has at least two elements: i) an element named \code{$data}
#' with dimensions (time, statistic = 2, season) and ii) an element
#' named \code{$statistic} with the names of 'statistic' dimension
#' of the first element ("mean", "sigma").
#' The firt statistic is the parameter 'mean' of the PDF
#' The second statistic is the parameter 'standard deviation' of the PDF
#' @export
#' @examples
#' pdf_exp <- c(1: (10 * 2 * 1 * 4 * 1))
#' dim(pdf_exp) <-  c(time = 10, dataset = 2, member = 1, statistic = 4, 
#' season = 1)
#' pdf_exp <- list(data = pdf_exp, Datasets = c("ECMWF-S5","UKMO-S13"),
#'                 season = c('DJF'), Dates = list(start = 1997:2006))
#' class(pdf_exp) <- 's2dv_cube'
#' res_CST <- CST_PDFBest(pdf_exp)
#' str(res_CST)
#' # List of 5
#' # $ data     : num [1:10, 1:2, 1] 45.2 46.3 47.3 48.3 49.3 ...
#' # $ Datasets : chr [1:2] "ECMWF-S5" "UKMO-S13"
#' # $ season   : chr "DJF"
#' # $ Dates    :List of 1
#' # ..$ start: int [1:10] 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006
#' # $ statistic: chr [1:2] "mean" "sigma"
#' # - attr(*, "class")= chr "s2dv_cube"
#' dim(res_CST$data)
#' # time statistic    season
#' #   10         2         1
CST_PDFBest <- function(pdf_exp, bc_dataset1 = TRUE, bc_dataset2 = TRUE) {
  if (!inherits(pdf_exp, 's2dv_cube')) {
    stop("Parameter 'pdf_exp' must be of the class 's2dv_cube', ",
         "as output by CSTools::CST_Load.")
  }
  if (!is.logical(bc_dataset1)) {
    stop("The parameter 'bc_dataset1' must be a logical value.")
  }
  if (!is.logical(bc_dataset2)) {
    stop("The parameter 'bc_dataset2' must be a logical value.")
  }
  if (is.null(names(dim(pdf_exp$data)))) {
    stop("Element 'data' from parameters 'pdf_exp' should have dimmension ",
         "names.")
  }
  if(length(dim(pdf_exp$data)) != 5){
    stop("Wrong dimensions of the component 'data' of parameter 'pdf_exp'")
  } else if (!all(names(dim(pdf_exp$data)) == c('time', 'dataset', 'member', 
                                                'statistic', 'season'))) {
    stop("Wrong dimensions of the component 'data' of parameter 'pdf_exp'")
  }
  if (dim(pdf_exp$data)['dataset'] != 2) {
    stop("The length of the dimension 'dataset' in the component 'data' ",
         "of the parameter 'pdf_exp' must be equal to 2.")
  }
  if (dim(pdf_exp$data)['member'] != 1) {
    stop("The length of the dimension 'member' in the component 'data' ",
         "of the parameter 'pdf_exp' must be equal to 1.")
  }
  if (dim(pdf_exp$data)['statistic'] != 4) {
    stop("The length of the dimension 'statistic' in the component 'data' ",
         "of the parameter 'pdf_exp' must be equal to 4.")
  }
  
  
  Dim <- dim(pdf_exp$data)
  dim(pdf_exp$data) <- Dim[-which(names(Dim) == 'member')]

  PDFstatistics <- PDFBest(pdf_exp$data, bc_dataset1 = bc_dataset1,
                           bc_dataset2 = bc_dataset2)
  pdf_exp$data <- PDFstatistics
  pdf_exp$statistic <- c("mean","sigma")
  return(pdf_exp)
}

#' @rdname PDFBest
#' @title Computing the Best Index PDFs combining two SFSs Index PDFs.
#' @author Eroteida Sanchez-Garcia - AEMET, \email{esanchezg@aemet.es}
#' @description This function implements the computation to obtain the index PDFs
#' (e.g. NAO index) obtained to combining the Index PDFs for two SFSs,
#' the Best Index estimation.
#' @references Regionally improved seasonal forecast of precipitation through Best
#' estimation of winter NAO, Sanchez-Garcia, E. et al.,
#' Adv. Sci. Res., 16, 165174, 2019, https://doi.org/10.5194/asr-16-165-2019
#' @param pdf_exp Statistics array for the SFSs Index PDFs for a period of years
#' with dimensions (time, dataset = 2, statistic = 4, season).
#' @param bc_dataset1 Logical (default = TRUE).
#' If TRUE the Index PDFs for the first SFS or dataset has been computed
#' with bias corrected.
#' @param bc_dataset2 Logical (default = TRUE).
#' If TRUE the Index PDFs for the second SFS or dataset has been computed
#' with bias corrected.
#' @return PDFBest() returns an array
#' with dimensions (time, statistic = 2, season).
#' The firt statistic is the parameter 'mean' of the PDF for the best estimation
#' combining the two SFSs PDFs.
#' The second statistic is the parameter 'standard deviation' of the PDF for
#' the best estimation combining the two SFSs PDFs.
#' @import multiApply
#' @export
#' @examples
#' # Example for the PDFBest function
#' pdf_exp <- c(1: (10 * 2 * 4 * 1))
#' dim(pdf_exp) <-  c(time = 10, dataset = 2, statistic = 4, season = 1)
#' res <- PDFBest(pdf_exp, bc_dataset1 = TRUE, bc_dataset2 = FALSE)
#' dim(res)
#' # time   statistic    season
#' #   10           2         1
#' str(res)
#' # num [1:10, 1:2, 1] 17.2 18.3 19.5 20.6 21.7 ...
#'
PDFBest <- function(pdf_exp, bc_dataset1 = TRUE, bc_dataset2 = TRUE) {
  pdf_best <- Apply(list(pdf_exp),
                    target_dims = list(c('dataset','statistic'),
                                       c('dataset','statistic')),
                           fun = .PDFBest, bc_dataset1, bc_dataset2)
  pos <- match(c('time','statistic','season'), names(dim(pdf_best$output1)))
  res <- aperm(pdf_best$output1,pos)
  names(dim(res)) <- c('time','statistic','season')
  return(res)
}

#' Atomic PDFBest
#' @param pdf_exp Statistics array for two SFS PDFs with dimensions
#' (dataset = 2, statistic = 4).
#' @param bc_dataset1 Logical (default = TRUE).
#' If TRUE the Index PDF for the first SFS or dataset has been computed
#' with bias corrected.
#' @param bc_dataset2 Logical (default = TRUE).
#' If TRUE the Index PDF for the second SFS or dataset has been computed
#' with bias corrected.
#' @return .PDFBest returns an array with dimensions (statistic = 2).
#' The firt statistic is the parameter 'mean' of the PDF for the best estimation
#' combining the two SFSs PDF.
#' The second statistic is the parameter 'standard deviation' of the PDF for
#' the best estimation combining the two SFSs PDF.
#' @examples
#' # Example for the Atomic PDFBest function
#' pdf_exp <- c(1.1,0.6,1.6,0.9,1,0.5,1.5,0.8)
#' dim(pdf_exp) <-  c(dataset = 2, statistic = 4)
#' res <- .PDFBest(pdf_exp, bc_dataset1 = TRUE, bc_dataset2 = FALSE)
#' str(res)
#' # num [1:2(1d)] 0.706 0.772
#' dim(res)
#' # statistic
#' #    2
#' @noRd
.PDFBest <- function(pdf_exp, bc_dataset1 = TRUE, bc_dataset2 = TRUE) {
  #names(dim(pdf_exp)) <- c('dataset','statistic')
  if(bc_dataset1){
    # apply bias correction to model 1
    sigma_1 <- pdf_exp[1,4]
    mean_1 <- pdf_exp[1,3]
  } else{
    # not bias correction to model 1
    sigma_1 <- pdf_exp[1,2]
    mean_1 <- pdf_exp[1,1]
  }
  if(bc_dataset2){
    # apply bias correction to model 2
    sigma_2 <- pdf_exp[2,4]
    mean_2 <- pdf_exp[2,3]
  } else {
    # not bias correction to model 2
    sigma_2 <- pdf_exp[2,2]
    mean_2 <- pdf_exp[2,1]
  }
  a_1 <- (sigma_2^2)/((sigma_1^2)+(sigma_2^2))
  a_2 <- (sigma_1^2)/((sigma_1^2)+(sigma_2^2))
  pdf_mean <- a_1*mean_1 + a_2*mean_2
  pdf_sigma <- sqrt((sigma_1^2)*(sigma_2^2)/((sigma_1^2)+(sigma_2^2)))
  data <- c(pdf_mean, pdf_sigma)
  dim(data) <-  c(statistic = 2)
  return(data)
}
