function generateInteractionFunction( fid, m, userCodeSections )
    ifname = makeIFname( m.globalProps.modelname );
    if isempty(ifname)
        complain( 'generateInteractionFunction: no model name.  Cannot make interaction function.' );
        return;
    end
    if nargin < 3
        need_setproperties = true;
        userCodeSections = defaultUserCodeSections();
    else
        need_setproperties = (~isfield( userCodeSections, 'subfunctions')) ...
            || isempty( userCodeSections.subfunctions );
        userCodeSections = defaultFromStruct( ...
            userCodeSections, defaultUserCodeSections() );
    end
    
    coderevinfo = sprintf( '%%   Written at %s.\n%%   GFtbox revision %d, %s.', ...
             datestr(clock,'yyyy-mm-dd HH:MM:SS'), ...
             m.globalProps.coderevision, ...
             m.globalProps.coderevisiondate );
    if m.globalProps.modelrevision==0
        modelrevinfo = '';   % '%   Model not saved on SVN.';
    else
        modelrevinfo = sprintf( '%%   Model last saved to SVN as revision %d, %s.\n', ...
             m.globalProps.modelrevision, ...
             m.globalProps.modelrevisiondate );
    end
    
    preamble1a = ...
      { [ 'function m = ', ifname, '( m )' ], ...
        [ '%m = ', ifname, '( m )' ], ...
        '%   Morphogen interaction function.', ...
        coderevinfo, ...
        modelrevinfo ...
        };
    preamble1b = loadIFtemplate( 'if_before_user_init' );
    
    if m.versioninfo.mgenversion==0
        preamble2 = loadIFtemplate( 'if_oldmgens' );
        systematic_mgen_range = 4:length(m.mgenIndexToName);
    else
        preamble2 = loadIFtemplate( 'if_newmgens' );
        systematic_mgen_range = [1:5 7:length(m.mgenIndexToName)];
    end
    
    if m.versioninfo.mgenversion==0
        postamble1 = loadIFtemplate( 'if_endinit_old' );
    else
        postamble1 = loadIFtemplate( 'if_endinit_new' );
    end

    printstrings( fid, preamble1a );
    printstrings( fid, preamble1b );
    fwrite( fid, userCodeSections.init );
    printstrings( fid, preamble2 );

    for i=systematic_mgen_range
        n = m.mgenIndexToName{i};
        ln = lower(n);
        fprintf( fid, ...
            '    [%s_i,%s_p,%s_a,%s_l] = getMgenLevels( m, ''%s'' );\n', ...
            ln, ln, ln, ln, n );
    end

    writeMeshInfo( fid, m );
    
    printstrings( fid, loadIFtemplate( 'if_begin_interaction' ) );

    fwrite( fid, userCodeSections.mid );
    printstrings( fid, postamble1 );

    for i=systematic_mgen_range
        n = m.mgenIndexToName{i};
        ln = lower(n);
        fprintf( fid, ...
            '    m.morphogens(:,%s_i) = %s_p;\n', ...
            ln, ln );
    end

    printstrings( fid, ...
        { '', ...
          '%%% USER CODE: FINALISATION', ...
          userCodeSections.final, ...
          '%%% END OF USER CODE: FINALISATION', ...
          '', ...
          'end', ...
          '' } );
      
    printstrings( fid, ...
        { '', ...
          '%%% USER CODE: SUBFUNCTIONS' } );

    if need_setproperties
        dumpGlobalPropsToIF( fid, m );
    end

    fwrite( fid, userCodeSections.subfunctions );
end

function dumpGlobalPropsToIF( fid, m )
    fns = fieldnames( m.globalProps );
    fwrite( fid, loadIFtemplate( 'if_initproperties' ) );
    nfns = length(fns);
    for i=1:nfns
        fn = fns{i};
        val = m.globalProps.(fn);
        if ischar( val )
            fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', ''%s'' );\n', fn, unesc(val) );
        else
            n = numel(val);
            if n==0
                fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', [] );\n', fn );
            elseif n==1
                if islogical( val )
                    if val
                        fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', true );\n', fn );
                    else
                        fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', false );\n', fn );
                    end
                elseif isinteger( val )
                    fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', %d );\n', fn, val );
                elseif isreal( val )
                    fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', %f );\n', fn, val );
                else
                    fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', (unknown type ''''%s'''') );\n', fn, class(val) );
                end
            else
                fprintf( fid, '%%    m = leaf_setproperty( m, ''%s'', (%d values) );\n', fn, n );
            end
        end
    end
    fprintf( fid, 'end\n' );
end

function s = unesc(s)
%unescape s so that it can appear as the contents of a Matlab string constant.
    s = regexprep( s, '''', '''''' );
end