ACC_bootstrap <- function(var_exp, var_obs, sampmet, lon = NULL, lat = NULL,
                          lonlatbox = NULL, nrspa=1000,
                          blocspa=1, confmet = "quantile", center = TRUE) {
# Matrix var_exp & var_obs should have dimensions (nexp/nobs,  nsdates,  
# nltimes,  nlat,  nlon).
# ACC computes the Anomaly Correlation Coefficient for each jexp in 
# 1:nexp and each jobs in 1:nobs which gives nexp x nobs ACC for each 
# startdate and each leadtime.
# A domain can be selected by providing the list of longitudes/latitudes
# (lon/lat) of the grid together with the corner of the domain:
#   lonlatbox = c(lonmin,  lonmax,  latmin,  latmax)
# 
# Args:
#   var_exp: Matrix of experimental data.
#   var_obs: Matrix of observational data,  same dimensions as var_exp except 
#            along the first dimension.
#   sampmet: "bootstrap"/"permutation". If "bootstrap" set, observation
#            and experiment fields are re-sampled together. The original
#            correlation should be included with a 95% probability in the
#            confidence interval. In this case, the p-value can not be use to
#            estimate the significance. Instead of using the p-value, the
#            ACC or MACC will be considered significant if the confident
#            interval does not include 0.
#            If "permutation" set, a simple spatial permutation of the
#            experiment field is done. The confidence interval will be center
#            over 0 and can not be used directly as a "real confidence interval".
#            The p-value is used to estimate the significance of the result and
#            is defined as the percent of the sampled distribition higher than the
#            estimated correlation.
#   lon: Array of longitudes of the var_exp/var_obs grids,  optional.
#   lat: Array of latitudes of the var_exp/var_obs grids,  optional.
#   lonlatbox: Domain to select c(lonmin,  lonmax,  latmin,  latmax),  optional.
#   nrspa: number of sample for the bootstrap  (default: 1000)
#   blocspa: Length of spatial blocks used for resampling the field (default: 1)
#   confmet: "mason"/"quantile". If "mason" set, the lower/upper limit of 95%
#           interval are estimated with the method based
#           on Mason and Mimmack (1991). In the default case ("quantile"),
#           simply the 2.5% and the 97.5% of the bootstrap distribution
#           are given.
#   center: TRUE/FALSE if TRUE (default) compute the center anomaly correlation
#           coefficient (using pearson correlation).
#           if FALSE, the mean map anomalies are not substracted from both
#           oberved and and experiement fields.
#   
#           
# 
# Returns:
#   $ACC: Matrix with c(nexp,  nobs,  nsdates,  nleadtimes,  4) dimensions.
#        The fourth dimension of length 4 corresponds to the lower limit of
#        the 95% confidence interval,  the computed ACC,  the upper limit of 
#        the 95% confidence interval and the p-value.
#        (see the detail of sampmet and confmet arguments for more details)
# 
#   $MACC: Matrix with c(nexp,  nobs,  nsdates,  nleadtimes,  4) dimensions.
#        The fourth dimension of length 4 corresponds to the lower limit of
#        the 95% confidence interval,  the computed Mean Anomaly Correlation
#        Coefficient, the upper limit of  the 95% confidence interval
#        and the p-value. 
#        (see the detail of sampmet and confmet arguments for more details)
# 
# History:
#   1.0  #  2013-08  (C.Prodhomme,  chloe.prodhomme@ic3.cat)  #  Original code
  
  dimsvar <- dim(var_exp)
  if (length(dimsvar) != 5) {
    stop("var_exp & var_obs should have dimensions
        (nexp/nsobs, nsdates, nltimes,  nlat,  nlon) ")
  }
  for (iind in 2:length(dimsvar)) {
    if (dim(var_obs)[iind] != dimsvar[iind]) {
      stop("var_exp & var_obs must have same dimensions except the first one
          (number of experiments or number of observational datasets) ")
    }
  }
  nexp <- dimsvar[1]
  nobs <- dim(var_obs)[1]
  nsdates <- dimsvar[2]
  nltimes <- dimsvar[3]
  nlat <- dimsvar[4]
  nlon <- dimsvar[5]

  #number of blocks needed to reconstruct the field
  nblon1=floor((nlon - 1)/blocspa)+1
  nblat1=floor((nlat - 1)/blocspa)+1
  
  distriACC <- array(NA,  dim=c(nexp, nobs, nsdates, nltimes,
                            nrspa ))
  distriMACC <- array(NA,  dim=c(nexp, nobs, nltimes,
                             nrspa ))
  #output
  ACC <- array(NA,  dim=c(nexp, nobs, nsdates, nltimes, 3))
  MACC <- array(NA,  dim=c(nexp, nobs, nltimes))

  #bootstrap
  for (irand in 1:nrspa) {
      exprand <- array(NA,
                       dim=c(nexp, nsdates, nltimes,
                         nblat1 * blocspa, nblon1 * blocspa))
      obsrand <- array(NA,
                       dim=c(nobs, nsdates, nltimes,
                         nblat1 * blocspa, nblon1 * blocspa))
      #choose of random points for exp
      vlonrand <- sample(1:(nlon - blocspa),  nblon1,  replace=T)
      vlatrand <- sample(1:(nlat - blocspa),  nblat1,  replace=T)

      #reconstruct the new random field
      #   #loops over the elements of the blocks
      for (iblock in 0:(blocspa - 1)) {
          for (jblock in 0:(blocspa - 1)) {
              exprand[, , , seq(1, nlat, blocspa)+jblock ,
                      seq(1, nlon, blocspa)+iblock]=
                        var_exp[, , , vlatrand+jblock,
                                vlonrand+iblock]
            }
        }
      
      exprand <- array(exprand[, , , 1:nlat, 1:nlon],
                       dim=c(nexp, nsdates, nltimes,
                         nlat, nlon))
      
      # random the observation field
      if(sampmet == "bootstrap") {
        for (iblock in 0:(blocspa - 1)) {
          for (jblock in 0:(blocspa - 1)) {
            obsrand[, , , seq(1, nlat, blocspa)+jblock ,
                    seq(1, nlon, blocspa)+iblock]=
                      var_obs[, , , vlatrand+jblock,
                              vlonrand+iblock]
            }
        }
        obsrand <- array(obsrand[, , , 1:nlat, 1:nlon],
                         dim=c(nobs, nsdates, nltimes,
                           nlat, nlon))
      #  keep the original field 
      } else if (sampmet == "permutation") {
        obsrand=var_obs
      } else {
        stop("This sampling method is not available (only permutation or bootstrap)")
      }
      
       #calcultate the ACC
      #print(dim(exprand))
      ACC=ACC(exprand, obsrand, conf = FALSE, center = center)
      distriACC[, , , , irand] <- (ACC$ACC)
      distriMACC[, , ,  irand] <- (ACC$MACC)
    }
  #output definition
  ACC <- array(NA,  dim=c(nexp, nobs, nsdates, nltimes, 4))
  MACC <- array(NA,  dim=c(nexp, nobs, nltimes, 4))

  #calcultate the ACC and MACC of original data
  ACCori <- ACC(var_exp,var_obs, conf = FALSE, center = center)
  ACC[, , , , 2] <- (ACCori$ACC)
  MACC[, , ,  2] <- (ACCori$MACC)


  #calculate the p-value from the bootstrap distribution
  distriACCaux=abind(distriACC, array(ACC[, , , , 2], 
    dim=c(nexp, nobs, nsdates, nltimes, 1)), along=5)
  distriMACCaux=abind(distriMACC, array(MACC[ , , ,  2], 
    dim=c(nexp, nobs, nltimes, 1)), along=4)
  
  ACC[, , , , 4] <- apply(distriACCaux, c(1, 2, 3, 4),
                          function(x)
                          sum(abs(x[1:nrspa]) > abs(x[nrspa+1]),
                              na.rm = TRUE)
                          / nrspa)
  MACC[, , ,  4] <- apply(distriMACCaux, c(1, 2, 3),
                          function(x)
                          sum(abs(x[1:nrspa]) > abs(x[nrspa+1]),
                              na.rm=TRUE)
                          / nrspa)
  
  #calcultate the confidence interval

  if(confmet == "mason")
    {
      #  #Calcultate the inverse CDF for a normal law

      ACCb <- apply(array(1 - ACC[, , , , 4],
                          dim=c(nexp, nobs, nsdates, nltimes)), c(1, 2, 3, 4),
                    function(x) qnorm(x))
      MACCb <- apply(array(1 - MACC[, , ,  4], dim=c(nexp, nobs, nltimes)), c(1, 2, 3),
                     function(x) qnorm(x))

      #  #975% quantile -> to get the 95% confidence intervale
      delta=qnorm(0.975)

      ACClow <- apply(ACCb, c(1, 2, 3, 4),  function(x) pnorm(2 * x - delta))
      ACChig <- apply(ACCb, c(1, 2, 3, 4),  function(x) pnorm(2 * x + delta))
      MACClow <-  apply(MACCb, c(1, 2, 3),  function(x) pnorm(2 * x - delta))
      MACChig <- apply(MACCb, c(1, 2, 3),  function(x) pnorm(2 * x + delta))


      #  #calculate the quantiles associated to this probability
      
      distriACCaux <- abind(distriACC, ACClow, ACChig, along=5)
      distriMACCaux <- abind(distriMACC, MACClow, MACChig, along=4)

      ACC[, , , , 1] <- apply(distriACCaux, c(1, 2, 3, 4),  function(x)
                              quantile(x[1:nrspa],  c(x[nrspa+1]), na.rm=TRUE))
      ACC[, , , , 3] <- apply(distriACCaux, c(1, 2, 3, 4),  function(x)
                              quantile(x[1:nrspa],  c(x[nrspa+2]), na.rm=TRUE))
      MACC[, , ,  1] <- apply(distriMACCaux, c(1, 2, 3),  function(x)
                              quantile(x[1:nrspa],  c(x[nrspa+1]), na.rm=TRUE))
      MACC[, , ,  3] <- apply(distriMACCaux, c(1, 2, 3),  function(x)
                              quantile(x[1:nrspa],  c(x[nrspa+2]), na.rm=TRUE))
      
    }else if(confmet == "quantile")
      {
        ACC[, , , , 3] <- apply(distriACC, c(1, 2, 3, 4),  function(x)
                                quantile(x[1:nrspa],  c(0.975), na.rm=TRUE))
        ACC[, , , , 1] <- apply(distriACC, c(1, 2, 3, 4),  function(x)
                                quantile(x[1:nrspa],  c(0.025), na.rm=TRUE))
        MACC[, , ,  1] <- apply(distriMACC, c(1, 2, 3),  function(x)
                                quantile(x[1:nrspa],  c(0.025), na.rm=TRUE))
        MACC[, , ,  3] <- apply(distriMACC, c(1, 2, 3),  function(x)
                                quantile(x[1:nrspa],  c(0.975), na.rm=TRUE))
      }else{
        print("WARNING:only quantile and mason method are available")
        print("the dimension corresponding to confident
               interval will be filled with NA")
      }

  
  invisible(list(ACC = ACC,  MACC = MACC ))

}

