########################################################################################################################################
########################################################################################################################################
# BuildBubleyDyerEvaluationGenerator
########################################################################################################################################
########################################################################################################################################

#' @title
#' Generator for the approximated computation of the mean value of functions over linear
#' extensions.
#'
#' @description
#' `BuildBubleyDyerEvaluationGenerator`
#' creates an object of S4 class `BuildBubleyDyerEvaluationGenerator`, for the estimation of
#' the mean values of the input functions, over linear extensions sampled according to the Bubley-Dyer procedure.
#' Actually, this function does not perform the computation of mean values, but just generates the object that will compute them
#' by using function `BubleyDyerEvaluation`.
#'
#' @param poset An object of S4 class `POSet` representing the poset from which linear extensions are generated.
#' Object `poset` must be created by using any function contained in the package aimed at building object of S4 class `POSet`
#' (e.g. [POSet()], [LinearPOSet()], [ProductPOSet()], ...) .
#'
#' @param seed Positive integer to initialize random linear extension generation. Set `seed=NULL` for random initialization.
#'
#' @param f1 The function whose mean value is to be computed.
#' `f1` must be an R-function having as a single parameter a linear extension of `poset` and returning a numerical matrix.
#'
#' @param ... Further functions whose mean values are to be computed.
#'
#' @return
#' An object of S4-class `BuildBubleyDyerEvaluationGenerator`.
#'
#' @examples
#' el1 <- c("a", "b", "c", "d")
#' el2 <- c("x", "y")
#' el3 <- c("h", "k")
#' dom <- matrix(c(
#'   "a", "b",
#'   "c", "b",
#'   "b", "d"
#' ), ncol = 2, byrow = TRUE)
#'
#' pos1 <- POSet(elements = el1, dom = dom)
#'
#' pos2 <- LinearPOSet(elements = el2)
#'
#' pos3 <- LinearPOSet(elements = el3)
#'
#' pos <- ProductPOSet(pos1, pos2, pos3)
#'
#' # median_distr computes the frequency distribution of median profile
#'
#' elements <- POSetElements(pos)
#'
#' median_distr <- function(le) {
#'   n <- length(elements)
#'   if (n %% 2 != 0) {
#'     res <- (elements == le[(n + 1) / 2])
#'   } else {
#'     res <- (elements == le[n / 2])
#'   }
#'   res <- as.matrix(res)
#'   rownames(res) <- elements
#'   colnames(res) <- "median_distr"
#'   return (as.matrix(res))
#' }
#'
#' BDgen <- BuildBubleyDyerEvaluationGenerator(poset = pos, seed = NULL, median_distr)
#'
#' @name BuildBubleyDyerEvaluationGenerator
#' @export BuildBubleyDyerEvaluationGenerator
BuildBubleyDyerEvaluationGenerator <- function(poset, seed, f1, ...)  {
  if (!methods::is(poset, "POSet")) {
    stop("poset must be of class POSet")
  }
  if (!is.null(seed) && (seed < 0 || seed != round(seed))) {
    stop("seed must be a positive integer")
  }

  if (!methods::is(f1, "function")) {
    out_str <- paste("Arguments must be a R-function.", collapse=", ")
    stop(out_str)
  }

  functions_list = list(f1)
  for(f in list(...)) {
    if (!methods::is(f, "function")) {
      out_str <- paste("Arguments must be a R-function.", collapse=", ")
      stop(out_str)
    }
    functions_list[[length(functions_list)+1]] = f

  }

  tryCatch({
    ptr <- .Call("_BuildBubleyDyerEvaluationGenerator", poset@ptr, seed, functions_list)
    result <- methods::new("BubleyDyerEvaluationGenerator", ptr=ptr)
    return (result)
    return (0)
  }, error = function(err) {
    err_split <- strsplit(err[[1]], split = ":")
    stop(err_split[[1]][length(err_split[[1]])])
  }) # END tryCatch
}
