#' Add the BZIP2 filter to the chunk processing pipeline.
#'
#' @param h5plist Object of class [H5IdComponent-class] representing a dataset
#' creation property list.
#' @param level Compression level to be used by the selected algorithm.
#'
#' @export
H5Pset_bzip2 <- function(h5plist, level = 2L) {
  if (!is.loaded("_H5Pset_bzip2", PACKAGE = "rhdf5")) {
    stop(
      "BZIP2 filter not found.\nPlease install rhdf5filters, and then reinstall rhdf5."
    )
  }

  h5checktypeAndPLC(h5plist, "H5P_DATASET_CREATE")
  res <- .Call(
    "_H5Pset_bzip2",
    h5plist@ID,
    as.integer(level),
    PACKAGE = "rhdf5"
  )
  invisible(res)
}

#' Add the BLOSC filter to the chunk processing pipeline.
#'
#' @param h5plist Object of class [H5IdComponent-class] representing a dataset
#' creation property list.
#' @param h5tid HDF5 data type id
#' @param method Integer defining which of the compression algorithms provided
#' by BLOSC should be used. (See the details section for the mapping between
#' integers and algorithms).
#' @param level Compression level to be used by the selected algorithm.
#' @param shuffle Logical defining whether the bit-shuffle algorithm should
#' be used prior to compression.  This makes use of the shuffle implementation
#' provide by BLOSC, rather than the HDF5 version.
#'
#' @export
H5Pset_blosc <- function(
  h5plist,
  h5tid,
  method = 1L,
  level = 6L,
  shuffle = TRUE
) {
  if (!is.loaded("_H5Pset_blosc", PACKAGE = "rhdf5")) {
    stop(
      "BLOSC filter not found.\nPlease install rhdf5filters, and then reinstall rhdf5."
    )
  }

  method <- as.integer(method)
  if (method < 1 || method > 6) {
    method <- 1L
    warning("Invalid method selected. Using BLOSC_LZ")
  }

  ## START: simplified reimplementation of C code from H5Zblosc.c
  ## Filter from https://github.com/nexusformat/HDF5-External-Filter-Plugins/
  ## contains a call to blosc_set_local() which determines chunk size & blosc
  ## parameters. This requires calls to HDF5 functions and doesn't play well
  ## with our static linking.  We move this setup code into R code below.
  chunkdims <- H5Pget_chunk(h5plist)
  typesize <- H5Tget_size(h5tid)
  if (typesize > 255) {
    typesize <- 1
  }
  bufsize <- typesize * prod(chunkdims)
  ## END

  h5checktypeAndPLC(h5plist, "H5P_DATASET_CREATE")
  res <- .Call(
    "_H5Pset_blosc",
    h5plist@ID,
    as.integer(method - 1L),
    as.integer(level),
    as.integer(as.logical(shuffle)),
    as.integer(typesize),
    as.integer(bufsize),
    PACKAGE = "rhdf5"
  )
  invisible(res)
}

#' Add the LZF filter to the chunk processing pipeline.
#'
#' @param h5plist Object of class [H5IdComponent-class] representing a dataset
#' creation property list.
#' @param h5tid HDF5 data type id
#'
#' @export
H5Pset_lzf <- function(h5plist, h5tid) {
  if (!is.loaded("_H5Pset_lzf", PACKAGE = "rhdf5")) {
    stop(
      "LZF filter not found.\nPlease install rhdf5filters, and then reinstall rhdf5."
    )
  }

  ## START: simplified reimplementation of C code from lzf_filter.c
  ## Filter from h5py
  ## contains a call to lzf_set_local() which determines chunk size
  ## This requires calls to HDF5 functions and doesn't play well
  ## with our static linking.  We move this setup code into R code below.
  chunkdims <- H5Pget_chunk(h5plist)
  typesize <- H5Tget_size(h5tid)
  bufsize <- typesize * prod(chunkdims)
  ## END

  h5checktypeAndPLC(h5plist, "H5P_DATASET_CREATE")
  res <- .Call(
    "_H5Pset_lzf",
    h5plist@ID,
    as.integer(bufsize),
    PACKAGE = "rhdf5"
  )
  invisible(res)
}
