%% set_code
%    set the script of an embedded matlab block to an inputed
%    string of eml code, create the inputs and outputs for the
%    subsystem to connect to the eml block
% inputs:
%   block_handle:handle - handle block to update
%   code:string - eml code
%   function_name:string - name of the function
% outputs:
%   eml_handle:handle - handle of eml block, as this function may
%   create a new block.
% Author: Colin Eles elesc@mcmaster.ca
% Organization: McMaster Centre for Software Certification
function eml_handle = set_code(block_handle,code,function_name)
% unlink the block from the library, this is necessary if
% we
% want to change the subsystem of the block.
set_param(block_handle,'LinkStatus','none');


% determine if the name already exists in the model

if (~strcmp(get(block_handle,'Name'),function_name))
    try
        set_param(block_handle,'Name',function_name);
    catch exception
        msgbox(exception.message);
    end
end

% embedded matlab code block store code in stateflow states so
% we need to get the root hande
S = sfroot;

% get the path of the code block
code_block = sprintf('%s/code',getfullname(block_handle));
% determine if code block already exists
code_blocks = find_system(getfullname(block_handle),'LookUnderMasks','all','BlockType','SubSystem','Name','code');

% if the code block does not already exists we need to create a
% new one
if (isempty(code_blocks))
    if (sum(version('-release') >= '2011a') >= 5)
        code_blocks = add_block('simulink/User-Defined Functions/MATLAB Function',code_block);
    else
        code_blocks = add_block('simulink/User-Defined Functions/Embedded MATLAB Function',code_block);
    end        
end

eml_handle = code_blocks;
% find the state of the code block and update it to the new
% code
myState = S.find('-isa','Stateflow.EMChart', '-and', 'Path', code_block); % find which one we want to edit

if (~isempty(myState))
    myState.Script =  sprintf('%s',code);
end

% delete any lines that are unconnected and one end or both
% code from
lines = find_system( getfullname(block_handle), ...
    'LookUnderMasks', 'all', ...
    'FindAll', 'on', ...
    'Type', 'line' ) ;


for i=1:length( lines )
    if ishandle( lines( i ) )
        TableBlock.delete_recursive( lines( i ) );
    end
end


% we need to determine which of the inports and outports we
% need to create and delete. Whenever we delete a port anything
% connected with this port is unconnected, other blocks, scopes
% etc. We would like to avoid this if possible because it can
% be quite annoying.

% First loop through all the inport blocks, if there does not
% exists an inport in the code block of the same name then
% delete the inport block
inports = find_system(getfullname(block_handle),'LookUnderMasks','all','SearchDepth',1,'FindAll','On','BlockType','Inport');
for i=1:size(inports,1)
    found = 0;
    in_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Inport');
    
    for j=1:size(in_handles,1)
        if strcmp(get_param(inports(i),'Name'),get_param(in_handles(j),'Name'))
            % Make sure the port numbers agree.
            set_param(inports(i), 'Port', get_param(in_handles(j), 'Port'));
            found = 1;
        end
    end
    
    if (~found)
        % old inport no longer exists
        delete_block(inports(i));
    end
end

% now we loop through all the inports in the code block if
% there is an inport block of the same name then connect them,
% else create a new inport block and connect them
in_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Inport');
for j = 1:size(in_handles,1)
    found = 0;
    inports = find_system(getfullname(block_handle),'LookUnderMasks','all','SearchDepth',1,'BlockType','Inport');
    for i = 1:size(inports,1)
        if strcmp(get_param(inports(i),'Name'),get_param(in_handles(j),'Name'))
            found = 1;
            
            % draw the line
            new_port_num = sprintf('%s/1',get_param(in_handles(j),'Name'));
            dest_port = sprintf('%s/%d','code',j);
            try
                add_line(getfullname(block_handle),new_port_num,dest_port);
            end
        end
    end
    if (~found)
        new_port = sprintf('%s/%s',getfullname(block_handle),get_param(in_handles(j),'Name'));
        add_block('simulink/Sources/In1',new_port);
        new_port_num = sprintf('%s/1',get_param(in_handles(j),'Name'));
        dest_port = sprintf('%s/%d','code',j);
        % Set the port number so the ports line up properly.
        set_param(new_port, 'Port', get_param(in_handles(j), 'Port'));
        % sometimes line will be created automatically
        try
            add_line(getfullname(block_handle),new_port_num,dest_port);
        end
    end
    
    
end


% Next we do the same thing with the outputs
outports = find_system(getfullname(block_handle),'LookUnderMasks','all','SearchDepth',1,'FindAll','On','BlockType','Outport');
for i=1:size(outports,1)
    found = 0;
    out_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Outport');
    
    for j=1:size(out_handles,1)
        if strcmp(get_param(outports(i),'Name'),get_param(out_handles(j),'Name'))
            found = 1;
        end
    end
    
    if (~found)
        % old inport no longer exists
        delete_block(outports(i));
    end
end

out_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Outport');
for j = 1:size(out_handles,1)
    found = 0;
    outports = find_system(getfullname(block_handle),'LookUnderMasks','all','SearchDepth',1,'BlockType','Outport');
    for i = 1:size(outports,1)
        if strcmp(get_param(outports(i),'Name'),get_param(out_handles(j),'Name'))
            found = 1;
            
            % draw the line
            new_port_num = sprintf('%s/1',get_param(out_handles(j),'Name'));
            dest_port = sprintf('%s/%d','code',j);
            try
                add_line(getfullname(block_handle),dest_port,new_port_num);
            end
        end
    end
    if (~found)
        new_port = sprintf('%s/%s',getfullname(block_handle),get_param(out_handles(j),'Name'));
        add_block('simulink/Sinks/Out1',new_port);
        new_port_num = sprintf('%s/1',get_param(out_handles(j),'Name'));
        dest_port = sprintf('%s/%d','code',j);
        try
            add_line(getfullname(block_handle),dest_port,new_port_num);
        end
    end
end

% delete any lines that are unconnected and one end or both
% again sometimes extra lines are created
lines = find_system( getfullname(block_handle), ...
    'LookUnderMasks', 'all', ...
    'FindAll', 'on', ...
    'Type', 'line' ) ;

for i=1:length( lines )
    if ishandle( lines( i ) )
        TableBlock.delete_recursive( lines( i ) );
    end
end

end