predict.ARCHmX <- function(object, newdata, ...){
  # strip newdata to only the columns used in object
  
  if (is.null(object$covariates)) {
    stop("Predict Function requires an ARCHmX object with a data component.")
  } else if (p == 0) {
    stop("Prediction requires p > 0.")
  }
  
  # newdata <- matrix(rnorm(100), nrow=10)
  newdata <- matrix(newdata[, object$covariates], nrow=nrow(newdata))
  
  # retrieve the necessary attributes from the model object
  
  h <- object$h
  epsilon_delta <- object$epsilon_delta
  p <- object$p
  alphas <- matrix(object$alphas, ncol=1)
  T_ <- object$T_
  train <- matrix(object$X[, object$covariates], nrow=nrow(object$X))[(p+1):T_,]
  delta <- object$delta
  
  # t-1 correction:
  #   Since epsilon^delta_t depends on the data at time t-1, our "newdata" should
  #   consist of the time T_ data along with everything but the last new observation.
  
  newdata <- rbind(matrix(train[nrow(train),], nrow=1), matrix(newdata[(1:(nrow(newdata)-1)),], ncol=ncol(newdata)))
  
  # build the epsilon matrix
  
  get_epsilon_matrix <- function(epsilon_delta) {
    Epsilon_matrix = matrix(0,T_-p,p)
    for (j in 1:p) {
      Epsilon_matrix[,j] = epsilon_delta[(p-j+1):(T_-j)] 
    }
    return(Epsilon_matrix)
  }
  Epsilon_matrix <- get_epsilon_matrix(epsilon_delta)
  
  # build the weight matrix 
  
  W <- ARCHmX_kernel_between_iso(newdata, train, h)
  
  # Generate the m_hat matrix
  
  m_hats <- W %*% (matrix(epsilon_delta[(p+1):T_], ncol=1) - Epsilon_matrix %*% alphas)
  
  # Expand epsilon_delta and generate the new predicted epsilon_deltas 
  
  epsilon_delta <- c(epsilon_delta, rep(0, nrow(newdata)))
  #for i in ((T_+1):(T_+nrow(newdata))) {
  for (i in 1:nrow(m_hats)) {
    epsilon_delta[T_ + i] <- epsilon_delta[(T_+i-1):(T_+i-p)] %*% alphas + max(m_hats[i],0)
  }
  
  # return the new predicted volatilities
  
  return(epsilon_delta[(T_+1):(T_+nrow(m_hats))]^(2/delta))
} # End predict.ARCHmX
