function WriteData(fid,varargin)
%WRITEDATA - write model field in binary file
%
%   Usage:
%      WriteData(fid,varargin);

%process options
options=pairoptions(varargin{:});

%Get data properties
if exist(options,'object');
	%This is a object field, construct enum and data
	obj       = getfieldvalue(options,'object');
	fieldname = getfieldvalue(options,'fieldname');
	classname = getfieldvalue(options,'class',class(obj));

	enum      = BuildEnum([classname '_' fieldname]);
	data      = obj.(fieldname);
else
	%No processing required
	data = getfieldvalue(options,'data');
	enum = getfieldvalue(options,'enum');
end
format  = getfieldvalue(options,'format');
mattype = getfieldvalue(options,'mattype',0);    %only required for matrices
forcinglength = getfieldvalue(options,'forcinglength',-1);

%Process sparse matrices
if issparse(data),
	data=full(data);
end

%Scale data if necesarry
if exist(options,'scale'),
	scale = getfieldvalue(options,'scale');
	if size(data,1)==forcinglength,
		data(1:end-1,:) = scale.*data(1:end-1,:);
	else
		data  = scale.*data;
	end
end
if(size(data,1)==forcinglength),
	yts=365.0*24.0*3600.0;
	data(end,:) = data(end,:)*yts;
end

%Step 1: write the enum to identify this record uniquely
fwrite(fid,enum,'int'); 

%Step 2: write the data itself.
if     strcmpi(format,'Boolean'),% {{{
	if(numel(data)~=1), error(['field ' EnumToString(enum) ' cannot be marshalled as it has more than one element!']); end

	%first write length of record
	fwrite(fid,4+4,'int');  %1 bool (disguised as an int)+code

	%write data code: 
	fwrite(fid,FormatToCode(format),'int'); 

	%now write integer
	fwrite(fid,data,'int');  %send an int, not easy to send a bool
	% }}}
elseif strcmpi(format,'Integer'), % {{{
	if(numel(data)~=1), error(['field ' EnumToString(enum) ' cannot be marshalled as it has more than one element!']); end

	%first write length of record
	fwrite(fid,4+4,'int');  %1 integer + code

	%write data code: 
	fwrite(fid,FormatToCode(format),'int'); 

	%now write integer
	fwrite(fid,data,'int'); 
	% }}}
elseif strcmpi(format,'Double'), % {{{
	if(numel(data)~=1), error(['field ' EnumToString(enum) ' cannot be marshalled as it has more than one element!']); end

	%first write length of record
	fwrite(fid,8+4,'int');  %1 double+code

	%write data code: 
	fwrite(fid,FormatToCode(format),'int'); 

	%now write double
	fwrite(fid,data,'double'); 
	% }}}
elseif strcmpi(format,'String'), % {{{
	%first write length of record
	fwrite(fid,length(data)+4+4,'int');  %string + string size + code

	%write data code: 
	fwrite(fid,FormatToCode(format),'int'); 

	%now write string
	fwrite(fid,length(data),'int'); 
	fwrite(fid,data,'char'); 
	% }}}
elseif strcmpi(format,'BooleanMat'), % {{{

	%Get size
	s=size(data);
	%if matrix = NaN, then do not write anything
	if (s(1)==1 & s(2)==1 & isnan(data)),
		s(1)=0; s(2)=0;
	end

	%first write length of record
	fwrite(fid,4+4+8*s(1)*s(2)+4+4,'int');  %2 integers (32 bits) + the double matrix + code + matrix type

	%write data code and matrix type: 
	fwrite(fid,FormatToCode(format),'int'); 
	fwrite(fid,mattype,'int');

	%now write matrix
	fwrite(fid,s(1),'int'); 
	fwrite(fid,s(2),'int'); 
	if s(1)*s(2),
		fwrite(fid,data','double'); %get to the "c" convention, hence the transpose
	end
	% }}}
elseif strcmpi(format,'IntMat'), % {{{

	%Get size
	s=size(data);
	%if matrix = NaN, then do not write anything
	if (s(1)==1 & s(2)==1 & isnan(data)),
		s(1)=0; s(2)=0;
	end

	%first write length of record
	fwrite(fid,4+4+8*s(1)*s(2)+4+4,'int');  %2 integers (32 bits) + the double matrix + code + matrix type

	%write data code and matrix type: 
	fwrite(fid,FormatToCode(format),'int'); 
	fwrite(fid,mattype,'int');

	%now write matrix
	fwrite(fid,s(1),'int'); 
	fwrite(fid,s(2),'int'); 
	if s(1)*s(2),
		fwrite(fid,data','double'); %get to the "c" convention, hence the transpose
	end
	% }}}
elseif strcmpi(format,'DoubleMat'), % {{{

	%Get size
	s=size(data);
	%if matrix = NaN, then do not write anything
	if (s(1)==1 & s(2)==1 & isnan(data)),
		s(1)=0; s(2)=0;
	end

	%first write length of record
	recordlength=4+4+8*s(1)*s(2)+4+4; %2 integers (32 bits) + the double matrix + code + matrix type
	if recordlength>2^31; error(['field ' EnumToString(enum) ' cannot be marshalled because it is larger than 2^31 bytes!']); end
	fwrite(fid,recordlength,'int');

	%write data code and matrix type: 
	fwrite(fid,FormatToCode(format),'int'); 
	fwrite(fid,mattype,'int');

	%now write matrix
	fwrite(fid,s(1),'int'); 
	fwrite(fid,s(2),'int'); 
	if s(1)*s(2),
		fwrite(fid,data','double'); %get to the "c" convention, hence the transpose
	end
	% }}}
elseif strcmpi(format,'MatArray'), % {{{

	numrecords=numel(data);

	%first get length of record
	recordlength=4+4; %number of records + code
	for i=1:numrecords,
		matrix=data{i};
		s=size(matrix);
		recordlength=recordlength+4*2+... %row and col of matrix
			s(1)*s(2)*8; %matrix of doubles
	end

	%write length of record
	fwrite(fid,recordlength,'int'); 

	%write data code: 
	fwrite(fid,FormatToCode(format),'int'); 

	%write data, first number of records
	fwrite(fid,numrecords,'int'); 

	%write each matrix: 
	for i=1:numrecords,
		matrix=data{i};
		s=size(matrix);
		fwrite(fid,s(1),'int'); 
		fwrite(fid,s(2),'int'); 
		fwrite(fid,matrix','double');
	end
	% }}}
elseif strcmpi(format,'StringArray'), % {{{

	%first get length of string array: 
	num=numel(data);
	if isnumeric(data) & num==1 & isnan(data),
		num = 0;
	end

	%now get length of record: 
	recordlength=4+4; %for length of array + code
	for i=1:num,
		string=data{i};
		recordlength=recordlength+4+length(string); %for each string
	end

	%write length of record
	fwrite(fid,recordlength,'int'); 

	%write data code: 
	fwrite(fid,FormatToCode(format),'int'); 

	%now write length of string array
	fwrite(fid,num,'int'); 

	%now write the strings
	for i=1:num,
		string=data{i};
		fwrite(fid,length(string),'int'); 
		fwrite(fid,string,'char'); 
	end
	% }}}
else  % {{{
	error(['WriteData error message: data type: ' num2str(format) ' not supported yet! (' EnumToString(enum) ')']);
end % }}}
end

function enum=BuildEnum(string) % {{{
%BUILDENUM - build enum out of string
%
%   Usage:
%      enum=BuildEnum(string)

	if findstr(string,'_'),
		indices=findstr(string,'_');
		for i=1:length(indices),
			string(indices(i)+1)=upper(string(indices(i)+1));
		end
		string(indices)=[];
	end

	%take first letter of string and make it uppercase: 
	string(1)=upper(string(1));

	%Get Enum
	enum=StringToEnum(string); 
end % }}}
function code=FormatToCode(format) % {{{
%This routine takes the format string, and hardcodes it into an integer, which 
%is passed along the record, in order to identify the nature of the dataset being 
%sent.
	if     strcmpi(format,'Boolean'),
		code=1;
	elseif strcmpi(format,'Integer'), 
		code=2;
	elseif strcmpi(format,'Double'), 
		code=3;
	elseif strcmpi(format,'String'), 
		code=4;
	elseif strcmpi(format,'BooleanMat'),
		code=5;
	elseif strcmpi(format,'IntMat'),
		code=6;
	elseif strcmpi(format,'DoubleMat'),
		code=7;
	elseif strcmpi(format,'MatArray'), 
		code=8;
	elseif strcmpi(format,'StringArray'),
		code=9;
	else 
		error('FormatToCode error message: data type not supported yet!');
	end
end% }}}
