function nc_addvar ( ncfile, varstruct )
% NC_ADDVAR:  adds a variable to a NetCDF file
%
% USAGE:  nc_addvar ( ncfile, varstruct );
%
% PARAMETERS:
% Input
%    ncfile:
%    varstruct:
%        This is a structure with four fields:
%
%        Name
%        Nctype
%        Dimension
%        Attribute
%
%      "Name" is just that, the name of the variable to be defined.
%
%      "Nctype" should be 
%          'double', 'float', 'int', 'short', or 'byte', or 'char'
%          'NC_DOUBLE', 'NC_FLOAT', 'NC_INT', 'NC_SHORT', 'NC_BYTE', 'NC_CHAR'
%
%      "Dimension" is a cell array of dimension names.
%
%      "Attribute" is also a structure array.  Each element has two
%      fields, "Name", and "Value".
%
% Output: 
%     None.  In case of an error, an exception is thrown.
%
% AUTHOR:
%    johnevans@acm.org
%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% $Id: nc_addvar.m 1870 2006-10-09 12:08:53Z johnevans007 $
% $LastChangedDate: 2006-10-09 08:08:53 -0400 (Mon, 09 Oct 2006) $
% $LastChangedRevision: 1870 $
% $LastChangedBy: johnevans007 $
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin < 2
	error ( '%s:  must have two input arguments.\n', mfilename );
end


if  ~ischar(ncfile) 
	error ( '%s:  1st input argument must be char.\n', mfilename );
end

if ( ~isstruct(varstruct) )
	error ( '%s:  2nd input argument must be a structure.\n', mfilename );
end

%
% Check that required fields are there.
% Must at least have a name.
if ~isfield ( varstruct, 'Name' )
	error ( '%s:  variable structure must at least have ''Name'' field.\n', mfilename );
end

%
% Check that required fields are there.
% Default Nctype is double.
if ~isfield ( varstruct, 'Nctype' )
	varstruct.Nctype = 'double';
end

%
% Are there any unrecognized fields?
fnames = fieldnames ( varstruct );
for j = 1:length(fnames)
	fname = fnames{j};
	switch ( fname )

	case { 'Nctype', 'Name', 'Dimension', 'Attribute' }
		%
		% These are used to create the variable.  They are ok.
		
	case { 'IsUnlimitedVariable', 'Size', 'Rank' }
		%
		% These come from the output of nc_getvarinfo.  We don't 
		% use them, but let's not give the user a warning about
		% them either.

	otherwise
		fprintf ( 2, '%s:  unrecognized field name ''%s''.  Ignoring it...\n', mfilename, fname );
	end
end


% If the datatype is not a string.
% Change suggested by Brian Powell
if ( isa(varstruct.Nctype, 'double') & varstruct.Nctype < 7 )
	types={ 'byte' 'char' 'short' 'int' 'float' 'double'};
	varstruct.Nctype = char(types(varstruct.Nctype));
end


%
% Check that the datatype is known.
switch ( varstruct.Nctype )
case { 'NC_DOUBLE', 'double', ...
	'NC_FLOAT', 'float', ...
	'NC_INT', 'int', ...
	'NC_SHORT', 'short', ...
	'NC_BYTE', 'byte', ...
	'NC_CHAR', 'char'  }
	%
	% Do nothing
otherwise
	error ( '%s:  unknown Nctype ''%s''\n', mfilename, varstruct.Nctype );
end

%
% Check that required fields are there.
% Default Dimension is none.  Singleton scalar.
if ~isfield ( varstruct, 'Dimension' )
	varstruct.Dimension = [];
end

%
% Check that required fields are there.
% Default Attributes are none
if ~isfield ( varstruct, 'Attribute' )
	varstruct.Attribute = [];
end

[ncid, status] = mexnc ( 'open', ncfile, nc_write_mode );
if ( status < 0 )
	ncerr = mexnc ( 'strerror', status );
	fmt = '%s:  mexnc:open failed on ''%s'', error message ''%s''.\n';
	error ( fmt, mfilename, ncfile, ncerr );
end

%
% determine the dimids of the named dimensions
num_dims = length(varstruct.Dimension);
dimids = [];
for j = 1:num_dims
	[dimids(j), status] = mexnc ( 'dimid', ncid, varstruct.Dimension{j} );
	if ( status < 0 )
		ncerr = mexnc ( 'strerror', status );
		mexnc ( 'close', ncid );
		strformat = '%s:  mexnc:dimid failed to return a dimid for %s, file %s, error ''%s''.\n';
		error ( strformat, mfilename, varstruct.Dimension{j}, ncfile, ncerr );
	end
end


%
% go into define mode
status = mexnc ( 'redef', ncid );
if ( status < 0 )
	ncerr = mexnc ( 'strerror', status );
	mexnc ( 'close', ncid );
	error ( '%s:  mexnc:redef failed on %s, ''%s''.\n', mfilename, ncfile, ncerr );
end

[varid, status] = mexnc ( 'def_var', ncid, varstruct.Name, varstruct.Nctype, num_dims, dimids );
if ( status ~= 0 )
	ncerr = mexnc ( 'strerror', status );
	mexnc ( 'endef', ncid );
	mexnc ( 'close', ncid );
	error ( '%s:  mexnc:def_var failed on %s, ''%s''.\n', mfilename, ncfile, ncerr );
end



status = mexnc ( 'endef', ncid );
if ( status < 0 )
	mexnc ( 'close', ncid );
	error ('%s:  mexnc:endef failed on %s.\n', mfilename, ncfile );
end

status = mexnc ( 'close', ncid );
if ( status < 0 )
	error ( '%s:  mexnc:close failed on %s.\n', mfilename, ncfile );
end



%
% Now just use nc_attput to put in the attributes
for j = 1:length(varstruct.Attribute)
	attname = varstruct.Attribute(j).Name;
	attval = varstruct.Attribute(j).Value;
	nc_attput ( ncfile, varstruct.Name, attname, attval );
end


return



