BrierScore <- function(obs, pred, thresholds = seq(0, 1, 0.1)) {
  if (max(pred) > 1 | min(pred) < 0) {
    stop("Predictions outside [0,1] range. Are you certain this is a probability forecast? \n")
  } else if (max(obs) != 1 & min(obs) != 0) {
    .message("Binary events must be either 0 or 1. Are you certain this is a binary event? ")
  } else {
    nbins <- length(thresholds) - 1  # Number of bins
    n <- length(pred)
    bins <- as.list(paste("bin", 1:nbins,sep = ""))
    for (i in 1:nbins) {
      if (i == nbins) {
        bins[[i]] <- list(which(pred >= thresholds[i] & pred <= thresholds[i + 1]))
      } else {
        bins[[i]] <- list(which(pred >= thresholds[i] & pred < thresholds[i + 1]))
      }
    }
    
    fkbar <- okbar <- nk <- array(0, dim = nbins)
    for (i in 1:nbins) {
      nk[i] <- length(bins[[i]][[1]])
      fkbar[i] <- sum(pred[bins[[i]][[1]]]) / nk[i]
      okbar[i] <- sum(obs[bins[[i]][[1]]]) / nk[i]
    }
    
    obar <- sum(obs) / length(obs)
    relsum <- ressum <- term1 <- term2 <- 0
    for (i in 1:nbins) {
      if (nk[i] > 0) {
        relsum <- relsum + nk[i] * (fkbar[i] - okbar[i])^2
        ressum <- ressum + nk[i] * (okbar[i] - obar)^2
        for (j in 1:nk[i]) {
          term1 <- term1 + (pred[bins[[i]][[1]][j]] - fkbar[i])^2
          term2 <- term2 + (pred[bins[[i]][[1]][j]] - fkbar[i]) * (obs[bins[[i]][[1]][j]] - okbar[i])
        }
      }
    }
    rel <- relsum / n
    res <- ressum / n
    unc <- obar * (1 - obar)
    bs <- sum((pred - obs)^2) / n
    bs_check_res <- rel - res + unc
    bss_res <- (res - rel) / unc
    gres <- res - term1 * (1 / n) + term2 * (2 / n)   # Generalized resolution
    bs_check_gres <- rel - gres + unc                 # BS using GRES
    bss_gres <- (gres - rel) / unc                    # BSS using GRES
    
    #
    # Estimating the bias-corrected components of the BS 
    #
    term3 <- array(0, nbins)
    for (i in 1:nbins) {
      term3[i] <- (nk[i] / (nk[i] - 1)) * okbar[i] * (1 - okbar[i])
    }
    term_a <- sum(term3,  na.rm = T) / n
    term_b <- (obar * (1 - obar)) / (n - 1)
    rel_bias_corrected <- rel - term_a
    gres_bias_corrected <- gres - term_a + term_b
    if (rel_bias_corrected < 0 || gres_bias_corrected < 0) {
      rel_bias_corrected2 <- max(rel_bias_corrected, rel_bias_corrected - gres_bias_corrected, 0)
      gres_bias_corrected2 <- max(gres_bias_corrected, gres_bias_corrected - rel_bias_corrected, 0)
      rel_bias_corrected <- rel_bias_corrected2
      gres_bias_corrected <- gres_bias_corrected2
    }
    unc_bias_corrected <- unc + term_b
    bss_bias_corrected <- (gres_bias_corrected - rel_bias_corrected) / unc_bias_corrected
    
    #if (round(bs, 8) == round(bs_check_gres, 8) & round(bs_check_gres, 8) == round((rel_bias_corrected - gres_bias_corrected + unc_bias_corrected), 8)) {
    #  cat("No error found  \ n")
    #  cat("BS = REL - GRES + UNC = REL_lessbias - GRES_lessbias + UNC_lessbias  \ n")
    #}
    
    invisible(list(rel = rel, res = res, unc = unc, bs = bs, bs_check_res = bs_check_res, bss_res = bss_res, gres = gres, bs_check_gres = bs_check_gres, bss_gres = bss_gres, rel_bias_corrected = rel_bias_corrected, gres_bias_corrected = gres_bias_corrected, unc_bias_corrected = unc_bias_corrected, bss_bias_corrected = bss_bias_corrected, nk = nk, fkbar = fkbar, okbar = okbar, bins = bins, pred = pred, obs = obs))
  }
}


.BrierScore <- function(ens, obs, thresholds = seq(0, 1, 0.1)) {
  if (max(ens) > 1 | min(ens) < 0) {
    stop("Predictions outside [0,1] range. Are you certain this is a probability forecast? \n")
  } else if (max(obs) != 1 & min(obs) != 0) {
    .message("Binary events must be either 0 or 1. Are you certain this is a binary event? ")
  } else {
    nbins <- length(thresholds) - 1  # Number of bins
    n <- dim(ens)[1]                # Number of observations
    n.ens <- seq(1,dim(ens)[2],1)            # Number of ensemble members
    bins <- array(as.list(paste("bin", 1:nbins,sep = "")), c(nbins,dim(ens)[2]))
    for (i in 1:nbins) {
      if (i == nbins) {
        bins[i,] <- apply(ens, MARGIN = 2, FUN = function(x) list(which(x >= thresholds[i] & x <= thresholds[i + 1])))
      } else {
        bins[i,] <- apply(ens, MARGIN = 2, FUN = function(x) list(which(x >= thresholds[i] & x < thresholds[i + 1])))
      }
    }
    
    
    fkbar <- okbar <- nk <- array(0, dim = c(nbins,dim(ens)[2]))
   for (k in 1:dim(ens)[2]) {
     for (i in 1:nbins) {
        nk[i,k] <- length(bins[[i,k]][[1]])
        fkbar[i,k] <- sum(ens[,k][bins[[i,k]][[1]]])/nk[i,k]
        okbar[i,k] <- sum(obs[bins[[i,k]][[1]]]) / nk[i,k]
    }
      }
  
    fkbar[fkbar == Inf] <- 0 
    okbar[is.nan(okbar)] <- 0
    obar <- sum(obs) / length(obs)
    relsum <- ressum <- relsum1  <- ressum1  <- term1 <- term1a <- term2 <- term2a <- rep(0,dim(ens)[2])
    
    for (k in 1:dim(ens)[2]) {
      for (i in 1:nbins) {
      
        if (nk[i,k] > 0) {
          relsum[k]  <-  relsum[k] + nk[i,k] * (fkbar[i,k] - okbar[i,k])^2
          ressum[k]     <-  ressum[k] + nk[i,k] * (okbar[i,k] - obar)^2
         
        for (j in 1:nk[i,k]) {
          term1[k] <- term1[k] + (ens[,k][bins[[i,k]][[1]][j]] - fkbar[i,k])^2
          term2[k] <- term2[k] + (ens[,k][bins[[i,k]][[1]][j]] - fkbar[i,k]) * (obs[bins[[i,k]][[1]][j]] - okbar[i,k])
         }
        }
      }
    }
    
    rel <- relsum / n
    res <- ressum / n
    unc <- obar * (1 - obar)
    bs <- apply(ens, MARGIN = 2, FUN = function(x) sum((x - obs)^2) / n)
    
    bs_check_res <- rel - res + unc
    bss_res <- (res - rel) / unc
    gres <- res - term1 * (1 / n) + term2 * (2 / n)   # Generalized resolution
    bs_check_gres <- rel - gres + unc                 # BS using GRES
    bss_gres <- (gres - rel) / unc                    # BSS using GRES
    
    #
    # Estimating the bias-corrected components of the BS 
    #
    term3 <- array(0, dim = c(nbins,dim(ens)[2]))
    for (i in 1:nbins) {
      for (k in 1:dim(ens)[2]) {
      term3[i,k] <- (nk[i,k] / (nk[i,k] - 1)) * okbar[i,k] * (1 - okbar[i,k])
      }
    }
    term_a <- apply(term3, MARGIN = 2, FUN = function(x)  sum(x,  na.rm = T) / n)
    term_b <- (obar * (1 - obar)) / (n - 1)
    rel_bias_corrected <- rel - term_a
    gres_bias_corrected <- gres - term_a + term_b
    rel_bias_corrected2 <-  gres_bias_corrected2 <- rep(0, dim(ens)[2])
      for(j in 1:dim(ens)[2]) {
    if (rel_bias_corrected[j] < 0 || gres_bias_corrected[j] < 0) {
      rel_bias_corrected2[j] <- max(rel_bias_corrected[j], rel_bias_corrected[j] - gres_bias_corrected[j], 0)
      gres_bias_corrected2[j] <- max(gres_bias_corrected[j], gres_bias_corrected[j] - rel_bias_corrected[j], 0)
      rel_bias_corrected[j] <- rel_bias_corrected2[j]
      gres_bias_corrected[j] <- gres_bias_corrected2[j]
       }
    }
    unc_bias_corrected <- unc + term_b
    bss_bias_corrected <- (gres_bias_corrected - rel_bias_corrected) / unc_bias_corrected
    
    #if (round(bs, 8) == round(bs_check_gres, 8) & round(bs_check_gres, 8) == round((rel_bias_corrected - gres_bias_corrected + unc_bias_corrected), 8)) {
    #  cat("No error found  \ n")
    #  cat("BS = REL - GRES + UNC = REL_lessbias - GRES_lessbias + UNC_lessbias  \ n")
    #}
    
    invisible(list(rel = rel, res = res, unc = unc, bs = bs, bs_check_res = bs_check_res, bss_res = bss_res, gres = gres, bs_check_gres = bs_check_gres, bss_gres = bss_gres, rel_bias_corrected = rel_bias_corrected, gres_bias_corrected = gres_bias_corrected, unc_bias_corrected = unc_bias_corrected, bss_bias_corrected = bss_bias_corrected, nk = nk, fkbar = fkbar, okbar = okbar, bins = bins, ens = ens, obs = obs))
  }
}
