ProjectField <- function(ano, eof, mode = NULL) { 
  # Checking ano
  if (!is.numeric(ano) || !is.array(ano)) {
    stop("Parameter 'ano' must be a numeric array.")
  }

  # Checking eof
  print_error <- FALSE
  if (!is.list(eof)) {
    print_error <- TRUE
  } else {
    if ('EOFs' %in% names(eof)) {
      EOFs <- "EOFs"
    } else if ('REOFs' %in% names(eof)) {
      EOFs <- "REOFs"
    } else {
      print_error <- TRUE
    }
    if (!'wght' %in% names(eof)) {
      print_error <- TRUE
    }
  }
  if (print_error) {
    str(eof)
    stop("Parameter 'eof' must be a list with the components 'EOFs' or 'REOFs' and 'whgt' as output from EOF() or REOF().")
  }

  if (!is.numeric(eof[[EOFs]]) || !is.array(eof[[EOFs]])) {
    stop("The component 'EOFs' of parameter 'eof' must be a numeric array.")
  }
  if (length(dim(eof[[EOFs]])) != 3) {
    stop("The component 'EOFs' of parameter 'eof' must have dimensions c(neof, nlat, nlon).")
  }
  if (!is.numeric(eof$wght) || !is.array(eof$wght)) {
    stop("The component 'wght' of parameter 'eof' must be a numeric array.")
  }
  if (length(dim(eof$wght)) != 2) {
    stop("The component 'wght' of parameter 'eof' must have dimensions c(n. latitudes, n. longitudes).")
  }

  # Truncate eof to keep only selected modes
  # This is for compatibility with NAO function
  if (!is.null(mode)) {
    eof[[EOFs]] <- Subset(eof[[EOFs]], 1, mode)
  }

  # Get ano and eof dimensions
  # moredims can be different lead times, ensemble members, models, whatever.
  nlon <- dim(ano)[length(dim(ano))]
  nlat <- dim(ano)[length(dim(ano))-1]
  neofs <- dim(eof[[EOFs]])[1]
  moredims <- dim(ano)[1:(length(dim(ano))-2)]
  nanom <- prod(moredims)

  # Security checks.
  if (dim(eof[[EOFs]])[2] != nlat || dim(eof$wght)[1] != nlat) {
    stop("Inconsistent number of latitudes between parameter 'eof' and input field")
  }
  if (dim(eof[[EOFs]])[3] != nlon || dim(eof$wght)[2] != nlon) {
    stop("Inconsistent number of longitudes between parameter 'eof' and input field")
  }
  
  # Multiply anomalies and EOFs by weights
  # Change dimensions of ano to (nanom,nlat,nlon), then multiply by weights
  dim(ano) <- c(nanom,nlat,nlon)
  ano.wght <- ano*InsertDim(eof$wght,1,nanom)
  dim(ano.wght) <- c(nanom,nlat*nlon)
  loadings <- eof[[EOFs]]*InsertDim(eof$wght,1,neofs)
  dim(loadings) <- c(neofs,nlat*nlon)

  # Matrix multiplication anomalies (anom,nlat*nlon) by loadings (nlat*nlon,neofs) 
  # Result is then (anom,neofs)
  projection <- ano.wght %*% t(loadings) 

  # Change back dimensions to feet original input
  dim(projection) <- c(moredims, pc = unname(neofs))
  return(projection)
}
