#'Anomalies relative to a climatology along selected dimension with or without cross-validation
#'
#'@description This function computes the anomalies relative to a climatology computed along the 
#'selected dimension (usually starting dates or forecast time) allowing the application or not of
#'crossvalidated climatologies. The computation is carried out independently for experimental and 
#'observational data products.
#'
#'@param var_exp A multidimensional array related to experimental simulations with the specific 
#'dimensions required by Clim(): i.e. \code{dim(var_exp)} goes from c(nmod/nexp, nmemb/nparam, nsdates, nltime) 
#'up to c(nmod/nexp, nmemb/nparam, nsdates, nltime, nlevel, nlat, nlon).
#'
#'@param var_obs A multidimensional array related to observations with the specific dimensions required 
#'by Clim(): i.e. \code{dim(var_exp)} goes from c(nmod/nexp, nmemb/nparam, nsdates, nltime) up to 
#' c(nmod/nexp, nmemb/nparam, nsdates, nltime, nlevel, nlat, nlon)
#'
#'@param cross A logical value indicating whether cross-validation should be applied or not. Default = FALSE.
#'
#'@param memb A logical value indicating whether Clim() computes one climatology for each experimental data 
#'product member(TRUE) or it computes one sole climatology for all members (FALSE). Default = TRUE.
#'
#'@param dim_ano An integer indicating the dimension along which the climatology will be computed. It 
#'usually corresponds to 3 (sdates) or 4 (ftime). Default = 3.
#'
#'
#'@return A list of length 2:
#'\itemize{
#'\item\code{$var_exp}{ Array of anomalies for \code{var_exp} with same dimensions input.}
#'\item\code{$var_obs}{ Array of anomalies for \code{var_obs} with same dimensions input.}}
#'
#'
#'@examples
#'
#'# Example 1:
#'
#'dim_exp=c(mod = 1, member = 3, sdates = 2, ftime = 100)
#'dim_obs=c(mod = 1, member = 1, sdates = 2, ftime = 100)
#'
#'var_exp = array(rnorm(prod(dim_exp)), dim=dim_exp)
#'var_obs = array(rnorm(prod(dim_obs)), dim=dim_obs)
#'
#'Computation of anomalies without cross-validation
#'anoM <- AnoMultiOptions(var_exp = var_exp, var_obs = var_obs, 
#'                        cross = FALSE, memb = TRUE)
#'str(anoM)
#'
#'
#'# Example 2:
#'
#'dim_exp=c(mod = 1, member = 3, sdates = 2, ftime = 100, nlon = 100, nlat = 50)
#'dim_obs=c(mod = 1, member = 1, sdates = 2, ftime = 100, nlon = 100, nlat = 50)
#'
#'var_exp = array(rnorm(prod(dim_exp)), dim=dim_exp)
#'var_obs = array(rnorm(prod(dim_obs)), dim=dim_obs)
#'
#'Computation of anomalies with cross-validation using kharin and NDV methods
#'anoM <- AnoMultiOptions(var_exp = var_exp, var_obs = var_obs, 
#'                        cross = TRUE, memb = TRUE)
#'str(anoM)
#'anoM <- AnoMultiOptions2(var_exp = var_exp)
#'
#'@seealso 
#'\code{\link{Ano_CrossValid}} 
#'\code{\link{Clim}}
#'
#'
#'@export

AnoMultiOptions <- function(var_exp = NULL, var_obs = NULL, cross = FALSE, memb = TRUE, dim_ano = 3) {
  
  case_exp = case_obs = 0
  if (is.null(var_exp) & is.null(var_obs)) {
    stop("Parameter 'var_exp' and 'var_obs' cannot be NULL.")
  }
  if (is.null(var_exp)) {
    var_exp <- var_obs
    case_obs = 1
    warning("Parameter 'var_exp' is not provided and will be recycled.")
  } 
  if (is.null(var_obs)) {
    var_obs <- var_exp
    case_exp = 1
    warning("Parameter 'var_obs' is not provided and will be recycled.")
  }
  
  dim_exp <- dim(var_exp)
  dim_obs <- dim(var_obs)
  dimnames_data <- names(dim_exp)
  
  
  if (length(dim_exp) < 4 | length(dim_obs) < 4) {
    stop("Invalid input dimensions: At least 4 dimensions needed for var_exp or var_obs, 
         c(nexp/nobs, nmemb, nsdates, nltime).")
  }
  if (length(dim_exp) != length(dim_obs)) {
    stop('Invalid input dimensions: var_exp and var_obs should have same number of dimensions.')
  }
  for (jn in 3:max(length(dim_exp), length(dim_obs))) {
    if (dim_exp[jn] != dim_obs[jn]) {
      stop("Invalid input dimensions: var_exp and var_obs dimensions should have same length
           for nsdates and nltime (and for nlevel,nlon and nlat if present).")
    }
  }
  
  if (dim_ano == dim_ano & (dim_exp[dim_ano] == 1 | dim_obs[dim_ano] == 1)) {
    stop("Invalid input dimensions: selected dim_ano dimension length should be greater than 1")
  }
  if (!is.logical(cross) | !is.logical(memb) ) {
    stop("Invalid flags used: Flags 'cross' and 'memb' should be all logical.")
  }
  if (length(cross) > 1 | length(memb) > 1 ) {
    stop("Invalid flags used: Flags 'cross' and 'memb' should all have length 1.")
  }
  if  ( !(dim_ano == 3 | dim_ano == 4)) {
    warning("A not-temporal dimension selected, check 'dim_ano' parameter.")
  }
  if (dim_exp[dim_ano] < 2) {
    stop("Invalid length for selected anomaly time dimension 'dim(var_exp[dim_ano])': length should be greater than 1.")
  }
  
  # Selecting time dimension through dimensions permutation
  if  (dim_ano != 3) {
    dimperm <- 1 : length(dim_exp)
    dimperm[3] <- dim_ano
    dimperm[dim_ano] <- 3
    
    var_exp <- aperm(var_exp, perm = dimperm)
    var_obs <- aperm(var_obs, perm = dimperm)
    
    #Updating permuted dimensions
    dim_exp <- dim(var_exp)
    dim_obs <- dim(var_obs)
  }
  
  
  # Computating anomalies
  #----------------------
  
  # With cross-validation
  if (cross) {
    ano <- Ano_CrossValid(var_exp, var_obs, memb = memb)
    
    if (case_obs == 1) {
      ano <- list(ano_obs = ano$ano_obs)
    } 
    else if (case_exp == 1) {
      ano <- list(ano_exp = ano$ano_exp)
    }
    
    #  Without cross-validation 
  } else {
    tmp <- Clim(var_exp , var_obs , memb )
    
    if (memb) { 
      clim_exp <- tmp$clim_exp
      clim_obs <- tmp$clim_obs
    } else {
      clim_exp <- InsertDim(tmp$clim_exp, 2, dim_exp[2]) 
      clim_obs <- InsertDim(tmp$clim_obs, 2, dim_obs[2]) 
    }
    
    
    clim_exp <- InsertDim(clim_exp, 3, dim_exp[3]) 
    clim_obs <- InsertDim(clim_obs, 3, dim_obs[3]) 
    
    ano_exp <- var_exp - clim_exp
    ano_obs <- var_obs - clim_obs 
    
    if (case_obs == 1) {
      ano <- list(ano_obs = ano_obs)
    } 
    else if (case_exp == 1) {
      ano <- list(ano_exp = ano_exp)
    }
    else {
      ano <- list(ano_exp = ano_exp, ano_obs = ano_obs)
    }
  }
  
  # Permuting back dimensions to original order
  if  (dim_ano != 3) {
    
    if (case_obs == 0) {
      ano$ano_exp <- aperm(ano$ano_exp, perm = dimperm)
    } 
    if (case_exp == 0) {
      ano$ano_obs <- aperm(ano$ano_obs, perm = dimperm)
    }
    
    
    #Updating back permuted dimensions
    dim_exp <- dim(var_exp)
    dim_obs <- dim(var_obs)
  }
  
  #Adding dimensions names
  if (case_obs == 0) {
    attr(ano$ano_exp, 'dimensions') <- dimnames_data
  }
  if (case_exp == 0) {
    attr(ano$ano_obs, 'dimensions') <- dimnames_data
  }
  #  Outputs
  # ~~~~~~~~~
  invisible(ano)
}


