function [data, return_status] = nc_getall ( ncfile )
% NC_GETALL:  read the entire contents of a netcdf file into a nested structure
%
% This routine was a good idea, but is really kind of flawed.  What 
% can be a valid NetCDF variable name is not necessarily a valid
% matlab structure field name.  Getting around this is fairly 
% clumsy.  
%
% USAGE:  [structure, status] = nc_getall ( ncfile );
%
% PARAMETERS:
% Input:
%     ncfile:  
%        Input netcdf file name.
% Output:
%     structure:
%        Structure with all netcdf data present.  Each variable will
%        be a substructure.  Within each variable lies the data and 
%        each attribute.  The global attributes are stored in a 
%        sub-structure called 'global_atts'
% return_status:
%        -1 if the routine fails, 0 if successful
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% $Name:  $
% $Id: nc_getall.m,v 1.1 2005/06/29 16:07:00 brian Exp $
% AUTHOR:  johnevans@acm.org
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%







%
% assume failure until success is known
return_status = -1;
data = [];


% Show usage if too few arguments.
%
if nargin~=1 
   help nc_getall;
   return;
end


%
% Open netCDF file
%
[cdfid,rcode ]=mexnc('open',ncfile,'NOWRITE');
if cdfid < 0
	fprintf ( 2, '%s:  mexnc:open failed on %s.\n', mfilename, ncfile );
	return
end

% Suppress warning messages from netCDF
[rcode]=mexnc('setopts',0);


[ndims, nvars, ngatts, recdim, status] = mexnc('INQUIRE', cdfid);
if status < 0
	fprintf ( 2, '%s:  mexnc:inquire failed on %s.\n', mfilename, ncfile );
	mexnc('close',cdfid);
    return
end

for varid=0:nvars-1

	varstruct = [];

	[varname, datatype, ndims, dims, natts, status] = mexnc('VARINQ', cdfid, varid);
	if status < 0 
		fprintf ( 2, '%s:  mexnc:varinq failed on varid %d, file %s.\n', mfilename, varid, ncfile );
		mexnc('close',cdfid);
	end


	%
	% If ndims is zero, then it must be a singleton variable.  Don't bother trying
	% to retrieve the data, there is none.
	if ( ndims == 0 )
		varstruct.data = [];
	else
		[values, status] = nc_varget(ncfile, varname);
		if status < 0 
			fprintf ( 2, '%s:  nc_varget failed on %s, file %s.\n', mfilename, varname, ncfile );
			mexnc('close',cdfid);
		end

		varstruct = setfield ( varstruct, 'data', values );
	end



	%
	% get all the attributes
	for attnum = 0:natts-1

		[attname, status] = mexnc('ATTNAME', cdfid, varid, attnum);
		if status < 0 
			fprintf ( 2, '%s:  mexnc:attname failed on %s, file %s.\n', mfilename, varname, ncfile );
			mexnc('close',cdfid);
		end

		[attval, status] = nc_attget(ncfile, varname, attname);
		if status < 0 
			fprintf ( 2, '%s:  nc_attget failed on %s, %s, file %s.\n', mfilename, attname, varname, ncfile );
			mexnc('close',cdfid);
		end
		
		%
		% Matlab structures don't like the leading '_'
		if strcmp(attname,'_FillValue' )
			attname = 'FillValue';
		end


		sanitized_attname = matlab_sanitize_attname ( attname );


		%
		% this puts the attribute into the variable structure
		varstruct = setfield ( varstruct, sanitized_attname, attval );


	end


	%
	% Add this variable to the entire file structure
	data = setfield ( data, varname, varstruct );

end


%
% Do the same for the global attributes
%
% get all the attributes
varname = 'global';
global_atts = [];
for attnum = 0:ngatts-1

	[attname, status] = mexnc('ATTNAME', cdfid, varname, attnum);
	if status < 0 
		fprintf ( 2, '%s:  mexnc:attname failed on %s, file %s.\n', mfilename, varname, ncfile );
		mexnc('close',cdfid);
	end

	[attval, status] = nc_attget(ncfile, varname, attname);
	if status < 0 
		fprintf ( 2, '%s:  nc_attget failed on %s, %s, file %s.\n', mfilename, attname, varname, ncfile );
		mexnc('close',cdfid);
	end
	
	sanitized_attname = matlab_sanitize_attname ( attname );


	%
	% this puts the attribute into the variable structure
	global_atts = setfield ( global_atts, sanitized_attname, attval );



end

if ~isempty ( global_atts )
	data = setfield ( data, 'global_atts', global_atts );
end

mexnc('close',cdfid);

if isempty(data)
	data = struct([]);
end

return_status = 1;

return



function sanitized_attname = matlab_sanitize_attname ( attname )
	%
	% could the attribute name  be interpreted as a number?
	% If so, must fix this.
	% An attribute name of, say, '0' is not permissible in matlab
	if ~isnan(str2double(attname))
		sanitized_attname = ['x_' attname];
	else

		sanitized_attname = attname;

		%
		% Does the attribute have non-letters in the leading 
		% position?  Convert these to underscores.  
		if ( ~isletter(attname(1)) );
			sanitized_attname(1) = '_';
		end
	end
return
