###################################################################################
#' Ensemble: Stacking
#'
#' Generates an ensemble of surrogate models with stacking
#'
#' @param x design matrix (sample locations), rows for each sample, columns for each variable.
#' @param y vector of observations at \code{x}
#' @param control (list), with the options for the model building procedure:\cr
#' \code{startTheta} optional start value for theta optimization, default is \code{NULL}\cr
#' \code{algTheta}  algorithm used to find theta, default is \code{optimLBFGSB}.\cr
#' \code{budgetAlgTheta} budget for the above mentioned algorithm, default is \code{200}. The value will be multiplied with the length of the model parameter vector to be optimized.\cr
#' \code{nugget} Value for nugget. Default is -1, which means the nugget will be optimized during MLE. Else it can be fixed in a range between 0 and 1.
#' \code{regr} Regression function to be used: \code{\link{regpoly0}} (default), \code{\link{regpoly1}}, \code{\link{regpoly2}}. Can be a custom user function.\cr
#' \code{corr} Correlation function to be used: \code{\link{corrnoisykriging}} (default), \code{\link{corrkriging}}, \code{\link{corrnoisygauss}}, \code{\link{corrgauss}}, \code{\link{correxp}}, \code{\link{correxpg}}, \code{\link{corrlin}}, \code{\link{corrcubic}},\code{\link{corrspherical}},\code{\link{corrspline}}. Can also be user supplied (if in the right form).
#' \code{target} target values of the prediction, a vector of strings. Each string specifies a value to be predicted, e.g., "y" for mean, "s" for standard deviation, "ei" for expected improvement. See also \code{\link{predict.kriging}}.
#' This can also be changed after the model has been build, by manipulating the respective \code{object$target} value.
#'
#' @return returns an object of class \code{ensembleStack} with the following elements:
#' 			\item{\code{model}}{A list, containing model parameters}
#' 			\item{\code{like}}{Estimated likelihood value}
#' 			\item{\code{theta}}{activity parameters theta (vector)}
#' 			\item{\code{p}}{exponents p (vector)}
#' 			\item{\code{lambda}}{nugget value (numeric)}
#' 			\item{\code{nevals}}{ Number of iterations during MLE}
#'
#' @seealso \code{\link{predict.ensembleStack}}
#'
#' @examples
#' ## Create a test function: branin
#' braninFunction <- function (x) {	
#' 	(x[2]  - 5.1/(4 * pi^2) * (x[1] ^2) + 5/pi * x[1]  - 6)^2 + 
#'	10 * (1 - 1/(8 * pi)) * cos(x[1] ) + 10
#' }
#' ## Create design points
#' x <- cbind(runif(20)*15-5,runif(20)*15)
#' ## Compute observations at design points
#' y <- as.matrix(apply(x,1,braninFunction))
#' ## Create model with default settings
#' fit <- buildEnsembleStack(x,y)
#' ## Predict new point
#' predict(fit,cbind(1,2))
#' ## True value at location
#' braninFunction(c(1,2))
#' 
#' @export
###################################################################################
buildEnsembleStack <- function(x, y, control=list()){ #nugget -1 means that the nugget will be optimized in lme
	con <- list(modelL1 = buildLM  #L1 model: Linear Model
          ,modelL1Control = list() #default: empty list, use default parameters for L1 model
				  ,modelL0 = list(buildLM
				                  ,buildRandomForest
				                  ,buildCTree  
				                  ,buildKriging
				                  ) #L0 models: Kriging and Random Forest
          ,modelL0Control = list(list()
                                 ,list()
                                 ,list()
                                 ,list()
                                  ) #default: empty lists, use default parameters for all L0 models
          ,k = 10 #number of folds (k-fold CV)
				)
	con[names(control)] <- control
	control<-con
		
	
	## number of data samples
	n <- nrow(x)
	## number of folds
	k <- control$k
  ## number of ensemble models on level 0
  p <- length(control$modelL0)
    ## generate k-fold data split
  folds <- sample(cut(seq(1,n),breaks=k,labels=FALSE))
  ## for each model
  fit0 <- list()
  ythat <- matrix(NA,n,p)
  for(j in 1:p){
    fit0[[j]] <- list()
    ## do k-fold cross-validation
    for(i in 1:k){
      xt <- x[folds!=i,,drop=FALSE]
      yt <- y[folds!=i]
      fit0[[j]][[i]] <- control$modelL0[[j]](xt
                                             ,as.matrix(yt)
                                             ,control$modelL0Control[[j]])
      ythat[folds==i,j] <- predict(fit0[[j]][[i]]
                                   ,x[folds==i,,drop=FALSE])$y
      }
  }
  ## fit level 1 model
  fit1 <- control$modelL1(ythat, y, control$modelL1Control)
  fit <- list(fit0=fit0, fit1=fit1, ythat=ythat,y=y,x=x,k=k,p=p) 
	class(fit)<- "ensembleStack"
	fit
}

###################################################################################
#' Predict Stacked Ensemble
#' 
#' Predict with ensemble model produced by \code{\link{buildEnsembleStack}}.
#'
#' @param object Kriging model (settings and parameters) of class \code{kriging}.
#' @param newdata design matrix to be predicted
#' @param ... not used
#'
#' @return list with predicted value \code{y}
#notimplementedyet
#, uncertainty \code{s} (optional) and expected improvement \code{ei} (optional). 
# Whether \code{s} and \code{ei} are returned is specified by the vector of strings \code{object$target}, which then contains \code{"s"} and \code{"ei"}.
#'
#' @seealso \code{\link{buildKriging}}
#' @export
###################################################################################
predict.ensembleStack <- function(object,newdata,...){  
  ## number of folds
  k <- object$k
  ## number of level 0 models
  p <- object$p  
  #for each level 0 model
  ythat <- NULL
  for(j in 1:p){ 
    # TODO this may be different than as described in Bart16j: 
    # averaging on ythat, not on pred(l1,ythat)
    ## for each of k models (k-fold cross-validation)
    ## predict, then average.
    ytemp <- NULL
    for(i in 1:k){
       ytemp <- cbind(ytemp,predict(object$fit0[[j]][[i]],newdata)$y)
    }
    ythat <- cbind(ythat,rowMeans(ytemp))
  }
  predict(object$fit1,ythat)
}