#' Compute climatological weights for RainFARM stochastic precipitation downscaling
#'
#' @author Jost von Hardenberg - ISAC-CNR, \email{j.vonhardenberg@isac.cnr.it}
#'
#' @description Compute climatological ("orographic") weights from a fine-scale precipitation climatology file.
#' Reference: Terzago, S., Palazzi, E., & von Hardenberg, J. (2018).
#' Stochastic downscaling of precipitation in complex orography: 
#' A simple method to reproduce a realistic fine-scale climatology.
#' Natural Hazards and Earth System Sciences, 18(11),
#' 2825–2840. http://doi.org/10.5194/nhess-18-2825-2018 .
#' Please notice: The function uses the \code{julia_setup()}
#' function from the JuliaCall library, 
#' which takes a long time only the first time it is called on a machine
#' @param orofile Filename of a fine-scale precipitation climatology.
#' The file is expected to be in NetCDF format and should contain
#' at least one precipitation field. If several fields at different times are provided,
#' a climatology is derived by time averaging.
#' Suitable climatology files could be for example a fine-scale precipitation climatology
#' from a high-resolution regional climate model (see e.g. Terzago et al. 2018), a local
#' high-resolution gridded climatology from observations, or a reconstruction such as those which 
#' can be downloaded from the WORLDCLIM (http://www.worldclim.org) or CHELSA (http://chelsa-climate.org)
#' websites. The latter data will need to be converted to NetCDF format before being used (see for example the GDAL tools (https://www.gdal.org).
#' @param nf Refinement factor for downscaling (the output resolution is increased by this factor).
#' @param lon Vector of longitudes (can be omitted if \code{reffile} is used).
#' @param lat Vector of latitudes (can be omitted if \code{reffile} is used).
#' The number of longitudes and latitudes is expected to be even and the same. If not
#' the function will perform a subsetting to ensure this condition.
#' @param reffile Filename of reference file (e.g. the file to downscale).
#' Not needed if \code{lon} and \code{lat} are passed.
#' @param varname Name of the variable to be read from \code{reffile}.
#' @param weightsfn Optional filename to save the weights also to an external file in netcdf format.
#' @param fsmooth Logical to use smooth conservation (default) or large-scale box-average conservation.
#' @return A matrix containing the weights with dimensions (lon, lat).
#' @import ncdf4
#' @import JuliaCall
#' @examples
#' # Create weights to be used with the CST_RainFARM() or RainFARM() functions
#' # using an external fine-scale climatology file.
#'
#' \donttest{
#' # Specify lon and lat of the input
#' lon_mat <- seq(10,13.5,0.5)
#' lat_mat <- seq(40,43.5,0.5)
#'
#' nf <- 8
#' ww <- RFWeights("./worldclim.nc", nf, lon=lon_mat, lat=lat_mat, weightsfn="", fsmooth = TRUE)
#'
#' # or use a reference file (e.g. the input file itself) to specify the coordinates
#' ww <- RFWeights("./worldclim.nc", nf, reffile="./input.nc")
#' }
#' @export

RFWeights <- function(orofile, nf, lon=NULL, lat=NULL, reffile="",
                      weightsfn="", varname="", fsmooth=TRUE) {

  julia_setup(useRCall = FALSE)
  julia_library("RainFARM")
  if ( (reffile == "") & ( (typeof(lon) == "NULL") | (typeof(lat) == "NULL"))) {
     stop("Neither a reference filename nor lon and lat specified!\n")
  }
  if (reffile == "") {
    # Ensure input  grid is square and with even dimensions
    if ((length(lat) != length(lon)) | (length(lon) %% 2 == 1)) {
      print("Warning: input data are expected to be on a square grid")
      print("         with an even number of pixels per side")
      nmin <- min(length(lon), length(lat))
      nmin <- floor(nmin / 2) * 2
      lon <- lon[1:nmin]
      lat <- lat[1:nmin]
      print("The input data have been cut to the range")
      print(paste0("lon: [", lon[1], ", ", lon[length(lon)], "] ",
                   " lat: [", lat[1], ", ", lat[length(lat)], "]"))
    }
    xvar <- ncdim_def("lon", "degrees_east", lon, longname = "longitude")
    yvar <- ncdim_def("lat", "degrees_north", lat, longname = "latitude")
    tvar <- ncdim_def("time", "days since 01-01-2000", 0., longname = "time",
                      unlim = T)
    my_ncdf <- ncvar_def("grid", "m", list(xvar, yvar, tvar), -999,
                         longname = "grid", prec = "single")
    reffile <- tempfile()
    ncfile <- nc_create(reffile, my_ncdf, force_v4 = FALSE)
    nc_close(ncfile)
  }

  ww <- julia_call("rfweights", orofile, reffile, as.integer(nf),
                   weightsfn = weightsfn, varname = varname, fsmooth = fsmooth)

  attributes(dim(ww))$names <- c("lon","lat")
  unlink(reffile)
  return(ww)
}
