
function [result, totalRows] = slSurrogateInExcel(modelName, surrogateName, parentIdx, SIDs)
% example script to generate Simulink Model surrogate in Excel Workbook
%
% Usage:
%   >> open_system(modelName);
%   >> [objHs, parentIdx, isSf, objSIDs] = rmi('getObjectsInModel',  modelName);
%   >> [resultsFileName, totalRows] = slSurrogateInExcel(modelName, surrogateName, parentIdx, objSIDs)

    % will try to create a new surrogate in current directory
    result = fullfile(pwd, [surrogateName '.xlsx']);
    
    try
        % try to connect running Excel application if possible
        hExcel = actxGetRunningServer('excel.application'); 
    catch ME %#ok<NASGU>
        % or initialize a new instance
        hExcel = actxserver('excel.application');
    end
    hExcel.Visible = 1;
    
    % Save a new empty Workbook
    hWorkbook = hExcel.Workbooks.Add();
    hWorkbook.SaveAs(result);
    
    
    % Populate headers:
    topLabel = labelAndType([modelName SIDs{1}]);
    hSheet = hWorkbook.ActiveSheet;
    row = 1; col = 2;
    hSheet.Rows.Item(row).Cells.Item(col).Value = ['Surrogate module for ' topLabel];
    hSheet.Rows.Item(row).Cells.Item(col).Font.Size = 20;
    hSheet.Rows.Item(row).Cells.Item(col).Font.Bold = 1;
    row = 3;
    hSheet.Rows.Item(row).Font.Size = 16;
    hSheet.Rows.Item(row).Font.Bold = 1;
    hSheet.Rows.Item(row).Cells.Item(1).Value = 'RequirementID';
    hSheet.Columns.Item(1).ColumnWidth = 30;
    hSheet.Rows.Item(row).Cells.Item(col).Value = 'Simulink Object';
    
    % Populate model structure:
    row = 4; col=3; 
    idx = 1; % start from top
    totalRows = addObjectsRecursively(hSheet, modelName, idx, parentIdx, SIDs, row, col);
    hWorkbook.Save();
end

function label = labelAndType(slObj)
    [objName, objType] = rmi('getObjLabel', slObj);
    label = [objName ' (' objType ')'];
end

function [row, col] = addObjectsRecursively(hSheet, modelName, idx, parentIdx, SIDs, row, col)
    for i = 1:length(idx)
        itemIdx = idx(i);
        row = oneObjectRow(hSheet, row+1, col, modelName, SIDs{itemIdx});
        if isSignalBuilder([modelName SIDs{itemIdx}])
            continue;  % for now, SignalBuilder is treated as a single item with no children
        end
        children = find(parentIdx == itemIdx);
        if ~isempty(children)
            col = col+1;
            for j = 1:length(children)
                [row, col] = addObjectsRecursively(hSheet, modelName, children(j), parentIdx, SIDs, row, col);
            end
            col = col-1;
        end
    end
end

function yesno = isSignalBuilder(objSid)
    slObj = Simulink.ID.getHandle(objSid);
    if isa(slObj, 'Stateflow.Object')
        yesno = false;
    else
        yesno = rmisl.is_signal_builder_block(slObj);
    end
end

function row = oneObjectRow(hSheet, row, col, modelName, sid)

    % fill-in a row for SL object with this SID
    item = [modelName sid];
    
    % display object Name and Type
    label = labelAndType(item);
    hSheet.Rows.Item(row).Cells.Item(col).Value = label;

    % add hyperlink in previous column
    url = rmi.getURL(item);
    hSheet.Hyperlinks.Add(hSheet.Rows.Item(row).Cells.Item(col-1), url, '', 'Show in Simulink', '[SL]');

    % if there are links, populate the 1st column with the last link
    linkInfo = rmi('get', item);
    if ~isempty(linkInfo)
        oneLink = linkInfo(end);
        if oneLink.linked  % we are only interested in real links, not the surrogate links
            linkUrl = rmi.reqToUrl(oneLink, modelName, true);
            if isempty(oneLink.id)
                [~, linkLabel] = fileparts(oneLink.doc);
            else
                linkLabel = oneLink.id;
                if linkLabel(1) == '@'
                    linkLabel(1) = [];  % '@' has special meaning in Excel 
                end
            end
            hSheet.Hyperlinks.Add(hSheet.Rows.Item(row).Cells.Item(1), linkUrl, '', oneLink.description, linkLabel);
        end
    end
    
    % finally, append the surrogate link to the object in Simulink
    if isempty(linkInfo)
        % surrogate link is the only link here
        allLinks = excelSurrogateLink(hSheet.Parent.Name, row);
    elseif linkInfo(1).linked
        % pre-pend surrogate link to existing links
        allLinks = [excelSurrogateLink(hSheet.Parent.Name, row) ; linkInfo];
    else
        % replace the existing surrogate link with an updated link
        allLinks = [excelSurrogateLink(hSheet.Parent.Name, row) ; linkInfo(2:end)];
    end
    rmi('set', item, allLinks);
end

function surrogateLink = excelSurrogateLink(docName, row)
    surrogateLink = rmi('createempty');
    surrogateLink.reqsys = 'linktype_rmi_excel';
    surrogateLink.doc = docName;
    surrogateLink.description = 'Excel Surrogate Item';
    surrogateLink.id = sprintf('$A%d:B%d', row, row);
    surrogateLink.linked = 0;
end
