;; -------  internal functions -----------

;-------------------------- NXprintError --------------------------------------
; hack Nxprinterror if you want errors printed somewhere else and not onto the
; IDL prompt. You may choose to pop message boxes instead.



PRO NXprinterror, txt
     Print, txt
END

FUNCTION NXcheck, handle
     IF N_PARAMS() LT 1 THEN BEGIN
        NXprinterror, 'ERROR: Internal, insufficient number of arguments to NXcheck'
        return, 0
      END
      IF handle.NXID  NE  110898 THEN BEGIN
         NXprinterror, 'ERROR: invalid NeXus file handle'
         return, 0
      END
      return, 1
END


FUNCTION NXIfindvgroup, handle, name, class
;; root level
  IF handle.iCurrentVG EQ 0 THEN BEGIN
     list = hdf_vg_lone(handle.iVID)
     IF N_ELEMENTS(list) EQ 0 THEN BEGIN
        return, 0
     END
;; look them all up
     FOR I = 0, (N_ELEMENTS(list) - 1) DO BEGIN
       vgid = hdf_vg_attach(handle.iVID,list(I))
       hdf_vg_getinfo, vgid, name=nm, class =cn
       hdf_vg_detach, vgid
       IF (name EQ nm) AND (class EQ cn) THEN BEGIN
         return, list(I)
       END
     END
  END ELSE BEGIN
    hdf_vg_gettrs, handle.iCurrentVG, tags, refs
    FOR I = 0, (N_ELEMENTS(tags) - 1) DO BEGIN
      IF tags(I) EQ 1965 THEN BEGIN
        vgid = hdf_vg_attach(handle.iVID,refs(I))
        hdf_vg_getinfo, vgid, name=nm, class =cn
        hdf_vg_detach, vgid
        IF (name EQ nm) AND (class EQ cn) THEN BEGIN
           return, refs(I)
        END
      END
    END
  END
  return, 0
END


FUNCTION NXIfindsds, handle, name
;; no arg checking, as this is supposed to be called only internally
;; root level
  IF handle.iCurrentVG EQ 0 THEN BEGIN
     hdf_sd_fileinfo, handle.iSID, iSDS, iATT
     for i = 0, (iSDS - 1) DO BEGIN
         iNew = hdf_sd_select(handle.iSID,i)
         hdf_sd_getinfo, iNew,name = me
         iRef = hdf_sd_idtoref(iNew)
         hdf_sd_endaccess,iNew
         IF me EQ name THEN return, iRef
     END
  END ELSE BEGIN ; vGroup level
          hdf_vg_getinfo,handle.iCurrentVG, NENTRIES = iN
          FOR i = 0, (iN - 1) DO BEGIN
             hdf_vg_gettr, handle.iCurrentVG,i,iTag,iRef
             IF (iTag EQ 700) OR (iTag EQ 720) OR (iTag EQ 703) THEN BEGIN
               ; DFTAG_SDG, DFTAF_NDG, DFTAG_SDS
               iNew = hdf_sd_reftoindex(handle.iSID,iRef)
               i2 = hdf_sd_select(handle.iSID,iNew)
               hdf_sd_getinfo, i2, name = me
               hdf_sd_endaccess, i2
               IF me EQ name THEN return, iRef
             END
          END
  END
  return, 0
END

;; -------- external functions ------------

Function NXopen, filename, access, handle
    COMMON setting1, HDF_access
    S = 0
    HDF_access = access
    IF ( SIZE(access,/TNAME) NE 'STRING') THEN BEGIN
        print, 'ERROR: Wrong datatype of variable ACCESS! ACCESS must be of type STRING.'
        stop, 'Current type of variable ACCESS is: ', SIZE(access,/TNAME)
    ENDIF
    c_access = 0
    CASE access OF
      "NXACC_CREATE": c_access = 2
      "NXACC_CREATE5": c_access = 1
      "NXACC_RDWR": c_access = 3
      "NXACC_READ": c_access = 3
    ELSE: stop, 'ERROR: Unknown access property! File can not be opened with ', access
    ENDCASE
    IF ( SIZE(handle,/TNAME) EQ 'UNDEFINED') THEN BEGIN
       print, 'ERROR: Parameter HANDLE of NXopen function is not defined!'
       stop, 'HANDLE must be of type LONG!'
    ENDIF
    IF ( SIZE(handle,/TNAME) NE 'LONG') THEN BEGIN
       print, 'Warning: Wrong datatype of variable HANDLE! HANDLE is casted to type of LONG.'
    ENDIF
    ;  the NeXus data structure
    handle = {NXstruct, NXID: 110898, Acess: ' ', iVID:LONG(0), $
              iCurrentVG: LONG(0), iSID:LONG(0), $
              iCurrentSDS:LONG(0), iVREF:LONARR(10), $
              iStackPtr:0, hdf_type:LONG(0)}
    IF (c_access EQ  2) THEN BEGIN
;;      HDF4 will be used !
        handle.hdf_type = 2
    END ELSE BEGIN
        IF (c_access EQ  1) THEN BEGIN
;;         HDF5 will be used !
           handle.hdf_type = 1
        END ELSE BEGIN
;;         read HDF4 or HDF5
           iRet=H5F_is_hdf5(filename)
           IF (iRet EQ 0) THEN BEGIN
              iRet=HDF_ishdf(filename)
              IF (iRet EQ 0) THEN BEGIN
                  stop, 'ERROR: File Format not supported!'
              END ELSE BEGIN
;;               existing file is HDF4
                 handle.hdf_type = 2
              ENDELSE
           END ELSE BEGIN
;;            existing file is HDF5
              handle.hdf_type = 1
           ENDELSE
        ENDELSE
    ENDELSE
    IF (handle.hdf_type EQ 1) THEN BEGIN
       CASE access OF
          "NXACC_CREATE5": handle.iVID = H5F_CREATE(filename)
          "NXACC_RDWR":  handle.iVID = H5F_OPEN(filename)
          "NXACC_READ":  handle.iVID = H5F_OPEN(filename)
        ELSE: stop, 'ERROR: Unknown access property! File can not be opened with ', access
        ENDCASE
    END ELSE BEGIN
;;      open file, depending on access code
        if access EQ 'NXACC_READ' then begin
           handle.iVID = hdf_open(filename,/read)
           handle.Acess = 'read'
           handle.iSID = hdf_sd_start(filename,/read)
        end
 ;
        IF access EQ 'NXACC_RDWR' THEN BEGIN
           handle.iVID = hdf_open(filename,/write)
           handle.iSID = hdf_sd_start(filename,/RDWR)
           handle.Acess = 'write'
        END
;
        IF access EQ 'NXACC_CREATE' THEN BEGIN
          handle.iSID = hdf_sd_start(filename,/create)
          handle.iVID = hdf_open(filename,/write)
          handle.Acess = 'write'
          hdf_sd_attrset,handle.iSID, 'file_name',filename
;;        fix me, time is not in NeXus standard format
          tim = systime()
          hdf_sd_attrset, handle.iSID, 'file_time',tim
        END
    ENDELSE
    IF (handle.iVID GT 0) THEN BEGIN
       S = 1
    ENDIF
    return, S
end

Function NXclose, handle
    S = 0
    IF (handle.hdf_type EQ 1) THEN BEGIN
        H5F_CLOSE, handle.iVID
    END ELSE BEGIN
;;      close open vGroups
        IF handle.iCurrentVG NE 0 THEN BEGIN
           hdf_vg_detach, handle.iCurrentVG
        END
;;      close open SDS
        IF handle.iCurrentSDS NE 0 THEN BEGIN
           hdf_sd_endaccess, handle.iCurrentSDS
        END
;;      close SDS-API
        hdf_sd_end, handle.iSID
;;      close file
        hdf_close, handle.iVID
    ENDELSE
    handle = 0
    S = 1
    return, S
end

Function NXopengroup, handle, name, nxclass
    S = 0

    IF (handle.hdf_type EQ 1) THEN BEGIN
       IF ( SIZE(name,/TNAME) NE 'STRING') THEN BEGIN
          print, 'ERROR: Wrong datatype of variable NAME! NAME must be of type STRING.'
          stop, 'Current type of variable NAME is: ', SIZE(name,/TNAME)
       ENDIF
       IF ( SIZE(nxclass,/TNAME) NE 'STRING') THEN BEGIN
          print, 'ERROR: Wrong datatype of variable NXCLASS! NXCLASS must be of type STRING.'
          stop, 'Current type of variable NXCLASS is: ', SIZE(nxclass,/TNAME)
       ENDIF
       IF (handle.iCurrentVG EQ 0) THEN BEGIN
          handle.iCurrentVG = H5G_open(handle.iVID, name);
          IF (handle.iCurrentVG LE 0) THEN BEGIN
             stop, 'ERROR: Group does not exist!'
          ENDIF
       END ELSE BEGIN
          iRet = H5G_open(handle.iCurrentVG,name);
          IF (iRet LE 0) THEN BEGIN
             stop, 'ERROR: Group does not exist!'
          ENDIF
          handle.iVREF(handle.iStackPtr) = handle.iCurrentVG
          handle.iCurrentVG = iRet
       ENDELSE
       IF (handle.iCurrentVG GT 1) THEN BEGIN
          handle.iStackPtr = handle.iStackPtr + 1
          S = 1
       ENDIF
    END ELSE BEGIN
;;     check arguments
       IF N_PARAMS() LT 3 THEN BEGIN
          NXprinterror, 'ERROR: Insufficient number of arguments to NXopengroup'
          return, 0
       END
;;     check our handle
       iRET = NXcheck(handle)
       IF iRET NE 1 THEN return, 0
;;     install error handler
       catch, errvar
       IF errvar NE 0 THEN BEGIN
         NXprinterror, !ERR_String
         return, 0
       END
;;     search the vGroup
       iRef = NXIfindvgroup(handle,name,nxclass)
       IF iRef EQ 0 THEN BEGIN
          NXprinterror, 'ERROR: Requested vGroup NOT found'
          return,0
       END
;;     at root:
       IF handle.iCurrentVG EQ 0 THEN BEGIN
       IF handle.Acess EQ 'read' THEN $
          handle.iCurrentVG = hdf_vg_attach(handle.iVID,iRef) $
       ELSE  $
          handle.iCurrentVG = hdf_vg_attach(handle.iVID,iRef,/write)
          handle.iStackPtr = handle.iStackPtr + 1
          handle.iVREF(handle.iStackPtr) = iRef
       END ELSE BEGIN
          hdf_vg_detach, handle.iCurrentVG
          handle.iStackPtr = handle.iStackPtr + 1
          handle.iVREF(handle.iStackPtr) = iRef
          IF handle.Acess EQ 'read' THEN $
             handle.iCurrentVG = hdf_vg_attach(handle.iVID,iRef) $
          ELSE  $
             handle.iCurrentVG = hdf_vg_attach(handle.iVID,iRef,/write)
       END
       IF handle.iCurrentVG LT 0 THEN BEGIN
          NXprinterror, 'ERROR: HDF failed to open vGroup'
          handle.iCurrentVG = 0
          return, 0
       END ELSE $
         S = 1
    ENDELSE
    return, S
end

Function NXclosegroup, handle
    S = 0

    IF (handle.hdf_type EQ 1) THEN BEGIN
       H5G_CLOSE, handle.iCurrentVG
       handle.iStackPtr = handle.iStackPtr - 1
       handle.iCurrentVG = handle.iVREF(handle.iStackPtr)
       S = 1
    END ELSE BEGIN
;;     check arguments
       IF N_PARAMS() LT 1 THEN BEGIN
          NXprinterror, 'ERROR: Insufficient number of arguments to NXclosegroup'
          return, 0
       END
;;     check our handle
       iRET = NXcheck(handle)
       IF iRET NE 1 THEN return, 0
;;     install error handler
       catch, errvar
       IF errvar NE 0 THEN BEGIN
          NXprinterror, !ERR_String
          return, 0
       END
;;     the trivial case: we are at root
       IF handle.iCurrentVG EQ 0 THEN BEGIN
          return, 1
       END ELSE BEGIN
          hdf_vg_detach,handle.iCurrentVG
          handle.iStackPtr = handle.iStackPtr - 1
          IF handle.iStackPtr LE 0 THEN BEGIN ; we are at root now
             handle.iStackPtr = 0
             handle.iCurrentVG = 0
          END ELSE BEGIN ; open lower vGroup
             iRef = handle.iVREF(handle.iStackPtr)
             IF handle.Acess EQ 'read' THEN $
             handle.iCurrentVG = hdf_vg_attach(handle.iVID,iRef) $
          ELSE  $
             handle.iCurrentVG = hdf_vg_attach(handle.iVID,iRef,/write)
          END
       END
       S = 1
    ENDELSE
    return, S
end

Function NXopendata, handle, dname

   CATCH, Error_status
if Error_status ne 0 then begin
catch, /cancel
return,0
endif


    S = 0

    IF (handle.hdf_type EQ 1) THEN BEGIN
       IF ( SIZE(dname,/TNAME) NE 'STRING') THEN BEGIN
          print, 'ERROR: Wrong datatype of variable NAME! NAME must be of type STRING.'
          stop, 'Current type of variable NAME is: ', SIZE(dname,/TNAME)
       ENDIF
       handle.iCurrentSDS = H5D_OPEN(handle.iCurrentVG,dname)
       IF (handle.iCurrentSDS GT 0) THEN BEGIN
          S = 1
       ENDIF
       IF (handle.iCurrentSDS LE 0) THEN BEGIN
          stop, 'ERROR: Dataset does not exist!'
          ENDIF
    END ELSE BEGIN
;;     check arguments
       IF N_PARAMS() LT 2 THEN BEGIN
          NXprinterror, 'ERROR: Insufficient number of arguments to NXopendata'
          return, 0
       END
;;     check our handle
       iRET = NXcheck(handle)
       IF iRET NE 1 THEN return, 0
;;     install error handler
       catch, errvar
       IF errvar NE 0 THEN BEGIN
          NXprinterror, !ERR_String
          return, 0
       END
;;     find the SDS
       iData = NXIfindSDS(handle,dname)
       IF iData EQ 0 THEN BEGIN
          NXprinterror, 'ERROR: SDS NOT found!'
          return, 0
       END
;;     be nice: close SDS's which may still be open
       IF handle.iCurrentSDS NE 0 THEN BEGIN
          hdf_sd_endaccess, handle.iCurrentSDS
          handle.iCurrentSDS = 0
       END
;;     now do the job
       iNew = hdf_sd_reftoindex(handle.iSID,iData)
       handle.iCurrentSDS = hdf_sd_select(handle.iSID,iNew)
       IF handle.iCurrentSDS LE 0 THEN BEGIN
          NXprinterror, 'ERROR: failed to open SDS'
          handle.iCurrentSDS = 0
          return, 0
       END
       S = 1
    ENDELSE
    return, S
end

Function NXclosedata, handle
   CATCH, Error_status
if Error_status ne 0 then begin
catch, /cancel
return,-1
endif
    S = 0
    IF (handle.hdf_type EQ 1) THEN BEGIN
       IF (handle.iCurrentSDS GT 0) THEN BEGIN
          H5D_CLOSE,handle.iCurrentSDS
          S = 1
       END
    END ELSE BEGIN
;;     check arguments
       IF N_PARAMS() LT 1 THEN BEGIN
          NXprinterror, 'ERROR: Insufficient number of arguments to NXclosedata'
          return, 0
       END
;;     check our handle
       iRET = NXcheck(handle)
       IF iRET NE 1 THEN return, 0
;;     install error handler
       catch, errvar
       IF errvar NE 0 THEN BEGIN
          NXprinterror, !ERR_String
          return, 0
       END
       IF handle.iCurrentSDS NE 0 THEN BEGIN
          hdf_sd_endaccess, handle.iCurrentSDS
          handle.iCurrentSDS = 0
          END ELSE NXprinterror, 'WARNING: no SDS open, nothing to do'
       S = 1
    ENDELSE
    return, S
end


Function NXgetdata, handle, data
   CATCH, Error_status
if Error_status ne 0 then begin
catch, /cancel
data=-1
return,-1
endif

   S = 0

   IF (handle.hdf_type EQ 1) THEN BEGIN
;;    check if a dataset is opened
      IF (handle.iCurrentSDS EQ 0) THEN BEGIN
         stop, 'ERROR: No dataset open!'
         return, 0
      END
      data_id = H5D_get_type(handle.iCurrentSDS)
      data_type = H5T_get_class(data_id)
      data = H5D_READ(handle.iCurrentSDS)
      IF (data_type EQ "H5T_STRING") THEN BEGIN
          st_len = fix(total(StrLen(data)))
          fmt='(A'+String(st_len)+')'
          data = String(data,Format=fmt)
      ENDIF
      H5T_close, data_id
      S = 1
   END ELSE BEGIN
;;    check arguments
      IF N_PARAMS() LT 2 THEN BEGIN
         NXprinterror, 'ERROR: Insufficient number of arguments to NXgetdata'
         return, 0
      END
;;    check our handle
      iRET = NXcheck(handle)
      IF iRET NE 1 THEN return, 0
;;    install error handler
      catch, errvar
      IF errvar NE 0 THEN BEGIN
         NXprinterror, !ERR_String
         return, 0
      END
;;    check if there is an open SDS
      IF handle.iCurrentSDS EQ 0 THEN BEGIN
         NXprinterror, 'ERROR: no SDS open'
         return, 0
      END
;;    do read data
      hdf_sd_getdata, handle.iCurrentSDS, data
      S = 1
   ENDELSE
   return, S
END


Function NXgetattr, handle, attr_name, attr_data, attr_type
    S = 0

    IF (handle.hdf_type EQ 1) THEN BEGIN

;       IF (SIZE(attr_name,/TNAME) NE 'STRING') THEN BEGIN
;          print, 'ERROR: Wrong datatype of variable ATTR_NAME! ATTR_NAME must be of type STRING.'
;          stop, 'Current type of variable ATTR_NAME is: ', SIZE(attr_name,/TNAME)
;       ENDIF
;       IF ( SIZE(attr_type,/TNAME) NE 'LONG') THEN BEGIN
;          print, 'ERROR: Wrong datatype of variable ATTR_TYPE! ATTR_TYPE must be of type LONG.'
;          stop, 'Current type of variable ATTR_TYPE is: ', SIZE(attr_type,/TNAME)
;       ENDIF
;;     find attribute
       IF (handle.iCurrentSDS NE 0) THEN BEGIN
;;        Dataset attribute
          iNew = H5A_open_name(handle.iCurrentSDS, attr_name)
       END ELSE BEGIN
;;        globale and group attributes
          IF (handle.iCurrentVG NE 0 ) THEN BEGIN
;;           group attribute
             iNew = H5A_open_name(handle.iCurrentVG, attr_name)
          END ELSE BEGIN
;;           global attributes
             glob = H5G_open(handle.iVID,"/")
             iNew = H5A_open_name(glob, attr_name)
             IF (iNew LT 0) THEN BEGIN
                stop, 'ERROR: Attribute not found ! '
             ENDIF
             attr_id = H5A_get_type(iNew)
             attr_type = H5T_get_class(attr_id)
          ENDELSE
       ENDELSE
       d_switch = 0
       IF (attr_type EQ "H5T_STRING") THEN BEGIN
          attr_data = String('',Format='(A255)')
          d_switch = 1
       ENDIF
       IF (attr_type EQ "H5T_FLOAT") THEN BEGIN
          attr_data = 0.0
          d_switch = 1
       ENDIF
       IF (attr_type EQ "H5T_INTEGER") THEN BEGIN
          attr_data = 0L
          d_switch = 1
       ENDIF
       IF (d_switch LE 0) THEN BEGIN
          print, attr_type
          H5T_close, attr_id
          stop, 'ERROR: Unknown data type! '
       ENDIF
       H5T_close, attr_id
;;     finally read the data
       attr_data = H5A_read(iNew)
       H5A_close, iNew
       IF (glob GT 0) THEN BEGIN
          H5G_close, glob
       ENDIF
    END ELSE BEGIN
;;     check arguments
       IF N_PARAMS() LT 4 THEN BEGIN
          NXprinterror, 'ERROR: Insufficient number of arguments to NXgetattr'
          return, 0
       END
;;     check our handle
       iRET = NXcheck(handle)
       IF iRET NE 1 THEN return, 0
;;     install error handler
       catch, errvar
       IF errvar NE 0 THEN BEGIN
          NXprinterror, !ERR_String
          return, 0
       END
;;     find the attribute
       IF handle.iCurrentSDS EQ 0 THEN BEGIN ; global attribute
          iID = hdf_sd_attrfind(handle.iSID,attr_name)
       END ELSE BEGIN
          iID = hdf_sd_attrfind(handle.iCurrentSDS,attr_name)
       END
       IF iID LT 0 THEN BEGIN
          NXprinterror, 'ERROR: attribute NOT found!'
          return, 0
       END
;;     read the attribute
       IF handle.iCurrentSDS EQ 0 THEN BEGIN
          hdf_sd_attrinfo,handle.iSID, iID, name = nm, data = attr_data, HDF_TYPE = attr_type
       END ELSE BEGIN
          hdf_sd_attrinfo,handle.iCurrentSDS, iID, name = nmm, data = attr_data, HDF_TYPE = attr_type
       END
       S = 1
    ENDELSE
    return, S
end

;; -----------  only HDF4 support -----------------

FUNCTION NXgetslab, handle, data, start, ente
;; check arguments
   IF N_PARAMS() LT 4 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXgetslab'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; check if there is an open SDS
   IF handle.iCurrentSDS EQ 0 THEN BEGIN
      NXprinterror, 'ERROR: no SDS open'
      return, 0
   END
;; do read data
   hdf_sd_getdata, handle.iCurrentSDS, data, start=start, count=ente
   return, 1
END


FUNCTION NXputdata, handle, data
;; check arguments
   IF N_PARAMS() LT 2 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXputdata'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; check if there is an open SDS
   IF handle.iCurrentSDS EQ 0 THEN BEGIN
      NXprinterror, 'ERROR: no SDS open'
      return, 0
   END
;; write  data
   hdf_sd_adddata, handle.iCurrentSDS, data
   return, 1
END

FUNCTION NXputslab, handle, data, start, ente
;; check arguments
   IF N_PARAMS() LT 4 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXputslab'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; check if there is an open SDS
   IF handle.iCurrentSDS EQ 0 THEN BEGIN
      NXprinterror, 'ERROR: no SDS open'
      return, 0
   END
;; write data
   hdf_sd_adddata, handle.iCurrentSDS, data, start=start, count=ente
   return, 1
END

FUNCTION NXputattr, handle, name, data
;; check arguments
   IF N_PARAMS() LT 3 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXputattr'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; set the attribute
    IF handle.iCurrentSDS EQ 0 THEN BEGIN
       hdf_sd_attrset,handle.iSID,name,data
    END ELSE BEGIN
       hdf_sd_attrset,handle.iCurrentSDS, name,data
    END
    return, 1
END

FUNCTION NXgetinfo, handle, rank, dim, type
;;check arguments
   IF N_PARAMS() LT 2 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXgetdata'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; check if there is an open SDS
   IF handle.iCurrentSDS EQ 0 THEN BEGIN
      NXprinterror, 'ERROR: no SDS open'
      return, 0
   END
;; get data
   hdf_sd_getinfo, handle.iCurrentSDS, dims = dim, HDF_TYPE = type, NDIMS = rank
   return, 1
END

FUNCTION NXgroupdir, handle,names, class
;; check arguments
   IF N_PARAMS() LT 3 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXgroupdir'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; handling root level
   IF handle.iCurrentVG EQ 0 THEN BEGIN
      list = hdf_vg_lone(handle.iVID)
      iLen = N_ELEMENTS(list)
      names = STRARR(iLen)
      class = STRARR(iLen)
      FOR I = 0, (iLen - 1) DO BEGIN
         vgid = hdf_vg_attach(handle.iVID,list(I))
         hdf_vg_getinfo, vgid, name = nm, class = cn
         hdf_vg_detach, vgid
         names(I) = nm
         class(I) = cn
      END
      return, 1
   END ELSE BEGIN ; vGroup level
       hdf_vg_gettrs, handle.iCurrentVG, tags, refs
       iLen = N_ELEMENTS(tags)
       inames = STRARR(iLen+1)
       iclass = STRARR(iLen+1)
       iFound = 0
       FOR i = 0, (iLen - 1) DO BEGIN
            iTag = tags(I)
            IF iTag EQ 1965 THEN BEGIN ; vGroup
               vgid = hdf_vg_attach(handle.iVID,refs(I))
               hdf_vg_getinfo, vgid, name =nm, class = cn
               hdf_vg_detach, vgid
               inames[iFound] = nm
               iclass[iFound] = cn
               iFound = iFound + 1
            END
            IF (iTag EQ 700) OR (iTag EQ 720) OR (iTag EQ 703) THEN BEGIN
              ; scientific data
                iNew = hdf_sd_reftoindex(handle.iSID,refs[I])
                i2 = hdf_sd_select(handle.iSID, iNew)
                hdf_sd_getinfo, i2, name = nm
                hdf_sd_endaccess, i2
                inames[iFound] = nm
                iclass[iFound] = 'SDS'
                iFound = iFound + 1
            END
       END
       names = inames[0:iFound]
       class = iclass[0:iFound]
       return, 1
   END
   return, 0
END

FUNCTION NXattdir, handle, names
;; check arguments
   IF N_PARAMS() LT 2 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXattdir'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; root level
   IF handle.iCurrentSDS EQ 0 THEN BEGIN
      hdf_sd_fileinfo, handle.iSID, ds, atts
      names = STRARR(atts)
      FOR i = 0, (atts - 1) DO BEGIN
        hdf_sd_attrinfo, handle.iSID, i, name = nm, data =dat, HDF_TYPE = typ
        names[i] = nm
      END
      return, 1
   END ELSE BEGIN ; SDS attributes
      hdf_sd_getinfo, handle.iCurrentSDS, NATTS = atts
      names = STRARR(atts)
      FOR i = 0, (atts - 1) DO BEGIN
        hdf_sd_attrinfo, handle.iCurrentSDS, i, name = nm, data =dat, HDF_TYPE =typ
        names[i] = nm
      END
      return, 1
   END
END

FUNCTION NXgetgroupid, handle, id
;; check arguments
   IF N_PARAMS() LT 2 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXgetgroupid'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; invalid when at root
   IF handle.iCurrentVG EQ 0 THEN BEGIN
      NXprinterror, 'ERROR: No ID for root level'
      return, 0
   END
;; alright do it
   id = lonarr(2)
   id[0] = 1965
   id[1] = handle.iCurrentVG
   return, 1
END

FUNCTION NXgetdataid, handle, id
;; check arguments
   IF N_PARAMS() LT 2 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXgetdataid'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; invalid when at root
   IF handle.iCurrentSDS EQ 0 THEN BEGIN
      NXprinterror, 'ERROR: No  SDS open, no ID s then'
      return, 0
   END
;; alright do it
   id = lonarr(2)
   id[0] = 703
   id[1] = hdf_sd_idtoref(handle.iCurrentSDS)
   return, 1
END

FUNCTION NXmakelink, handle, id

;;  invalid if no vGroup open
    IF handle.iCurrentVG EQ 0 THEN BEGIN
;;            NXprinterror, 'ERROR: will not link into root level'
       return, 0
    END
;;  do it
    hdf_vg_addtr, handle.iCurrentVG, id[0], id[1]
    return, 1
END

FUNCTION NXmakegroup, handle, nname, cclass

;; make we do it?
    IF handle.Acess NE 'write' THEN BEGIN
       NXprinterror, 'ERROR: no permission to create vGroup'
       return,0
    END
;; make sure, that a group with this name does not yet exist
    iRet = NXIfindvgroup(handle,nname,cclass)
    IF iRet NE 0 THEN BEGIN
         NXprinterror, 'ERROR: vGroup already exists'
         return, 0
    END
;; do it
    iNew = hdf_vg_attach(handle.iVID,-1,/write)
    IF iNew LT 0 THEN BEGIN
       NXprinterror, 'ERROR: failed to create vGroup'
       return, 0
    END
    hdf_vg_setinfo, iNew, name = nname, class = cclass
;; insert when apropriate
    IF handle.iCurrentVG NE 0 THEN BEGIN
        hdf_vg_insert, handle.iCurrentVG, iNew
    END
    hdf_vg_detach, iNew
    return, 1
END

FUNCTION NXmakedata, handle, name, datatype, rank, dimensions
;; check arguments
   IF N_PARAMS() LT 5 THEN BEGIN
       NXprinterror, 'ERROR: Insufficient number of arguments to NXmakedata'
       return, 0
    END
;; check our handle
   iRET = NXcheck(handle)
     IF iRET NE 1 THEN return, 0
;; install error handler
   catch, errvar
   IF errvar NE 0 THEN BEGIN
      NXprinterror, !ERR_String
      return, 0
   END
;; do we have write privilege?
   IF handle.Acess NE 'write' THEN BEGIN
      NXprinterror, 'ERROR: no privilege to create SDS'
      return, 0
   END
;; is there already a SDS with the same name at the current level?
   iRet = NXIfindsds(handle,name)
   IF iRet NE 0 THEN BEGIN
      NXprinterror, 'ERROR: Cannot create duplicate SDS name'
      return, 0
   END
;; check rank
   IF rank LE 0 THEN BEGIN
      NXprinterror, 'ERROR: invalid rank parameter specified'
      return, 0
   END
;; check dims
   IF N_ELEMENTS(dimensions) LT rank THEN BEGIN
      NXprinterror, 'ERROR: not enough dimension values in dimensions array'
      return, 0
   END
;; be nice, if there is already an SDS open
   IF handle.iCurrentSDS NE 0 THEN BEGIN
      hdf_sd_endaccess, handle.iCurrentSDS
      handle.iCurrentSDS = 0
   END
;; disallow SDS creation at root level
   IF handle.iCurrentVG EQ 0 THEN BEGIN
      NXprinterror, 'ERROR: SDS creation at root level not permitted in NeXus'
      return, 0
   END
;; actually create the data set, depending on the value of the type info
   CASE datatype OF
        'NX_FLOAT32': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_FLOAT32)
        'NX_FLOAT64': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_FLOAT64)
        'NX_INT8': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/Byte)
        'NX_UINT8': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_UINT8)
        'NX_CHAR': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_CHAR)
        'NX_INT16': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_INT16)
        'NX_UINT16': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_UINT16)
        'NX_INT32': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_INT32)
        'NX_UINT32': $
           iRes = hdf_sd_create(handle.iSID,name,dimensions,/DFNT_UINT32)
         ELSE: BEGIN
            NXprinterror, 'ERROR: datatype not recognised'
            return, 0
         END
    ENDCASE
    IF iRes LT 0 THEN BEGIN
        NXprinterror, 'ERROR: failed to create SDS'
        return, 0
    END
;; link into vGroup
    IF handle.iCurrentVG NE 0 THEN BEGIN
       iRef = hdf_sd_idtoref(iRes)
       hdf_vg_addtr,handle.iCurrentVG, 700,iRef
    END
    hdf_sd_endaccess, iRes
    return, 1
END
