function data = 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'
% 
% In case of an error, an exception is thrown.
%
%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% $Id: nc_getall.m 1740 2006-08-29 16:15:23Z johnevans007 $
% $LastChangedDate: 2006-08-29 12:15:23 -0400 (Tue, 29 Aug 2006) $
% $LastChangedRevision: 1740 $
% $LastChangedBy: johnevans007 $
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


data = [];


% Show usage if too few arguments.
%
if nargin~=1 
	error ( '%s:  must have one input argument.\n', mfilename );
end


%
% Open netCDF file
%
[cdfid,status ]=mexnc('open',ncfile,'NOWRITE');
if status ~= 0
	error ( '%s:  mexnc:open failed on %s.\n', mfilename, ncfile );
end



[nvars, status] = mexnc('INQ_NVARS', cdfid);
if status < 0
	mexnc('close',cdfid);
	error ( '%s:  mexnc:inq_nvars failed on %s.\n', mfilename, ncfile );
end
[ngatts, status] = mexnc('INQ_NATTS', cdfid);
if status < 0
	mexnc('close',cdfid);
	error ( '%s:  mexnc:inq_natts failed on %s.\n', mfilename, ncfile );
end

for varid=0:nvars-1

	varstruct = [];

	[varname, datatype, ndims, dims, natts, status] = mexnc('INQ_VAR', cdfid, varid);
	if status < 0 
		mexnc('close',cdfid);
		error ( '%s:  mexnc:inq_var failed on varid %d, file %s.\n', mfilename, varid, ncfile );
	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 = nc_varget(ncfile, varname);
		varstruct.data = values;
	end



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

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

		try
			attval = nc_attget(ncfile, varname, attname);
		catch
			mexnc('close',cdfid);
			error ( '%s:  nc_attget failed, ''%s''.\n', mfilename, lasterr );
		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.(sanitized_attname) = attval;


	end


	%
	% Add this variable to the entire file structure
	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('inq_attname', cdfid, nc_global, attnum);
	if status < 0 
		mexnc('close',cdfid);
		fmt = '%s:  mexnc:inq_attname failed on %s, file %s.\n';
		error ( fmt, mfilename, varname, ncfile );
	end

	try
		attval = nc_attget(ncfile, nc_global, attname);
	catch
		mexnc('close',cdfid);
		error ( '%s:  nc_attget failed, ''%s''.\n', mfilename, lasterr );
	end
	
	sanitized_attname = matlab_sanitize_attname ( attname );


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



end

if ~isempty ( global_atts )
	data.global_atts = global_atts;
end

mexnc('close',cdfid);

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

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


