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)
  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 == 'FairEnsembleBSS') {
    bss <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
    size_ens_ref <- prod(dim(obs_ano)[c(posmemb, posdates)])
    indices_exp <- as.list(rep(TRUE, length(dim(exp_ano))))
    indices_exp[[posmemb]] <- c(1:dim(exp_ano)[posmemb])
    indices_exp <- indices_exp[c(posdatasets, posmemb, posdates)]
    indices_obs <- as.list(rep(TRUE, length(dim(obs_ano))))
    indices_obs[[posmemb]] <- c(1:dim(obs_ano)[posmemb]) + dim(exp_ano)[posmemb]
    indices_obs <- indices_obs[c(posdatasets, posmemb, posdates)]
    out_indices <- as.list(rep(TRUE, length(dim(bss))))
    for (n_obs in 1:dim(obs_ano)[posdatasets]) {
      for (n_exp in 1:dim(exp_ano)[posdatasets]) {
        data <- abind(take(exp_ano, posdatasets, n_exp), take(obs_ano, posdatasets, n_obs), along = posmemb)
        out_indices[c(1, 2)] <- c(n_exp, n_obs)
        bss <- do.call("[<-", c(list(x = bss), out_indices, list(value = apply(data, c(1:length(dim(data)))[-c(posdatasets, posmemb, posdates)], 
          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)
          })))
        )
      }
    }
    bss
  } else {
    if (type == 'FairEnsembleBS') {
      bs <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
      for (n_obs in 1:dim(obs_ano)[posdatasets]) {
        for (n_ltime in 1:dim(exp_ano)[4]) {
          for (n_lat in 1:dim(exp_ano)[5]) {
            for (n_lon in 1:dim(exp_ano)[6]) {
              for (n_exp in 1:dim(exp_ano)[posdatasets]) {
                n_tau <- 1
                for (tau in c(thr, 1)) {
                  bs[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- mean(FairBrier(t(exp_ano[n_exp, , , n_ltime, n_lat, n_lon]), obs_ano[n_obs, 1, , n_ltime, n_lat, n_lon], tau), na.rm = TRUE)
                  n_tau <- n_tau + 1
                }
              }
            }
          }
        }
      }
    } else {
      # Calculate probabilities of data with ProbBins and average over members
      exp_probs <- Mean1Dim(ProbBins(exp_ano, 1:dim(exp_ano)[posdates], thr, quantile, posdates, posmemb), 3)
      obs_probs <- array(ProbBins(obs_ano, 1:dim(obs_ano)[posdates], thr, quantile, posdates, posmemb),
                         dim=c(length(thr)+1,dim(obs_ano)[posdates],dim(obs_ano)[-c(posmemb, posdates)]))
      if (type == 'BS') {
        rel <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        res <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        unc <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        for (n_obs in 1:dim(obs_ano)[posdatasets]) {
          for (n_ltime in 1:dim(exp_ano)[4]) {
            for (n_lat in 1:dim(exp_ano)[5]) {
              for (n_lon in 1:dim(exp_ano)[6]) {
                for (n_exp in 1:dim(exp_ano)[posdatasets]) {
                  n_tau <- 1
                  for (tau in c(thr, 1)) {
                    bsd <- BrierScoreDecomposition(exp_probs[n_tau, , n_exp, n_ltime, n_lat, n_lon], obs_probs[n_tau, , n_obs, n_ltime, n_lat, n_lon])
                    rel[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- bsd['REL'] 
                    res[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- bsd['RES'] 
                    unc[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- bsd['UNC']
                    n_tau <- n_tau + 1
                  }
                }
              }
            }
          }
        }
        bs <- rel - res + unc
      } else if (type == 'FairStartDatesBS') {
        rel <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        res <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        unc <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        for (n_obs in 1:dim(obs_ano)[posdatasets]) {
          for (n_ltime in 1:dim(exp_ano)[4]) {
            for (n_lat in 1:dim(exp_ano)[5]) {
              for (n_lon in 1:dim(exp_ano)[6]) {
                for (n_exp in 1:dim(exp_ano)[posdatasets]) {
                  n_tau <- 1
                  for (tau in c(thr, 1)) {
                    bsd <- BrierScore(obs_probs[n_tau, , 1, n_obs, n_ltime, n_lat, n_lon], exp_probs[n_tau, , n_exp, n_ltime, n_lat, n_lon])
                    rel[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- bsd$rel
                    res[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- bsd$res
                    unc[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- bsd$unc
                    n_tau <- n_tau + 1
                  }
                }
              }
            }
          }
        }
        bs <- rel - res + unc
      } else if (type == 'BSS') {
        bss <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        for (n_obs in 1:dim(obs_ano)[posdatasets]) {
          for (n_ltime in 1:dim(exp_ano)[4]) {
            for (n_lat in 1:dim(exp_ano)[5]) {
              for (n_lon in 1:dim(exp_ano)[6]) {
                for (n_exp in 1:dim(exp_ano)[posdatasets]) {
                  n_tau <- 1
                  for (tau in c(thr, 1)) {
                    bss[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- BrierScore(obs_probs[n_tau, , n_obs, n_ltime, n_lat, n_lon], exp_probs[n_tau, , n_exp, n_ltime, n_lat, n_lon])$bss_res
                    n_tau <- n_tau + 1
                  }
                }
              }
            }
          }
        }
        # Ask Omar if this is the expected function
      } else if (type == 'FairStartDatesBSS') {
        bss <- array(dim = c(dim(exp_ano)[posdatasets], dim(obs_ano)[posdatasets], length(thr) + 1, dim(exp_ano)[-c(posdatasets, posmemb, posdates)]))
        for (n_obs in 1:dim(obs_ano)[posdatasets]) {
          for (n_ltime in 1:dim(exp_ano)[4]) {
            for (n_lat in 1:dim(exp_ano)[5]) {
              for (n_lon in 1:dim(exp_ano)[6]) {
                for (n_exp in 1:dim(exp_ano)[posdatasets]) {
                  n_tau <- 1
                  for (tau in c(thr, 1)) {
                    bss[n_exp, n_obs, n_tau, n_ltime, n_lat, n_lon] <- BrierScore(obs_probs[n_tau, , n_obs, n_ltime, n_lat, n_lon], exp_probs[n_tau, , n_exp, n_ltime, n_lat, n_lon])$bss_gres
                    n_tau <- n_tau + 1
                  }
                }
              }
            }
          }
        }
      }
    }

    if (type %in% c('BSS', 'FairStartDatesBSS')) {
      bss
    } else if (decomposition && type != 'FairEnsembleBS') {
      list(BS = bs, REL = rel, UNC = unc, RES = res)
    } else {
      bs
    }
  }
}

