function create_matdatafile_creator( matdatafilename, outputfilename )

% function create_matdatafile_creator( matdatafilename, outputfilename )
%
% Create a MATLAB creator function (".m" ASCII file: outputfilename)
% that permits to re-create the MATLAB object(s) input (matdatafilename).
%
% -> useful to prevent future/past MATLAB compatibility issues:
%    store a ".m" creator file along with each ".mat" binary file.
%
% For unsupported types of fields, a line containing "()" is outputted,
% so that the new MATLAB function will crash for sure.
% -> you just have to finish the job, editing those "()" by hand.
%
% By Guillaume Lathoud, 2006 - lathoud@idiap.ch
  
  if nargin < 2
    error( [ mfilename ' needs 2 input arguments.' ] );
  end
  
  % Check input and output files

  if ~exist( matdatafilename, 'file' )
    error( [ mfilename ' could not find input file "' matdatafilename '".' ] );
  end

  if exist( outputfilename, 'file' )
    error( [ mfilename ': output file already exists ("' outputfilename '").' ] );
  end

  fid_out = fopen( outputfilename, 'wt' );
  if fid_out < 0
    error( [ mfilename ' could not create output file "' outputfilename '".' ] );
  end
  
  % Load input file (MATLAB binary format, contains one or multiple object)

  original = load( matdatafilename );

  % Write out a little header

  fprintf( fid_out, [ '%% MATLAB code to re-create the object(s) stored in "' matdatafilename '".\n' ] );
  fprintf( fid_out, [ '%%\n' ] );
  fprintf( fid_out, [ '%% -> use this if your MATLAB version cannot read "' matdatafilename '".\n' ] );
  fprintf( fid_out, [ '%%\n' ] );
  fprintf( fid_out, [ '%% Created by "' mfilename '", itself created by Guillaume Lathoud, 2006 - lathoud@idiap.ch\n\n' ] );

  % Dump MATLAB code to create the numeric fields.
  % For non-numeric fields, dump a bugged code that the user will have to replace.

  dump_creation_code( original, fid_out, '' );
  
  % Finish writing out ".m" file

  fclose( fid_out );
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function for recursive call

function dump_creation_code( original, fid_out, header_str )

  if nargin < 3
    error( [ mfilename '.dump_creation_code() needs 3 input arguments.' ] );
  end

  if ~isstruct( original )
    error( [ mfilename '.dump_creation_code() needs a structure for the "original" argument.' ] );
  end

  % Precision to store floating point numbers
  prec = ceil( abs( log10( eps ) ) );
  format_str = sprintf( '%%.%de', prec-1 );  % to format the outputs
  formatint_str = '%d';
  
  n = numel( original );
  namelist = fieldnames( original );

  for a = 1:n

    basename = sprintf( 'original( %d )', a );

    for b = 1:numel( namelist )
      
      fullname = [ basename  '.' namelist{ b } ];

      new_header = header_str;
      if ~isempty( new_header )
	new_header = [ new_header sprintf( '( %d )', a ) '.' ];
      end
      new_header = [ new_header namelist{ b } ];
      
      % What is the type of this field

      if eval( sprintf( [ 'isnumeric( ' fullname ' )' ] ) )

	% Numeric
	s_out = [ new_header ' = reshape( [ ' ];

	if eval( [ 'isreal( ' fullname ' )' ] )
	  % Array of real numbers
	  s_out = [ s_out sprintf( [ format_str ' ;\n' ], eval( [ fullname '(:)' ] ) ) ];

	else
	  % Array of complex numbers
	  s_out = [ s_out sprintf( [ format_str ' + i * ' format_str ';\n' ], eval( [ '[ real( ' fullname '(:) ), imag( ' fullname '(:) ) ].''' ] ) ) ];
	end		   

	s_out = [ s_out( 1:end-1 ) ' ], [' sprintf( ' %d', eval( [ 'size( ' fullname ' )' ] ) ) ' ] );\n\n' ];
	
	fprintf( fid_out, s_out );
	  
      elseif eval( [ 'islogical( ' fullname ' )' ] )

	% Logical
	s_out = [ new_header ' = reshape( logical( [ ' ];

	s_out = [ s_out sprintf( [ '%d ; \n' ], eval( [ fullname '(:)' ] ) ) ];

	s_out = [ s_out( 1:end-1 ) ' ] ), [' sprintf( ' %d', eval( [ 'size( ' fullname ' )' ] ) ) ' ] );\n\n' ];

        fprintf( fid_out, s_out );

      elseif eval( [ 'ischar( ' fullname ' )' ] )
	  
	% String
	s_out =  [ new_header ' = ''' eval( fullname ) ''';\n' ];

	fprintf( fid_out, s_out );

      elseif eval( [ 'isstruct( ' fullname ' )' ] )
	
	% Structure -> recursive call to myself
	dump_creation_code( eval( fullname ), fid_out, new_header );
	
      elseif eval( [ 'iscell( ' fullname ' )' ] )

	% Cell array -> dump it only if it is an array of strings
	all_strings = 1;
	for zz = 1:eval( [ 'numel( ' fullname ' )' ] )
	  if eval( [ '~ischar( ' fullname '{ ' sprintf( '%d', zz ) ' } )' ] )
	    all_strings = 0;
	    break;
	  end
	end
	
	if all_strings

	  s_out = [ new_header ' = reshape( { ' ];
	  
	  % Cell array of strings
	  for zz = 1:eval( [ 'numel( ' fullname ' )' ] )
	    s_out = [ s_out  ' ''' eval( [ fullname sprintf( '{ %d }', zz ) ] ) ''',' sprintf( '\n' ) ];
	  end
	  
	  s_out = [ s_out( 1:end-1 ) ' }, [' sprintf( ' %d', eval( [ 'size( ' fullname ' )' ] ) ) ' ] );\n\n' ];
	  
	  fprintf( fid_out, s_out );

	else

	  % Other
	  fprintf( fid_out, [ new_header  ' = ();  % You have to do this one yourself.' ] );

	end

      else
	  
	% Other
	fprintf( fid_out, [ new_header  ' = ();  % You have to do this one yourself.' ] );
		
      end
	
    end
    
  end
  
