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 ((length(dim(exp_ano)) != length(dim(obs_ano))) || (any((dim(obs_ano) != dim(exp_ano))[-c(posdatasets, posmemb, posdates)]))) {
    stop("'exp_ano' and 'obs_ano' must have same dimensions except along 'posdatasets' and 'posmemb'.")
  }

  

  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)])
    for (n_obs in 1:dim(obs_ano)[posdatasets]) {
      for (n_exp in 1:dim(exp_ano)[posdatasets]) {
        # Calculate reference climatologies of each lead-time, longitude and latitude before calculating BSS.
        result_indices <- c(rep(TRUE, length(dim(bss))))
        result_indices[c(1, 2)] <- c(n_exp, n_obs)
        bss <- do.call("[<-", c(list(x = bss), as.list(result_indices), list(value =  
          mapply(function(exp, obs) {
                   ens_ref <- matrix(obs, size_ens_ref, size_ens_ref, byrow = TRUE)
                   apply(array(c(thr, 1)), 1, function(tau) FairBrierSs(t(exp), ens_ref, obs, tau))
                 }, 
                 alply(take(exp_ano, posdatasets, n_exp), (1:length(dim(exp_ano)))[-c(posdatasets, posmemb, posdates)]), 
                 alply(take(obs_ano, posdatasets, n_obs), (1:length(dim(obs_ano)))[-c(posdatasets, posmemb, posdates)])
                 ))))
      }
    }
    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, c(posdatasets, posmemb, 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], thr)
                    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], thr)$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], thr)$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
    }
  }
}
