#'CST_Analogs using Trained predictors
#'
#'@param exp a list of 's2dv_cube' objects containing the experimets for different variables
#'@param obs a list of 's2dv_cube' objects conatining the observed (era5/erainterim) variable. Notice that \code{exp} variables and \code{obs} variables must be the same.
#'@param var_name a character string indicating the variable to downscale: 'prec' for precipitation, 'temp' for tmax and tmin.
#'@param hrobs a 's2dv_cube' object containing the HR dataset (http:)
#'@details
#'@examples
#'@export
CST_AnalogsPredictors <- function(exp_psl, exp, obs_psl, obs, var_name = 'prec', hr_obs) {
  #checks inputs
  expdata <- lapply(exp, function(x) {x$data})
  obsdata <- lapply(obs, function(x) {x$data})

  result <- AnalogsPredictors(exp_psl = exp_psl$data, exp = expdata, obs_psl = obs_psl$data,
                              obs = obsdata, var_name = var_name, hr_obs)
  output <- exp[[1]]
  output$data <- result$data
  output$lat <- hr_obs$lat
  output$lon <- hr_obs$lon
  return(output)
}
#'Analogs using trained predictors for Iberian Peninsula
#'
#'@param exp a list containing N-dimensional arrays with named dimensions for each variable
#'@param exp_lat a vector of latitudes (increasing) corresponding to the experiments
#'@param
#'
#'@useDynLib CSTools
#'@export

# No voy a hacer que el usuario pase exp_psl_lat/lon porque lo puedo calcular con los de la
# rejilla sinoptica
AnalogsPredictors <- function(exp_psl, exp, exp_lat, exp_lon, obs_psl, obs, obs_lat, obs_lon, 
			      var_name = 'prec', hr_obs, hr_obs_lat, hr_obs_lon, ncores = NULL) {
  # check inputs
  # check exp
  # check exp_lat
# completar los checks (depende de lo exigente que seamos con la funcion)
  if (!is.numeric(exp_lat)) {
    stop("Parameter 'exp_lat' must be a numeric vector.")
  }
  if (length(exp_lat) < 2) {
    stop("Parameter 'exp_lat' must be a vector with multiple values.")
  }
# En esta parte calculamos todo lo que nuestra funcion necesite como argumento
  exp_res <- c(exp_lat, NA) - c(NA, exp_lat)
  exp_res <- exp_res[!is.na(exp_res)]
  if (!all(exp_res == exp_res[1])) {
    stop("Parameter 'exp_lat' must be in regular grid.")
  } else {
    exp_res <- exp_res[1]
  }
  nlat <- (exp_lat[length(exp_lat)] - exp_lat[1]) / exp_res
  nlon <- (exp_lon[length(exp_lon)] - exp_lon[1]) / exp_res
  ic <- nlat * nlon
  extra_nw_dom <- 7.5 
  extra_se_dom <- 3 
  dif_grids <- extra_nw_dom+extra_se_dom
  nlatt <- nlat + (dif_grids / exp_res)
  nlont <- nlon + (dif_grids / exp_res)
  id <- nlatt * nlont
  slat <- max(exp_lat)
  slon <- exp_lon[1] # if -180 : 180
  slon <- min(c(exp_lon[which(exp_lon > 180)] - 360, 
                exp_lon[which(exp_lon <= 180)])) # if lon 0 :360

  if (any(names(dim(obs_psl)) == 'time')) {
    time_dim <- which(names(dim(obs_psl)) == 'time')
  } else if (any(names(dim(obs_psl)) == 'sdate')) {
    if (any(names(dim(obs_psl)) == 'ftime')) {
        obs_psl <- MergeDims(obs_psl, c('ftime', 'sdate'), rename_dim = 'time')
        time_dim <- which(names(dim(obs_psl)) == 'time')
  }
  if (any(names(dim(obs_psl)) == 'gridpoint')) {
    gp_dim <- which(names(dim(obs_psl)) == 'gridpoint')
  } else if (any(names(dim(obs_psl)) == 'lat')) {
    if (any(names(dim(obs_psl)) == 'lon')) {
        obs_psl <- MergeDims(obs_psl, c('lat', 'lon'), rename_dim = 'gridpoint')
        gp_dim <- which(names(dim(obs_psl)) == 'gridpoint')
  }  
  
  nm <- exp$time 
  nd <- obs$time 
  
# completar los argumentos de la funcion training (basado en los programas de fortran)
# y ver la manera de obtenerlos de la informacion que nos pasa la funcion AnalogPredictors.
# Una vez que tenga todo claro, ir probandolo en R a ver si funciona (habria que hacerlo con el
# dyn.load como habia hecho la prueba).
  trained <- .Fortran("training", obs = obs,
                                  hr_obs = hr_obs,
                                  nlat = nlat,
                                  nlon = nlon, 
				  ic = ic,
                                  nlatt = nlatt,
                                  nlont = nlont,
                                  id = id,
                                  slat = slat,
                                  slon = slon, 
				  nger = nger,
                                  nm = nm,
				  nd = nd,
 				  obs_res,
                                  obs_ngrid,
                                  hr_res,
                                  
			PACKAGE = "CSTools") 
# Hacer lo mismo que con training pero con los argumentos del downscalin
#  for (i 1:nmember) {
#  result <- abind(result, .Fortran("downscaling", trained, exp[,i,,,,], hr_obs,
#                        PACKAGE = "CSTools"), along = 2)
#  }

#  result <- Apply(list(exp), target_dims = 'member', fun = function(x) {.Fortran("downscaling", x,
 #                 hr_obs, PACKAGE = "CSTools"), ncores = ncores)
  if (any(names(dim(exp)) %in% 'member')) {
    dim(exp) <- c(member = 1, dim(exp))
  }
  result <- Apply(list(exp), margins = 'member', fun = .analogspred, obs_HR)
  
  # res <- Apply(list(sys4_psl$data), target_dims = 'ftime', fun = mean)

  #  res <- Apply(list(sys4_psl$data), target_dims = 'ftime', fun = function(x) {(x - mean(x))/sqrt(var(x))})

 #    res <- Apply(list(sys4_psl$data), target_dims = c('member','ftime'), fun = function(x) {(x - mean(as.vector(x)))/sqrt(var(as.vector(x)))})

#     res <- Apply(list(era5_psl$data, era5_tas$data), target_dims = c('ftime'), fun = function(x,y) {(x - mean(as.vector(y)))/sqrt(var(as.vector(y)))})
}
.analogspred <- function(exp1memb, obs_HR) {
#  print(dim(exp1memb))
  res <- .Fortran("downscaling", exp1memb,..., PACKAGE = "CSTools")
  # Needs formating output?
  return(res)
}
