#'Computes Effective Sample Size With Classical Method
#'
#'Computes the effective number of independent values along the posdim 
#'dimension of a matrix.\cr
#'This effective number of independent observations can be used in 
#'statistical/inference tests.\cr
#'Based on eno function from Caio Coelho from rclim.txt.
#'
#'@param obs A numeric n-dimensional array with or without named dimensions.
#'@param posdim A character or an integer indicating the dimension along 
#'  which to compute the effective sample size.
#'@param na.action Function to be called to handle missing values, can be 
#'  na.pass or na.fail. Default: na.pass
#'@param ncores The number of cores to use for parallel computation. Default: NULL
#'@return An array with the same dimensions as obs except the posdim dimension.
#'
#'@keywords datagen
#'@author History:\cr
#'0.1  -  2011-05  (V. Guemas, \email{virginie.guemas@ic3.cat})  -  Original code\cr
#'1.0  -  2013-09  (N. Manubens, \email{nicolau.manubens@ic3.cat})  -  Formatting to R CRAN
#'3.0  -  2019-08  (A. Ho, \email{an.ho@bsc.es})  -  Adopt multiApply  
#'
#'@examples
#'# See examples on Load() to understand the first lines in this example
#'  \dontrun{
#'data_path <- system.file('sample_data', package = 's2dverification')
#'exp <- list(
#'         name = 'experiment',
#'         path = file.path(data_path, 'model/$EXP_NAME$/monthly_mean',
#'                          '$VAR_NAME$_3hourly/$VAR_NAME$_$START_DATE$.nc')
#'       )
#'obs <- list(
#'         name = 'observation',
#'         path = file.path(data_path, 'observation/$OBS_NAME$/monthly_mean',
#'                          '$VAR_NAME$/$VAR_NAME$_$YEAR$$MONTH$.nc')
#'       )
#'# Now we are ready to use Load().
#'startDates <- c('19851101', '19901101', '19951101', '20001101', '20051101')
#'sampleData <- Load('tos', list(exp), list(obs), startDates,
#'                   leadtimemin = 1, leadtimemax = 4, output = 'lonlat',
#'                   latmin = 27, latmax = 48, lonmin = -12, lonmax = 40)
#'  }
#'  \dontshow{
#'startDates <- c('19851101', '19901101', '19951101', '20001101', '20051101')
#'sampleData <- s2dverification:::.LoadSampleData('tos', c('experiment'), 
#'                                                c('observation'), startDates,
#'                                                output = 'lonlat', 
#'                                                latmin = 27, latmax = 48, 
#'                                                lonmin = -12, lonmax = 40) 
#'  }
#'sampleData$mod <- Season(sampleData$mod, 4, 11, 1, 12)
#'eno <- Eno(sampleData$mod[1, 1, , 1, , ], 1)
#'PlotEquiMap(eno, sampleData$lon, sampleData$lat)
#'
#'@importFrom stats acf na.pass na.fail
#'@export
Eno <- function(obs, posdim, na.action = na.pass, ncores = NULL) {

  #Check params:

  if (is.null(obs)) {
    stop("Parameter 'obs' cannot be NULL.")
  }
  if (!is.numeric(obs)) {
    stop("Parameter 'obs' must be a numeric array.")
  }

  if (is.null(posdim)) {
    stop("Parameter 'posdim' cannot be NULL.")
  }

  if (posdim %% 1 != 0 && !is.character(posdim)) {
#    if (is.null(dim(obs))) {   #a vector
#      posdim <- 1
#    } else if (length(dim(obs)) == 1) {
#      posdim <- 1
#    } else {
      stop("Parameter 'posdim' must be an integer or character.")
    }

  if (is.integer(posdim) && posdim > length(dim(obs))) {
    stop("Parameter 'posdim' excesses the dimension length of parameter 'obs'.")
  }

  if (is.character(posdim) && !any(posdim %in% names(dim(obs)))) {
    stop("Parameter 'posdim' does not match any dimension name of parameter 'obs'.")
  }


#  if (!is.null(dim(obs))) {
    effnumobs <- Apply(data = list(obs), 
                       target_dims = posdim,
                       fun = .Eno,
                       na.action = na.action,
                       ncores = ncores)$output1
                 #parallel = parallel)
    #effnumobs <- adrop(eno, 1)   #dont drop length(dim) = 1. Keep the dim same as input.
#  } else {
#    effnumobs <- .Eno(obs)
#  }
  return(effnumobs)
}

.Eno <- function(x, na.action) {

  if (length(sort(x)) > 1) {
    n <- length(sort(x))
    if (n == 0) {
      n <- 1
    }
    a <- acf(x, lag.max = n - 1, plot = FALSE, 
             na.action = na.action)$acf[2:n, 1, 1]
    s <- 0 
    for (k in 1:(n - 1)) {
      s <- s + (((n - k) / n) * a[k])
    }
    eno <- min(n / (1 + (2 * s)), n)
  } else {
    eno <- NA
  }
  eno
}

