// ------------------------------------------------------------------------------
// NeXus - Neutron & X-ray Common Data Format
//
// Delphi/Kylix Nexus utilities
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Contact for bug reports and problems :
//           F. Ott <fott@cea.fr>
//           Lab. Léon Brillouin CEA/CNRS
//           CE Saclay
//           91191 Gif sur Yvette, FRANCE
//
// For further information, see <http://www.neutron.anl.gov/NeXus/>
//
// ------------------------------------------------------------------------------
{ BUGS / LIMITATIONS }
{ * in "writeGlobals", the fields cannot be put INSide a folder                 }
{   either in parallel or within a dataSet                                      }
{ * can signal take values different from 1? what is it used for?               }
{ * the attriute 'primary' is compulsory                                        }
{ * the procedures NXUfindLink and NXUresumeLink are not implemented            }
{   they also require the implementation of NXUSearchGroup                      }
{ * there is a NXCloseData in the procedure NXUconfirmdata; I am wondering how  }
{   the calls to NXUconfirmdata do actually work in the fortran implementation  }
{ * for NXUReadData, the procedure automatically opens the data                 }
{   should the same be done for NXUwriteData ?                                  }
{ * something like "appendData" is missing                                      }
{   it is essential for experiments                                             }
{ * the procedure NXUconfirmdata is not really used                             }
{ one problem being that when reading data, no assumption is made on their size }
{ * writeGroup does not work properly if the gorup already exists!!     }
{ * there is a problem when reading data 2D, with the initialisation of the dimensions }
{  this is also conected with the NXUconfirmdata Problem                        }
{ * the way to process NEXUS errors is not described                            }

unit NexusUtilityDelphiAPI;

interface

uses sysUtils,NexusCoreDelphiAPI,QDialogs;

var
   NXcompress_type:integer = NX_COMP_NONE;
   NXcompress_size:integer = 100;

{ for internal use only }
function NXGetStrDataType(NXtype:integer):string;
{ public procedures }
{ all parameters are needed, if you put '', the parameter is not written }
function NXUwriteGlobals(file_id:integer;user, affiliation, address, phone, fax, email:string):integer; { ok }
function NXUwriteGroup(file_id:integer;group_name, group_class:string):integer; { ok }
{ NXUwriteData for various types } { 0D and 1D only for the moment }
function NXUwriteData(file_id:integer;data_name:string;data:integer;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:single;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:double;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:TDynArrayInt32;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:TDynArrayFloat32;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:TDynArrayFloat64;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:TDynArray2DInt32;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:TDynArray2DFloat32;units:string):integer; overload;
function NXUwriteData(file_id:integer;data_name:string;data:TDynArray2DFloat64;units:string):integer; overload;
{ NXUreadData for various types } { 0D and 1D only for the moment }
function NXUreadData(file_id:integer;data_name:string;var data:integer;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:single;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:double;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:TDynArrayInt32;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:TDynArrayFloat32;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:TDynArrayFloat64;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:TDynArray2DInt32;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:TDynArray2DFloat32;var units:string):integer; overload;
function NXUreadData(file_id:integer;data_name:string;var data:TDynArray2DFloat64;var units:string):integer; overload;
{ not implmeneted yet }
function NXUwriteHistogram(file_id:integer;data_name:string;data:string;units:string):integer;
function NXUreadHistogram(file_id:integer;data_name:string;var data:string;var units:string):integer;
{ NXUSetCompress }
function NXUsetcompress(file_id:integer;compress_type,compress_size:integer):integer;
{ findong group, data and attributes }
function NXUfindgroup(file_id:integer;group_name:string;var group_class:string):integer; { ok }
function NXUfindClass(file_id:integer;group_class:string;var group_name:string;find_index:integer):integer; { ok }
function NXUfindData(file_id:integer;data_name:string):integer; { ok }
function NXUfindAttr(file_id:integer;attr_name:string):integer; { ok }
function NXUfindSignal(file_id:integer;signal:integer;var data_name:string;var data_rank,data_type:integer;var data_dimensions:dimensions):integer; { ok }
function NXUfindAxis(file_id:integer;axis,primary:integer;var data_name:string;var data_rank,data_type,data_dimensions:integer):integer; { ok }
{ finding linked groups, not implemented yet }
function NXUfindLink(file_id:integer;group_class:string;var group_id:NXlink):integer; { not implemented }
function NXUresumeLink(file_id:integer;group_id:NXlink):integer; { not implemented }

implementation

{ return the product of the dimensions of the data }
{ i.e. the product of the vector along the different dimensions }
{ correspond to the function PRODUCT in Fortran                 }
function totalSize(dims:dimensions;min,max:integer):integer;
var i,aux:integer;
begin
  aux:=1;
  for i:=min to max  do aux:=aux*dims[i];
  totalSize:=aux;
end;

{ returns a string corresponding to a Nexus datatype given as an input }
function NXGetStrDataType(NXtype:integer):string;
var s:string;
begin
    case NXtype of
      NX_CHAR: s := 'NX_CHAR';
      NX_FLOAT32: s := 'NX_FLOAT32';
      NX_FLOAT64: s := 'NX_FLOAT64';
      NX_INT8: s := 'NX_INT8';
      NX_INT16: s := 'NX_INT16';
      NX_INT32: s := 'NX_INT32';
      NX_UINT32: s := 'NX_UINT32';
    else s := 'UNKNOWN';
    end;
end;


{ NXUpreparedata creates and opens a data set                                   }
{ the dimensions are to be given in the following order X,Y,Z etc               }
{ that is the convention is inverted with repsect to what is used in NXmakaData }
{ or Get info                                                                   }
function NXUpreparedata(file_id:integer;data_name:string;data_type, data_rank:integer;
                        data_dimensions:dimensions):integer;
var i,statusOut,status:integer;
    NXrank,NXtype:integer;
    NXdims:dimensions;
begin
{ inversion of the dimensions }

  status := NXUfinddata(file_id, data_name);
  if status = NX_EOD { it is necessary to create the data item }
  then begin
       status := NXmakedata (file_id, StrToPChar(data_name), data_type, data_rank, data_dimensions);
       if status=NX_OK then NXopendata (file_id, StrToPChar(data_name)); end
  else if status = NX_OK { data item already exists }
       then begin
            status := NXopendata(file_id, StrToPChar(data_name));
            status := NXgetinfo(file_id, NXrank, NXdims, NXtype);
            if (NXtype<>data_type)
            then begin MessageDlg('Type of existing data item does not match new data', mtInformation,[mbOk], 0, mbOk);status:=NX_ERROR; end
            else if (NXrank<>data_rank)
                 then begin MessageDlg('Rank of existing data item does not match new data', mtInformation,[mbOk], 0, mbOk);status:=NX_ERROR; end
                 else for i:=1 to NXrank do
                        if (data_dimensions[i] > NXdims[i])
                        then begin MessageDlg('Size of new data too large for existing item', mtInformation,[mbOk], 0, mbOk);status:=NX_ERROR; end
            end;
  if (status=NX_OK) and (NXcompress_type<>NX_COMP_NONE) and
          (TotalSize(data_dimensions,1,data_rank) > NXcompress_size)
  then status := NXcompress(file_id, NXcompress_type);
  NXUpreparedata:=status;
end;

{ NXUconfirmdata checks that a dataset has the expected type, rank              }
{ and returns the dimensions of the data                                        }
function NXUconfirmdata(file_id:integer;data_name:string;data_type, data_rank:integer;
                        var data_dimensions:dimensions):integer;
var statusOut,status:integer;
    NXrank,NXtype:integer;
    NXdims:dimensions;
begin
  status:=NXopendata(file_id, StrToPChar(data_name));
  if status<>NX_OK
  then statusOut:=status
  else begin
       status:=NXgetinfo(file_id, NXrank, NXdims, NXtype);
       if status<>NX_OK
       then statusOut:=status
       else if (NXrank <> data_rank)
            then begin statusOut:=NX_ERROR;MessageDlg('Ranks do not match', mtInformation,[mbOk], 0, mbOk) end
            else if (NXtype<>data_type)
                 then begin statusOut:=NX_ERROR;MessageDlg('Types do not match', mtInformation,[mbOk], 0, mbOk) end
                 else begin data_dimensions:=NXdims;statusOut:=NX_OK end;
       end;
  status := NXclosedata(file_id);
  NXUconfirmdata:=statusOut;
end;



{ ============================================================================= }
{ NEXUS utilities }
function NXUwriteGlobals(file_id:integer;user, affiliation, address, phone, fax, email:string):integer;
var status:integer;
begin
   if (user<>'') then status := NXputattrChar(file_id, 'user',StrToPChar(user),length(user),NX_CHAR);
   if (affiliation<>'') then status := NXputattrChar(file_id, 'affiliation',StrToPChar(affiliation),length(affiliation),NX_CHAR);
   if (address<>'') then status := NXputattrChar(file_id, 'address',StrToPChar(address),length(address),NX_CHAR);
   if (phone<>'') then status := NXputattrChar(file_id, 'telephone_number',StrToPChar(phone),length(phone),NX_CHAR);
   if (fax<>'') then status := NXputattrChar(file_id, 'fax_number',StrToPChar(fax),length(fax),NX_CHAR);
   if (email<>'') then status := NXputattrChar(file_id, 'email',StrToPChar(email),length(email),NX_CHAR);
end;

{ NXUwritegroup creates and leaves open a group }
function NXUwriteGroup(file_id:integer;group_name, group_class:string):integer;
var status:integer;
begin
   status := NXmakegroup(file_id, StrToPChar(group_name), StrToPChar(group_class));
   if (status = NX_OK) then status := NXopengroup(file_id, StrToPChar(group_name), StrToPChar(group_class));
   NXUwriteGroup:=NX_OK
end;

{ ==================== NXUwriteData =========================================== }
{ write a SCALAR INT32  integer data }
{ INPUT : units is compulsory, if there is no obvious unit you MUST put 'raw' for the units }
function NXUwriteData(file_id:integer;data_name:string;data:integer;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=1;
   status := NXUpreparedata(file_id, data_name, NX_INT32, 1, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ write a SCALAR FLOAT32 real data, no point of saving space with 32 bits reals }
{ INPUT : units is compulsory, if there is no obvious unit you MUST put 'raw' for the units }
function NXUwriteData(file_id:integer;data_name:string;data:single;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=1;
   status := NXUpreparedata(file_id, data_name, NX_FLOAT64, 1, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ write a SCALAR FLOAT64 real data, no point of saving space with 32 bits reals }
{ INPUT : units is compulsory, if there is no obvious unit you MUST put 'raw' for the units }
function NXUwriteData(file_id:integer;data_name:string;data:double;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=1;
   status := NXUpreparedata(file_id, data_name, NX_FLOAT64, 1, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ NXUwriteData writes a STRING data item }
{ no units is saved for string data          }
function NXUwriteData(file_id:integer;data_name:string;data:string):integer; overload;
var statusOut,status:integer;
    data_char:TCharacter255;
    size:dimensions;
begin
   size[1]:=length(data);
   data_char:=StrToPChar(data);
   status := NXUpreparedata(file_id, data_name, NX_CHAR, 1, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR;
   statusOut := NXputDataChar(file_id, data_char);
   NXUwriteData:=statusOut;
end;
{ NXUwriteData writes a data ARRAY 1D of INT32 }
{ no units is saved for string data          }
function NXUwriteData(file_id:integer;data_name:string;data:TDynArrayInt32;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
    data_size:integer;
begin
   data_size:=high(data)+1;
   size[1]:=data_size;
   status := NXUpreparedata(file_id, data_name, NX_INT32, 1, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ NXUwriteDataChar writes a data ARRAY 1D of FLOAT32 }
{ no units is saved for string data          }
function NXUwriteData(file_id:integer;data_name:string;data:TDynArrayFloat32;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=high(data)+1;
   status := NXUpreparedata(file_id, data_name, NX_FLOAT32, 1, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ NXUwriteData writes a data ARRAY 1D of FLOAT64 }
{ no units is saved for string data          }
function NXUwriteData(file_id:integer;data_name:string;data:TDynArrayFloat64;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=high(data)+1;
   status := NXUpreparedata(file_id, data_name, NX_FLOAT64, 1, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ NXUwriteData writes a data ARRAY 2D of INT32 }
{ no units is saved for string data          }
function NXUwriteData(file_id:integer;data_name:string;data:TDynArray2DInt32;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=high(data)+1;size[2]:=high(data[0])+1;
   status := NXUpreparedata(file_id, data_name, NX_INT32, 2, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ NXUwriteData writes a data ARRAY 2D of FLOAT32 }
function NXUwriteData(file_id:integer;data_name:string;data:TDynArray2DFloat32;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=high(data)+1;size[2]:=high(data[0])+1;
   status := NXUpreparedata(file_id, data_name, NX_FLOAT32, 2, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;
{ NXUwriteData writes a data ARRAY 2D of FLOAT64 }
function NXUwriteData(file_id:integer;data_name:string;data:TDynArray2DFloat64;units:string):integer; overload;
var statusOut,status:integer;
    size:dimensions;
begin
   size[1]:=high(data)+1;size[2]:=high(data[0])+1;
   status := NXUpreparedata(file_id, data_name, NX_FLOAT64, 2, size);
   if (status<>NX_OK)
   then statusOut:=NX_ERROR
   else if (NXUfindattr(file_id, 'units') = NX_EOD)
        then status := NXputattrChar(file_id, StrToPChar('units'), StrToPChar(units),length(units),NX_CHAR);
   statusOut := NXputData(file_id, data);
   NXUwriteData:=statusOut;
end;

{ ============================================================================= }
{ read data  Scalar Int32                                                       }
function NXUreadData(file_id:integer;data_name:string;var data:integer;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=1;
  status := NXUconfirmdata(file_id,data_name,NX_INT32,1,dims);
  status := NXOpenData(file_id,StrToPChar(data_name)); { because NXUCOnfirmData closes the data ?! }
  if status<>NX_OK then statusOut:=NX_ERROR
  else if (dims[1]<> 1) then statusOut:=NX_ERROR
       else begin
            status:=NXgetdata(file_id, data);
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data  Scalar Float32                                                       }
function NXUreadData(file_id:integer;data_name:string;var data:single;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=1;
  status := NXUconfirmdata(file_id,data_name,NX_FLOAT32,1,dims);
  status := NXOpenData(file_id,StrToPChar(data_name)); { because NXUCOnfirmData closes the data ?! }
  if status<>NX_OK then statusOut:=NX_ERROR
  else if (dims[1]<> 1) then statusOut:=NX_ERROR
       else begin
{            status:=NXgetdata(file_id, data); }
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data  Scalar Float64                                                     }
function NXUreadData(file_id:integer;data_name:string;var data:double;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=1;
  status := NXUconfirmdata(file_id,data_name,NX_FLOAT64,1,dims);
  status := NXOpenData(file_id,StrToPChar(data_name)); { because NXUCOnfirmData closes the data ?! }
  if status<>NX_OK then statusOut:=NX_ERROR
  else if (dims[1]<> 1) then statusOut:=NX_ERROR
       else begin
{            status:=NXgetdata(file_id, data); }
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data String                                                              }
function NXUreadData(file_id:integer;data_name:string;var data:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    data_char:TCharacter255;
begin
  dims[1]:=length(data);
  status := NXUconfirmdata(file_id,data_name,NX_CHAR,1,dims);
  status := NXOpenData(file_id,StrToPChar(data_name));
  if status<>NX_OK then statusOut:=NX_ERROR
  else begin status:=NXgetdata(file_id, data);statusOut:=NX_OK end;
  data:=data_char;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data 1D Array of INT32                                                   }
function NXUreadData(file_id:integer;data_name:string;var data:TDynArrayInt32;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=high(data)+1;
  status := NXUconfirmdata(file_id,data_name,NX_INT32,1,dims);
  status := NXOpenData(file_id,StrToPChar(data_name));
  if status<>NX_OK then statusOut:=NX_ERROR
  else begin
            status:=NXgetdata(file_id, data);
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data 1D Array of FLOAT32                                                 }
function NXUreadData(file_id:integer;data_name:string;var data:TDynArrayFloat32;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=high(data)+1;
  status := NXUconfirmdata(file_id,data_name,NX_FLOAT32,1,dims);
  status := NXOpenData(file_id,StrToPChar(data_name));
  if status<>NX_OK then statusOut:=NX_ERROR
  else begin
            status:=NXgetdata(file_id, data);
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data 1D Array of FLOAT64                                                 }
function NXUreadData(file_id:integer;data_name:string;var data:TDynArrayFloat64;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=high(data)+1;
  status := NXUconfirmdata(file_id,data_name,NX_FLOAT64,1,dims);
  status := NXOpenData(file_id,StrToPChar(data_name));
  if status<>NX_OK then statusOut:=NX_ERROR
  else begin
       status:=NXgetdata(file_id, data);
       status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
       units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data 2D Array of INT32                                                   }
function NXUreadData(file_id:integer;data_name:string;var data:TDynArray2DInt32;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=high(data)+1;dims[2]:=high(data[0])+1;
  status := NXUconfirmdata(file_id,data_name,NX_INT32,2,dims);
  status := NXOpenData(file_id,StrToPChar(data_name));
  if status<>NX_OK then statusOut:=NX_ERROR
  else begin
            status:=NXgetdata(file_id, data);
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data 2D Array of FLOAT32                                                 }
function NXUreadData(file_id:integer;data_name:string;var data:TDynArray2DFloat32;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=high(data)+1;dims[2]:=high(data[0])+1;
  status := NXUconfirmdata(file_id,data_name,NX_FLOAT32,2,dims);
  status := NXOpenData(file_id,StrToPChar(data_name));
  if status<>NX_OK then statusOut:=NX_ERROR
  else begin
            status:=NXgetdata(file_id, data);
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;
{ ============================================================================= }
{ read data 2D Array of FLOAT64                                                 }
function NXUreadData(file_id:integer;data_name:string;var data:TDynArray2DFloat64;var units:string):integer;
var statusOut,status:integer;
    dims:dimensions;
    unitsAux:TCharacter255;
begin
  dims[1]:=high(data)+1;dims[2]:=high(data[0])+1;
  status := NXUconfirmdata(file_id,data_name,NX_FLOAT64,2,dims);
  status := NXOpenData(file_id,StrToPChar(data_name));
  if status<>NX_OK then statusOut:=NX_ERROR
  else begin
            status:=NXgetdata(file_id, data);
            status:=NXgetattr(file_id, StrToPChar('units'), unitsAux);
            units:=unitsAux;statusOut:=NX_OK end;
  NXUreadData:=statusOut;
end;

{ ============================================================================= }
{ too fancy yet to be implemented }
function NXUwriteHistogram(file_id:integer;data_name:string;data:string;units:string):integer;
begin
end;
function NXUreadHistogram(file_id:integer;data_name:string;var data:string;var units:string):integer;
begin
end;
{ ============================================================================= }
function NXUsetcompress(file_id:integer;compress_type,compress_size:integer):integer;
var status:integer;
begin
   if (compress_type = NX_COMP_LZW) or (compress_type = NX_COMP_HUF) or
      (compress_type = NX_COMP_RLE) or (compress_type = NX_COMP_NONE)
   then begin NXcompress_type := compress_type;NXcompress_size := compress_size;status := NX_OK end
   else begin status := NX_ERROR;MessageDlg('Invalid compression option', mtInformation,[mbOk], 0, mbOk) end;
   NXUsetCompress:=status
end;


{ ============================================================================= }
{ NXUfindgroup finds if a NeXus group of the specified name exists }
function NXUfindgroup(file_id:integer;group_name:string;var group_class:string):integer;
var statusOut,status:integer;
    item_number,group_typeAux:integer;
    group_nameAux,group_classAux:TCharacter255;
    found:boolean; // flag telling if the data have been found
begin
   statusOut:=NX_OK;
   status := NXgetgroupinfo(file_id, item_number, group_nameAux, group_classAux);
   if status<>NX_OK
   then begin statusOut:=NX_ERROR;MessageDlg('No group opened', mtInformation,[mbOk], 0, mbOk) end
   else begin
        status:=NXinitGroupDir(file_id);
        status:=NX_OK;found:=false;
        while (status<>NX_EOD) and (not found) do
        begin
          status:=NXGetNextEntry(file_id,group_nameAux,group_classAux,group_typeAux);
          if group_nameAux=group_name
          then if (group_classAux[0]='N') and (group_classAux[1]='X')
               then begin found:=true;statusOUT:=NX_OK;group_class:=group_classAux end { the data have been found with the correct type }
               else begin statusOUT:=NX_ERROR;MessageDlg('Not a NeXuS Group item', mtInformation,[mbOk], 0, mbOk) end;
        end;
        end;
   if found then NXUfindGroup:=statusOUT else NXUfindGroup:=NX_ERROR;
end;

{ NXUfindclass finds if a NeXus group of the specified class exists             }
function NXUfindClass(file_id:integer;group_class:string;var group_name:string;find_index:integer):integer;
var statusOut,status:integer;
    fidx,item_number,group_typeAux:integer;
    group_nameAux,group_classAux:TCharacter255;
    found:boolean; // flag telling if the data have been found
begin
   { check if a group is opened }
   status := NXgetgroupinfo(file_id, item_number, group_nameAux, group_classAux);
   if status<>NX_OK
   then begin statusOut:=NX_ERROR;MessageDlg('No group opened', mtInformation,[mbOk], 0, mbOk) end
   else begin
        status:=NXinitGroupDir(file_id);
        status:=NX_OK;found:=false;fidx:=1;
        while (status<>NX_EOD) and (not found) do
        begin
           status:=NXGetNextEntry(file_id,group_nameAux,group_classAux,group_typeAux);
           if group_classAux=group_class
           then if fidx=find_index
                then begin group_name:=group_nameAux;found:=true;statusOut:=NX_OK end { the class have been found with the correct type }
                else inc(fidx); { we have to look for the next item }
        end;
        end;
   if found then NXUfindClass:=statusOut else NXUfindClass:=NX_ERROR;
end;

{ NXUfinddata finds if a NeXus data item is in the current group }
function NXUfindData(file_id:integer;data_name:string):integer;
var statusOut,status:integer;
    item_number,data_typeAux:integer;
    group_name,group_class,data_nameAux,data_classAux:TCharacter255;
    found:boolean; // flag telling if the data have been found
begin
   status := NXgetgroupinfo(file_id, item_number, group_name, group_class);
   if status<>NX_OK
   then begin statusOut:=NX_ERROR;MessageDlg('No group opened', mtInformation,[mbOk], 0, mbOk) end
   else begin
        status:=NXinitGroupDir(file_id);
        status:=NX_OK;found:=false;
        while (status<>NX_EOD) and (not found) do
        begin
          status:=NXGetNextEntry(file_id,data_nameAux,data_classAux,data_typeAux);
          if data_nameAux=data_name
          then if data_classAux='SDS'
               then begin found:=true;statusOut:=NX_OK end { the data have been found with the correct type }
               else begin statusOut:=NX_ERROR;MessageDlg('Not a data item', mtInformation,[mbOk], 0, mbOk) end;
        end;
        end;
   if found then NXUfindData:=NX_OK
   else if status=NX_EOD then NXUfindData:=status else NXUfindData:=statusOut; 
end;

{ NXUfindattr finds if a NeXus attribute exists }
function NXUfindAttr(file_id:integer;attr_name:string):integer;
var statusOut,status:integer;
    item_number,data_lengthAux,data_typeAux:integer;
    group_name,group_class,attr_nameAux,data_classAux:TCharacter255;
    found:boolean; // flag telling if the data have been found
begin
   status := NXgetgroupinfo(file_id, item_number, group_name, group_class);
   if status<>NX_OK
   then begin statusOut:=NX_ERROR;MessageDlg('No group opened', mtInformation,[mbOk], 0, mbOk) end
   else begin
        status:=NX_OK;found:=false;
        status:=NXinitAttrDir(file_id);
        while (status<>NX_EOD) and (not found) do
        begin
          status:=NXgetNextAttr(file_id,attr_nameAux,data_lengthAux,data_typeAux);
          if attr_nameAux=attr_name
          then begin found:=true;statusOut:=NX_OK end { the attr. have been found }
        end;
        end;
   if found then NXUfindAttr:=NX_OK else NXUfindAttr:=NX_EOD;
end;

{ NXUfindsignal finds the NeXus data item containing the required signal }
{ INPUT : signal required value of signal attribute                     }
function NXUfindSignal(file_id:integer;signal:integer;var data_name:string;var data_rank,data_type:integer;var data_dimensions:dimensions):integer;
var statusOut,status,statusDir,NXtype,attr_value:integer;
    attr_name,data_nameAux,data_classAux:TCharacter255;
    found:boolean;
begin
   found:=false;
   status := NXinitgroupdir(file_id);
   attr_name:=StrToPChar('signal');
   if status<>NX_OK
   then begin statusOut:=NX_ERROR;{MessageDlg('No group opened', mtInformation,[mbOk], 0, mbOk);} end
   else begin
        statusDir:=NX_OK;found:=false;
        while (statusDir<>NX_EOD) and (not found) do
        begin
           statusDir:=NXgetnextentry(file_id, data_nameAux, data_classAux, NXtype);
           if (statusDir=NX_OK) and (data_classAux='SDS')
           then begin
                status:=NXopenData(file_id,data_nameAux);
                if (status<>NX_OK)
                then {MessageDlg('Could not open data', mtInformation,[mbOk], 0, mbOk) }
                else begin
                     status:=NXUfindAttr(file_id,'signal');
                     if (status<>NX_OK)
                     then { MessageDlg('Could not get attribute', mtInformation,[mbOk], 0, mbOk) }
                     else begin
                          status:=NXgetAttr(file_id,attr_name,attr_value);
                          if (attr_value=signal)
                          then begin status:=NXgetInfo(file_id,data_rank,data_dimensions,data_type);
                                     data_name:=data_nameAux;found:=true;statusOut:=NX_OK end
                          end;
                     end;
                end
        end;
        end;
   if found=false
   then begin NXUfindSignal:=NX_ERROR;{ MessageDlg('No data with attribute '+IntToStr(signal)+' found', mtInformation,[mbOk], 0, mbOk) } end
   else NXUfindSignal:=statusOUT;
end;

{ NXUfindaxis finds the NeXus data item containing the required axis    }
function NXUfindAxis(file_id:integer;axis,primary:integer;var data_name:string;var data_rank,data_type,data_dimensions:integer):integer;
var status,statusDir,NXtype,attr_value:integer;
    attr_name,data_nameAux,data_classAux:TCharacter255;
    found:boolean;
    NXdims:dimensions;
begin
   status := NXinitgroupdir(file_id);
   attr_name:=StrToPChar('axis');
   if status<>NX_OK
   then begin {MessageDlg('No group opened', mtInformation,[mbOk], 0, mbOk);} end
   else begin
        statusDir:=NX_OK;found:=false;
        while (statusDir<>NX_EOD) and (not found) do
        begin
           statusDir:=NXgetnextentry(file_id, data_nameAux, data_classAux, NXtype);
           if (statusDir=NX_OK) and (data_classAux='SDS')
           then begin
                status:=NXopenData(file_id,data_nameAux);
                if (status<>NX_OK)
                then { MessageDlg('Could not open data', mtInformation,[mbOk], 0, mbOk) }
                else begin
                     status:=NXUfindAttr(file_id,'axis');
                     if (status=NX_OK)
                     then begin
                          status:=NXgetAttr(file_id,StrToPChar('axis'),attr_value);
                          if (status<>NX_OK) or (attr_value<>axis)
                          then { MessageDlg('Could not get value', mtInformation,[mbOk], 0, mbOk) }
                          else begin
                               status:=NXUfindAttr(file_id,'primary');
                               if (status = NX_OK)
                               then begin
                                    status:=NXgetAttr(file_id,StrToPChar('primary'),attr_value);
                                    if (status<>NX_OK) or (attr_value<>primary)
                                    then { MessageDlg('Could not get value', mtInformation,[mbOk], 0, mbOk) }
                                    else begin
                                         status:=NXgetInfo(file_id,data_rank,NXdims,data_type);
                                         data_name:=data_nameAux;found:=true;data_dimensions:=NXdims[1] end;
                                    end;
                               end;
                          end;
                     end;
                end
        end;
        end;
   if found=false
   then begin NXUfindAxis:=NX_ERROR;{ MessageDlg('No such axis', mtInformation,[mbOk], 0, mbOk) } end
   else NXUfindAxis:=NX_OK;
end;

function NXUfindLink(file_id:integer;group_class:string;var group_id:NXlink):integer;
begin
end;

function NXUresumeLink(file_id:integer;group_id:NXlink):integer;
begin
end;

end.
