UltimateBrier <- function(exp_ano, obs_ano, posdatasets = 1, posmemb = 2, posdates = 3, quantile = TRUE, thr = c(5/100, 95/100), type = 'BS', decomposition = TRUE) {
  #library(SpecsVerification)
  #library(plyr)
  if (!(type %in% c('BS', 'FairEnsembleBS', 'FairStartDatesBS', 'BSS', 'FairEnsembleBSS', 'FairStartDatesBSS'))) {
    stop("'type' not supported")
  }

  if (dim(obs_ano)[posmemb] != 1) {
    stop("Only observations with one member are supported. dim(obs_ano)[posmemb] should be 1")
  }

  if (any(is.na(exp_ano)) || any(is.na(obs_ano))) {
    stop("There can't be NA values in 'exp_ano' and 'obs_ano'")
  }

  if (type %in% c('FairEnsembleBSS', 'FairEnsembleBS')) {
    input_exp <- exp_ano
    input_obs <- obs_ano
    input_posdatasets <- posdatasets
    input_posmemb <- posmemb
    input_posdates <- posdates
  } else {
    # Calculate probabilities of data with ProbBins and average over members
    exp_probs <- array(Mean1Dim(ProbBins(exp_ano, 1:dim(exp_ano)[posdates], thr, quantile, posdates, posmemb), 3),
                       dim = c(length(thr) + 1, dim(exp_ano)[posdates], 1, dim(exp_ano)[-c(posmemb, posdates)]))
    obs_probs <- array(Mean1Dim(ProbBins(obs_ano, 1:dim(obs_ano)[posdates], thr, quantile, posdates, posmemb), 3),
                       dim = c(length(thr) + 1, dim(obs_ano)[posdates], 1, dim(obs_ano)[-c(posmemb, posdates)]))
    input_exp <- exp_probs
    input_obs <- obs_probs
    input_posdatasets <- 4
    input_posmemb <- 3
    input_posdates <- 2
  }

  if (type == 'FairEnsembleBSS') {
    size_ens_ref <- prod(dim(obs_ano)[c(posmemb, posdates)])
    f <- function(x) {
      ens_ref <- matrix(do.call("[", c(list(x = x), indices_obs)), size_ens_ref, size_ens_ref, byrow = TRUE)
      sapply(c(thr, 1), function(tau) FairBrierSs(t(do.call("[", c(list(x = x), indices_exp))), ens_ref, do.call("[", c(list(x = x), indices_obs)), tau)$bss)
    }
  } else {
    if (type == 'FairEnsembleBS') {
      f <- function(x) sapply(c(thr, 1), function(tau) mean(FairBrier(t(do.call("[", c(list(x = x), indices_exp))), do.call("[", c(list(x = x), indices_obs)), tau), na.rm = TRUE))
    } else {
      if (type == 'BS') {
        f <- function(x) {
          print(dim(x))
          print(indices_exp)
          print(indices_obs)
          as.vector(BrierScoreDecomposition(do.call("[", c(list(x = x), indices_exp)), do.call("[", c(list(x = x), indices_obs))))
        }
      } else if (type == 'FairStartDatesBS') {
        f <- function(x) unlist(BrierScore(do.call("[", c(list(x = x), indices_exp)), do.call("[", c(list(x = x), indices_obs)))[c('rel', 'res', 'unc')], use.names = FALSE)
      } else if (type == 'BSS') {
        f <- function(x) BrierScore(do.call("[", c(list(x = x), indices_exp)), do.call("[", c(list(x = x), indices_obs)))$bss_res
      } else if (type == 'FairStartDatesBSS') {
        f <- function(x) BrierScore(do.call("[", c(list(x = x), indices_exp)), do.call("[", c(list(x = x), indices_obs)))$bss_gres
      }
    }
  }

  if (type %in% c('BS', 'FairStartDatesBS')) {
    result <- array(dim = c(dim(ano_exp)[posdatasets], dim(ano_obs)[posdatasets], 3, length(thr) + 1, dim(ano_exp)[-c(posdatasets, posmemb, posdates)]))
  } else {
    result <- array(dim = c(dim(ano_exp)[posdatasets], dim(ano_obs)[posdatasets], length(thr) + 1, dim(ano_exp)[-c(posdatasets, posmemb, posdates)]))  
  }
  indices_exp <- as.list(rep(TRUE, length(dim(input_exp))))
  indices_exp[[input_posmemb]] <- c(1:dim(input_exp)[input_posmemb])
  indices_exp <- indices_exp[c(input_posdatasets, input_posmemb, input_posdates)]
  indices_obs <- as.list(rep(TRUE, length(dim(input_obs))))
  indices_obs[[input_posmemb]] <- c(1:dim(input_obs)[input_posmemb]) + dim(input_exp)[input_posmemb]
  indices_obs <- indices_obs[c(input_posdatasets, input_posmemb, input_posdates)]
  out_indices <- as.list(rep(TRUE, length(dim(result))))
  for (n_obs in 1:dim(obs_ano)[posdatasets]) {
    for (n_exp in 1:dim(exp_ano)[posdatasets]) {
      data <- abind(take(input_exp, input_posdatasets, n_exp), take(input_obs, input_posdatasets, n_obs), along = input_posmemb)
      out_indices[c(1, 2)] <- c(n_exp, n_obs)
      result <- do.call("[<-", c(list(x = result), out_indices, list(value = apply(data, c(1:length(dim(data)))[-c(input_posdatasets, input_posmemb, input_posdates)], f))))
    }
  }

  if (type %in% c('BSS', 'FairStartDatesBSS', 'FairEnsembleBSS')) {
    result
  } else {
    rel <- take(result, 3, 1)
    dim(rel) <- dim(rel)[-3]
    res <- take(result, 3, 2)
    dim(res) <- dim(res)[-3]
    unc <- take(result, 3, 3)
    dim(unc) <- dim(unc)[-3]
    bs <- rel - res + unc
    if (decomposition && type != 'FairEnsembleBS') {
      list(BS = bs, REL = rel, UNC = unc, RES = res)
    } else {
      bs
    }
  }
}

