#' @title Posterior Predictive Distribution from mcmcComposite object
#' @author Marc Girondot \email{marc.girondot@@gmail.com}
#' @return A data.frame with quantiles
#' @param x A mcmcComposite obtained as a result of \code{MHalgoGen()} function
#' @param chain The number of the chain in which to get parameters or "all"
#' @param FUN The function to apply the parameters. It must be text.
#' @param probs The probability to get quantiles
#' @param xlim The values to apply in fun if required
#' @param nameparxlim The name of the parameter for xlim
#' @param namepar The name of parameters from mcmc object to be used in fun
#' @description Extract quantile distributions from mcmcComposite object. If FUN is used, it keeps the 
#' correlations between parameters.
#' @family mcmcComposite functions
#' @examples
#' \dontrun{
#' library(HelpersMG)
#' require(coda)
#' x <- rnorm(30, 10, 2)
#' dnormx <- function(data, x) {
#'  data <- unlist(data)
#'  return(-sum(dnorm(data, mean=x['mean'], sd=x['sd'], log=TRUE)))
#' }
#' 
#' parameters_mcmc <- setPriors1(Name = "mean", 
#'                               Density = "dnorm", Prior1 = 10, Prior2 = 2, 
#'                               SDProp = 1, Min = -3, Max = 100, Init = 10)
#' parameters_mcmc <- parameters_mcmc + setPriors1(Name = "sd", 
#'                               Density = "dlnorm", Prior1 = 0.5, Prior2 = 0.5, 
#'                               SDProp = 1, Min = 0, Max = 10, Init = 2)
#'                               
#' mcmc_run <- MHalgoGen(n.iter=10000, parameters=parameters_mcmc, data=x, 
#'                      likelihood=dnormx, n.chains=1, n.adapt=100, thin=1, trace=1)
#' 
#' # Return the 2.5% and 97.5% quantiles of the mean parameter
#' k <- PPD(x=mcmc_run, namepar="mean")
#' k <- PPD(x=mcmc_run, namepar=NULL)
#' k <- PPD(x=mcmc_run, namepar=c("mean", "sd"))
#' 
#' # Here I return the distribution of coefficient of variation as a posterior predictive distribution
#' k <- PPD(x=mcmc_run            , 
#'                  FUN="sd/mean" )
#' 
#' # I can generate an output based on a x variable 
#' k <- PPD(x=mcmc_run                   , 
#'                   xlim=c(1, 2)        ,
#'                   nameparxlim="mult"  ,
#'                   FUN="mult*mean"     )
#' }
#' @export


PPD <- function(x                         , 
                chain="all"               , 
                FUN=NULL                  , 
                probs=c(0.025, 0.975)     , 
                xlim=NULL                 , 
                nameparxlim=NULL          , 
                namepar=NULL              ) {
  
  # chain=1; fun=function(x) {x}; probs=c(0.025, 0.975); xlim=NULL; nameparxlim=NULL; namepar=NULL
  if (chain[1] == "all") chain <- seq_along(x$resultMCMC)
  
  # if (total) p <- x$resultMCMC.total[[chain[1]]] else p <- x$resultMCMC[[chain[1]]]
  
  p <- NULL
  
  if (length(chain) >= 1) {
    for (i in chain) {
      p <- rbind(p, x$resultMCMC[[i]])
    }
  }
  
  if (is.null(p)) stop("No data are available.")
  
  if (is.null(namepar)) namepar <- colnames(p)
  
	# p <- x$resultMCMC[[chain]]
  if (is.null(FUN)) {
    df <- matrix(NA, ncol=length(namepar), nrow = nrow(p))
    colnames(df) <- namepar
  } else {
    if (is.null(xlim)) {
      xlimpos <- 1
    } else {
      xlimpos <- length(xlim)
    }
    df <- matrix(NA, ncol=xlimpos, nrow = nrow(p))
    colnames(df) <- as.character(xlim)
  }
	
  if (!is.null(FUN)) {
    FUN <- eval(parse(text = paste0("function(...) {dots <- list(...); return(with(dots, ", FUN, "))}")))
  }
  
	for (l in 1:nrow(p)) {
	  if (is.null(FUN)) {
	    funx <- function(...) return(as.numeric(list(...)))
	    par <- p[l, ]
	    if (!is.null(namepar)) par <- par[namepar]
	    parx <- as.list(par)
	    h <- do.call(funx, args=parx)
	    df[l, ] <- h
	  } else {
	    par <- p[l, ]
	    if (!is.null(namepar)) par <- par[namepar]
	    
	    for (i in 1:xlimpos) {
	      if (!is.null(xlim)) {
	      m <- xlim[i]
	      names(m) <- nameparxlim
	      parx <- as.list(c(m, par))
	      } else {
	        parx <- as.list(par)
	      }
	      h <- do.call(FUN, args=parx)
	      df[l, i] <- h
	    }
	  }
	}

	q <- apply(df, MARGIN = 2, FUN = function(x) quantile(x, probs))
	colnames(q) <- colnames(df)
	return(q)

}
