Calibration <- function(data) {
  is_s2dv_object <- function(x) {
    if (all(c('mod', 'obs', 'lon', 'lat') %in% names(x))) { #&& length(x) == 11) {
      TRUE
    } else {
      FALSE
    }
  }
  wrong_input <- FALSE
  if (!is.list(data)) {
    wrong_input <- TRUE
  }
  
  if (!is_s2dv_object(data)) {
    wrong_input <- TRUE
  }
  if (wrong_input) {
    stop("Parameter 'data' must be a list of s2dverification objects as returned by ",
         "the s2dverification::Load function.")
  }
  Calibrated <- Apply(data = list(var_obs = data$obs, var_exp = data$mod),
                      target_dims = list(c('member', 'sdate'), c('member', 'sdate')),
                      fun = 'cal')
  Calibrated <- aperm(Calibrated$output1, c(3, 1, 2, 4, 5, 6))
  names(dim(Calibrated)) <- names(dim(data$mod))
  return(list(calibrated = Calibrated))
}

cal <- function(var_obs, var_exp) {
  ntime <- length(var_obs)
  if (dim(var_exp)[1] != dim(var_exp)[2]) {
    nmembers <- dim(var_exp)[-which(dim(var_exp) == length(var_obs))]
  } else{
    nmembers <- dim(var_exp)[1]
  }
  if (!all(dim(var_exp) == c(nmembers, ntime))) {
    var_exp <- t(var_exp)
  }
  if (!all(dim(var_exp) == c(nmembers, ntime))) {
    var_exp <- t(var_exp)
  }
  climObs <- NA * var_obs
  climPred <- NA * var_obs
  for (t in 1:length(var_obs))
  {
    climObs[t] <- mean(var_obs)
    climPred[t] <- mean(var_exp[,-t])
  }
  var_obs <- var_obs - climObs
  for (i in 1:nmembers) {
    var_exp[i,] <- var_exp[i,] - climPred
  }
  calibrated <- NA * var_exp
  for (t in 1:ntime) {
    # defining forecast,hindcast and observation in cross-validation
    fcst <- var_exp[, t]
    hcst <- var_exp[,-t]
    obs <- var_obs[-t]
    #coefficients
    em_fcst <- mean(fcst)
    em_hcst <- apply(hcst, c(2), mean)
    corr <- cor(em_hcst, obs)
    sd_obs <- sd(obs)
    sd_em_hcst <- sd(em_hcst)
    
    fcst_diff <- fcst - em_fcst
    hcst_diff <- NA * hcst
    for (n in 1:nmembers) {
      hcst_diff[n,] <- hcst[n,] - em_hcst
    }
    sd_hcst_diff <- sd(hcst_diff)
    
    a <- corr * (sd_obs / sd_em_hcst)
    b <- (sd_obs / sd_hcst_diff) * sqrt(1 - (corr ^ 2))
    
    calibrated[, t] <- (a * em_fcst) + (b * fcst_diff) + climObs[t]
  }
  return(calibrated)
}