.packageName <- "rhdf5"
####Functions to manipulate HDF5 attributes

"hdf5.attr<-" <- function(set, name, value) {
  attribute(set,name) <- value;         #All HDF5 attributes are replicated in the R space
  invisible(.Call("HDF_attr_set", set, name, value, PACKAGE="rhdf5"))
}
hdf5.attr <- function(set, name)
	.Call("HDF_attr_get", set, name, PACKAGE="rhdf5")
hdf5.attributes <- function(set)
	.Call("HDF_attribute_get", set, PACKAGE="rhdf5")

#coerce functions

 as.single.hdf5.dataset <- function(x, ...) x

 as.double.hdf5.dataset <- function(x, ...) x
#
# HDF5 Dataset Functions
#

hdf5.dataset <- function(group, name, data=NULL, dims=NULL, type=NULL,
                         create=hdf5.default.properties) {
  if(is.null(data) && is.null(dims))
    stop("you must specify either data to store or dimensions for the dataset")
  if(!is.null(data) && !is.null(dims))
    stop("you must specify one of dims or data")
  if(!is.null(data))
    s <- .Call("HDF_dataset_store", group, data, name, PACKAGE="rhdf5")
   else
    s <- .Call("HDF_dataset_create_simple", group, name, dims, create,
               type, PACKAGE="rhdf5")
  invisible(s)
}


#We need the dimensionality construct
dim.hdf5 <- function(x) .Call("HDF_dims", x, PACKAGE="rhdf5")
length.hdf5.dataset <- function(x) .Call("HDF_dataset_length", x,
                                         PACKAGE="rhdf5")
min.hdf5.dataset <- function(..., na.rm=FALSE) {
     args <- list(...)
    x <- args[[1]]

    if (missing(na.rm)) {
        if (na.rm %in% names(args))
            na.rm <- args$na.rm
        else
            if (length(args) >= 2)
                na.rm <- args[[2]]
    }

     .External("HDF_dataset_min", x, na.rm, PACKAGE="rhdf5")
 }

max.hdf5.dataset <- function(..., na.rm=FALSE) {
    args <- list(...)
    x <- args[[1]]

    if (missing(na.rm)) {
        if (na.rm %in% names(args))
            na.rm <- args$na.rm
        else
            if (length(args) >= 2)
                na.rm <- args[[2]]
    }

    .External("HDF_dataset_max", x, na.rm, PACKAGE="rhdf5")
}

range.hdf5.dataset <- function(..., na.rm=FALSE) {
    args <- list(...)
    x <- args[[1]]

    if (missing(na.rm)) {
        if (na.rm %in% names(args))
            na.rm <- args$na.rm
        else
            if (length(args) >= 2)
                na.rm <- args[[2]]
    }

    .External("HDF_dataset_range", x, na.rm, PACKAGE="rhdf5")
}

is.finite.default <- function(x, ...) .Primitive("is.finite")(x)
is.finite <- function(x, ...) UseMethod("is.finite")
is.finite.hdf5.dataset <- function(x, ...) .Call("HDF_dataset_finite",
                                                 x, PACKAGE="rhdf5")

is.matrix.default <- function(x, ...) .Primitive("is.matrix")(x)
is.matrix <- function(x, ...) UseMethod("is.matrix")
is.matrix.hdf5.dataset <- function(x, ...) {
   if(length(dim(x)) == 2 && is.integer(dim(x)) )
	return(TRUE)
   return(FALSE)
}

as.matrix.hdf5.dataset <- function(x)
	invisible(.Call("HDF_dataset_mat_load", x, PACKAGE="rhdf5"))

as.hdf5.dataset <- function(file, value, name) {
    if( !is.vector(value) && is.null(dim(value)))
       stop("only vectors or arrays can be transformed to HDF5")
    if( missing(name) ) name <- deparse(substitute(value))
    invisible(.Call("HDF_dataset_store", file, value, name, PACKAGE="rhdf5"))
}

get.points <- function(d,x,y) .Call("HDF_dataset_select_points",d,x,y,
                                    PACKAGE="rhdf5")

"[.hdf5.dataset" <- function(x, ..., drop = TRUE) {
    mf <- match.call()
    mf$x <- NULL; mf$drop <- NULL
    nsubs <- length(mf) - 1
    subargs <- vector("list", length = nsubs)
    missing.marker <- "R_MissingArg"
    for(i in 1:nsubs) {
        tt <- mf[[i + 1]]
        subargs[[i]] <- if (missing(tt)) missing.marker else
                            eval(as.name(paste("..", i, sep="")))
    }
    .Call("HDF_dataset_select",  x, subargs, drop, PACKAGE="rhdf5")

}

"[<-.hdf5.dataset" <- function(x,...,value) {
	mf <- match.call()
        mf$x <- NULL; mf$value<-NULL
        nsubs <- length(mf)-1
	subargs<-vector("list", length=nsubs)
        for(i in 1:nsubs) {
	   tt <- mf[[i+1]]
	   subargs[[i]] <- if(missing(tt)) "R_MissingArg" else
	                       eval(as.name(paste("..", i, sep="")))
        }
	.Call("HDF_subassign", x, subargs, value, PACKAGE="rhdf5")
	x
}

print.hdf5.dataset <- function(x, ...) {
	.Call("HDF_dataset_print", x, PACKAGE="rhdf5")
	invisible(x)
}

addmemory <- function(set1)
    invisible(.Call("HDF_dataset_addmemory", set1, PACKAGE="rhdf5"))

freememory <- function(set1)
    invisible(.Call("HDF_dataset_freememory", set1, PACKAGE="rhdf5"))

hasmemory <-function(set1)
    .Call("HDF_dataset_hasmemory", set1, PACKAGE="rhdf5")

swapmemory <- function(set1, set2)
    invisible(.Call("HDF_dataset_swapmemory", set1, set2, PACKAGE="rhdf5"))

getmemory <- function(set1)
    .Call("HDF_dataset_getmemory", set1, PACKAGE="rhdf5")
#
# HDF5 Dataspace Functions
#

#obtain a dataspace

space <- function(set, ...) UseMethod("space")
space.hdf5.dataset <- function(set, ...)
    .Call("HDF_dataset_getspace", set, PACKAGE="rhdf5")


print.hdf5.dataspace <- function(x, ...)
  .Call("HDF_space_print", x, PACKAGE="rhdf5")

hdf5.select.hyperslab <- function(space, selop = "SET", start, stride,
                                  count, block)
{
    sd <- dims(space)
    nd <- length(sd)
    if(missing(start) )
        start <- rep(1, nd)
    if(missing(block) )
        block <- rep(1, nd)
    if(missing(stride) )
        stride <- rep(1, nd)
    if(missing(count) )
        count <- rep(1, nd)

    .Call("HDF_select_hyperslab", space, selop, start, stride, count,
          block, PACKAGE="rhdf5")
}
#
# HDF5 File Related Functions
#

hdf5.open <- function(filename, access=hdf5.default.properties)
  .Call("HDF_file_open", filename, access, PACKAGE="rhdf5")

hdf5.create <- function(filename, mode="e",
  create=hdf5.default.properties, access=hdf5.default.properties)
  .Call("HDF_file_create", filename, mode, create, access, PACKAGE="rhdf5")

#These functions take group-like behavior
names.hdf5.file <- function(x, ...)      names.hdf5.group(x)
print.hdf5.file <- function(x, ...)      print.hdf5.group(x)
"$.hdf5.file"   <- function(file, name) "$.hdf5.group"(file, name)
"[[.hdf5.file"  <- function(file, name) "[[.hdf5.group"(file,name)
"[.hdf5.file" <- function(x, i, j, drop)
    stop("[ is not implemented for hdf5.file")


#
# HDF5 Group Related Functions
#

hdf5.group <- function(group, name)
  invisible(.Call("HDF_group_mkgroup", group,name, PACKAGE="rhdf5"))
hdf5.group.rm <- function(group, name) {
  .Call("HDF_group_delete",group, name, PACKAGE="rhdf5")
  invisible(group)
}
print.hdf5.group <- function(x, ...) {
  .Call("HDF_group_print", x, PACKAGE="rhdf5")
  invisible(x)
}

names.hdf5.group <- function(x, ...)
  .Call("HDF_group_members", x, PACKAGE="rhdf5")

print.hdf5.info <- function(x, ...) {
  cat("Type: ", x$type, "\n")
  cat("Links: ", x$links, "\n")
  cat("Modification Time: ", x$modification.time, "\n")
  invisible(x)
}
groupgetinfo <- function(group, name)
  .Call("HDF_group_get_info", group, name, PACKAGE="rhdf5")

"[[.hdf5.group" <- function(group, name) {
    if(length(name) != 1)
        stop("second argument is the wrong length")
    nms <- names(group)
    if(is.numeric(name) ) {
        if(length(group) < name)
            stop("index out of range")
        name <- nms[name]
    } else {
        if( !(name %in% nms) )
            stop(paste(name, "is not one of the named objects"))
    }

   info <- .Call("HDF_group_get_info", group, name, PACKAGE="rhdf5")
   if( is.null(info)) return(NULL)
   if(info$type == "group") {
       return(.Call("HDF_group_get_group", group, name, PACKAGE="rhdf5"))
   }
   if(info$type == "dataset") {
       return(.Call("HDF_group_get_dataset", group, name, PACKAGE="rhdf5"))
   }
   return(NULL)
}

"$.hdf5.group" <- function(group,name) "[[.hdf5.group"(group,name)

"[.hdf5.group" <- function(x,...) stop("not implemented")
#"[.hdf5.group" <- function(x,...) "[[.hdf5.group"(x,names(x)[..1])

#Why doesn't this work?
##comment out for now - not sure what containers were meant to do
#as.container <- function(x, ...) UseMethod("as.container")
#as.container.hdf5.group <- function(x, ...) {
#  #There should be some consistency checking here
#  class(x) <- c("container",class(x))
#  group
#}

hdf5.apply <- function(X, REGION, FUN=function(x) x,...) {
  FUN <- match.fun(FUN)
  .Call("HDF_group_apply", X, FUN, REGION, list(...), PACKAGE="rhdf5")
}
# IO related functions

hdf5.readcel <- function(set, file, create = hdf5.default.properties)
    .Call("HDF_readCEL", set, file, create, PACKAGE="rhdf5")
#
# HDF5 Property List Functions
#
hdf5.plist.create <- function(type,...) {
  switch(type,
         file.create=return(.Call("HDF_plist_file_create",..1,..2,
                            PACKAGE="rhdf5")),
         file.access=return(.Call("HDF_plist_file_access", PACKAGE="rhdf5")),
         dataset.create=return(.Call("HDF_plist_dataset_create",
                               PACKAGE="rhdf5")),
         dataset.xfer=return(.Call("HDF_plist_dataset_xfer", PACKAGE="rhdf5")),
         mount=return(.Call("HDF_plist_mount", PACKAGE="rhdf5")))
  return(hdf5.default.properties)
}

hdf5.plist.set.cache <- function(plist,bytes)
  .Call("HDF_plist_set_cache",plist,bytes, PACKAGE="rhdf5")

print.hdf5.proplist <- function(x, ...)
  .Call("HDF_plist_print", x, PACKAGE="rhdf5")

hdf5.get.default.plist <- function() .Call("HDF_plist_default_plist", PACKAGE="rhdf5")

.initHDF5 <- function(where) {
    assign("hdf5.default.properties", hdf5.get.default.plist(),
    env=where)
    assign(".hdf5.Rwork", .hdf5.Rwork, env=where)
    assign(".hdf5.Rwork.Current", .hdf5.Rwork.Current, env=where)
    assign(".hdf5.space.dims.symbol" , .hdf5.space.dims.symbol, env=where)
    rm(.hdf5.Rwork, .hdf5.Rwork.Current,
         .hdf5.space.dims.symbol, envir=.GlobalEnv)
}
.First.lib <- function(lib, pkg, where) {
  library.dynam("rhdf5",pkg,lib)
  .Call("HDF_init", PACKAGE="rhdf5")
  if (missing(where)) {
      where <- match(paste("package:", pkg, sep = ""),
                     search())
      if (is.na(where)) {
          warning(paste("Not a package name: ", pkg))
          return()
      }
      where <- as.environment(where)
  }

  .initHDF5(where)
}

