#'Add a dimension to an array
#'
#'Insert an extra dimension into an array at position 'posdim' with length 
#''lendim'. The array repeats along the new dimension.
#'
#'@param data An array to which the additional dimension to be added.
#'@param posdim An integer indicating the position of the new dimension.
#'@param lendim An integer indicating the length of the new dimension.
#'@param name A character string indicating the name for the new dimension.
#'@param ncores An integer indicating the number of cores to use for parallel 
#'  computation. The default value is NULL.
#'
#'@return An array as parameter 'data' but with the added dimension.
#'
#'@keywords datagen
#'@author History:\cr
#'0.1  -  2011-03  (V. Guemas, \email{virginie.guemas@ic3.cat})  -  Original code\cr
#'1.0  -  2013-09  (N. Manubens, \email{nicolau.manubens@ic3.cat})  -  Formatting to R CRAN\cr
#'1.1  -  2015-03  (N. Manubens, \email{nicolau.manubens@ic3.cat})  -  Improvements
#'3.0  -  2019-12  (A. Ho, \email{an.ho@bsc.es})  -  Modify with multiApply
#'
#'@examples
#'a <- array(rnorm(15), dim = c(3, 1, 5, 1))
#'res <- InsertDim(InsertDim(a[, , , ], 2, 1), 4, 1)
#'
#'@import multiApply
#'@export
InsertDim <- function(data, posdim, lendim, name = 'new', ncores = NULL) {

  # Check inputs 
  ## data
  if (is.null(data)) {
    stop("Parameter 'data' cannot be NULL.")
  }
  if (is.vector(data) & !is.list(data)) {  #is vector
    data <- as.array(data)
  }
  if (!is.array(data)) {
    stop("Parameter 'data' must be an array.")
  }
  ## posdim
  if (!is.numeric(posdim)) {
    stop("Parameter 'posdim' must be a positive integer.")
  } else if (posdim %% 1 != 0 | posdim <= 0 | length(posdim) > 1) {
    stop("Parameter 'posdim' must be a positive integer.")
  }
  if (posdim > (length(dim(data)) + 1)) {
    stop("Parameter 'posdim' cannot excess the number of dimensions of parameter 'data' plus 1")
  }
  ## lendim
  if (!is.numeric(lendim)) {
    stop("Parameter 'lendim' must be a positive integer.")
  } else if (lendim %% 1 != 0 | lendim <= 0 | length(lendim) > 1) {
    stop("Parameter 'lendim' must be a positive integer.")
  }
  ## name
  if (!is.character(name) | length(name) > 1) {
    stop("Parameter 'name' must be a character string.")
  }
  ## ncores
  if (!is.null(ncores)) {
    if (!is.numeric(ncores)) {
      stop("Parameter 'ncores' must be a positive integer.")
    } else if (ncores %% 1 != 0 | ncores <= 0 | length(ncores) > 1) {
      stop("Parameter 'ncores' must be a positive integer.")
    }
  }

  ###############################
  # Calculate InsertDim

  ## create output dimension
  outdim <- lendim
  if (posdim > 1) {
    outdim <- c(dim(data)[1:(posdim - 1)], outdim)
  }
  if (posdim <= length(dim(data))) {
    outdim <- c(outdim, dim(data)[posdim:length(dim(data))])
  }
  ## create output array
  outvar <- array(dim = c(outdim))
  ## give temporary names for Apply(). The name will be replaced by data in the end
  names(dim(outvar)) <- paste0('D', 1:length(outdim))
  names(dim(outvar))[posdim] <- name #'new'

  res <- Apply(data = list(outvar), 
               margins = name, #'new', 
               fun = .InsertDim, 
               dat = data,
               ncores = ncores)$output1

  if (posdim != 1) {
    if (posdim < length(outdim)) {
    res <- .aperm2(res, c(1:(posdim - 1), length(outdim), posdim:(length(outdim) - 1)))
    } else {  #posdim = length(outdim)
        res <- .aperm2(res, c(1:(posdim - 1), length(outdim)))
    }
  } else {
      res <- .aperm2(res, c(length(outdim), 1:(length(outdim) - 1)))
  }

  return(res)
}

.InsertDim <- function(x, dat) {
  x <- data
  return(x)
}
