function displayOnModel(this, cvstruct, metricNames, toMetricNames,  options, hasFilter)
%

%   Copyright 1990-2019 The MathWorks, Inc.

% System table template
testCnt = length(cvstruct.tests);
if testCnt>1
    if options.cumulativeReport
        totalIdx = testCnt;
    else
        totalIdx = testCnt+1;
    end
else
    totalIdx = 1;
end

hasCodeCov = isfield(cvstruct, 'codeCovRes') && ~cvstruct.codeCovRes.isempty();

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%      Structural coverage     %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fullCovObjs = [];
justifiedCovObjs = [];
missingCovObjs = [];

metricNames = setdiff(metricNames , 'tableExec');

if any(strcmp(metricNames,'decision')) || ...
        any(strcmp(metricNames,'condition')) || ...
        any(strcmp(metricNames,'mcdc')) || ...
        any(strcmp(metricNames,'tableExec')) || ...
        ~isempty(toMetricNames) || ...
        hasFilter || ...
        hasCodeCov


    % First cache the coverage highlighting for any stateflow library linked charts
    % because the highlighting will need to change with user navigation
    modelH = get_param(cvstruct.model.name,'Handle');
    covColorData = get_param(modelH,'covColorData');
    if isempty(covColorData)
        covColorData = cvi.Informer.covcolordata_struct;
    end

    chartIds = [];
    if ~isempty(cvstruct.system)
        [linkInfo,chartIds,removeSys] = compute_sf_cov_display(this, cvstruct, metricNames, toMetricNames, options);

        if ~isempty(linkInfo)
            covColorData.sfLinkInfo = linkInfo;
            set_param(modelH,'covColorData',covColorData);
        end

        cvstruct.system(removeSys) = [];

        % Loop through each system and itemize coverage

        for i=1:numel(cvstruct.system)
            sysEntry = cvstruct.system(i);
            [fullCovObjs, justifiedCovObjs, missingCovObjs] = ...
                compute_sl_cov_display(this,fullCovObjs,justifiedCovObjs, missingCovObjs, ...
                                       sysEntry, cvstruct, metricNames, toMetricNames, options);
        end
    end
    topSlsf = cv('get',cvstruct.root.cvId,'.topSlsf');
    reportObj.metricNames = metricNames;
    reportObj.toMetricNames = toMetricNames;
    reportObj.cvstruct = cvstruct;
    reportObj.callFromCvmodelview = true;
    filteredCovObjs = addFilteredItems(this, topSlsf, reportObj);

    if hasCodeCov
        [fullCovObjs, justifiedCovObjs, missingCovObjs, filteredCovObjs] = ...
            addCodeCovData(this, cvstruct, fullCovObjs, justifiedCovObjs, missingCovObjs, filteredCovObjs, options);
    end

    this.storeColoring(fullCovObjs, justifiedCovObjs, missingCovObjs, filteredCovObjs);
    coverage_highlight_diagram(this, cvstruct, fullCovObjs, justifiedCovObjs, missingCovObjs, filteredCovObjs, cvi.HiliteBase.getHighlightingColorTable);

    %highlight library chart instances
    %See explanation in cvi.Informer.SFLibInstanceHighlighting
    if ~isempty(covColorData.sfLinkInfo)

        %Highlight SL-in-SF for all library instances
        instanceH = [covColorData.sfLinkInfo.instanceH];
        for chartIdx = 1:numel(instanceH)
            cvi.Informer.SFLibInstanceHighlighting_SLinSF(instanceH(chartIdx), modelH);
        end

        %Highlight other SF chart elements (transitions, states etc.) for
        %only the active instances. Other instances will be highlighted
        %dynamically after the call to open_system()
        chartIds = unique(chartIds);
        activeInstanceH = sf('get',chartIds,'.activeInstance');
        activeInstanceH(activeInstanceH==0)=[]; % Remove 0s
        for instH = activeInstanceH(:)'
            %the active instance has to be the last call,
            %because it is overwriting the
            %informer mapping data for the active instance, (all the
            %instances have the same id)
            cvi.Informer.SFLibInstanceHighlighting(instH);
        end
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%        Signal ranges         %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if any(strcmp(metricNames,'sigrange'))
    modelH = get_param(cvstruct.model.name,'Handle');
    covdata = cvstruct.allCvData{totalIdx};
    mapSignalRanges(this, modelH,covdata);
end

%=======================

function insertFilteredHtml(this, cvid, namedlink, rationale, isJustified)
rationale = cvi.ReportUtils.str_to_html(rationale);
if ~isa(this,'cvi.BadgeHandler')
    if isJustified
        filtText = getString(message('Slvnv:simcoverage:cvmodelview:isjustified'));
    else
        filtText = getString(message('Slvnv:simcoverage:cvmodelview:isfiltered'));
    end
    text= ['<b>' namedlink  '</b> ' filtText '. <br />'];
else
    filtText = getString(message('Slvnv:simcoverage:cvmodelview:Filtered'));
    text= [filtText ' <br />'];
end
text= [text '<b>' getString(message('Slvnv:simcoverage:cvmodelview:Rationale')) '</b> '  rationale ];
blkEntry.namedlink = namedlink;
blkEntry.rationale = rationale;
blkEntry.cvId = cvid;
blkEntry.postFix = true;
this.insertText(blkEntry, text);

%=======================
function filteredCovObjs = addFilteredItems(this, topSlsfobj, reportObj)

info  = cvi.ReportScript.getFilteredBlocks(reportObj, [], topSlsfobj, true);
filteredCovObjs  = [];
if isempty(info)
    return;
end


for idx = 1:numel(info)
    d = info(idx);
    %it is justified by parent
    if cv('get', d.cvId, '.isJustified')
        continue;
    end
    insertFilteredHtml(this, d.cvId, d.namedlink, d.rationale, d.mode);
    if isempty(d.metricCvIds) && d.mode == 0
        filteredCovObjs = [filteredCovObjs d.cvId]; %#ok<AGROW>
    end
end


%=======================
function coverage_highlight_diagram(infrmObj,cvstruct,fullCovObjs,justifiedCovObjs,missingCovObjs,filteredCovObjs, colorTable)

persistent sfFullCovStyle sfNoCovStyle sfMissingCovStyle sfJustifiedCovStyle;

sfIsa = get_sf_isa;

% Style objects
if isempty(sfFullCovStyle) || ~sf('ishandle',sfFullCovStyle) || ...
        sf('get',sfFullCovStyle,'.isa') ~= sfIsa.style
    sfFullCovStyle = sf('new','style');
    sf('set', sfFullCovStyle,  ...
       'style.name',                         'Full coverage', ...
       'style.blockEdgeColor',         colorTable.sfGreen, ...
       'style.wireColor',              colorTable.sfGreen, ...
       'style.fontColor',              colorTable.sfGreen, ...
       'style.bgColor',                colorTable.lightGray);
end

if isempty(sfJustifiedCovStyle) || ~sf('ishandle',sfJustifiedCovStyle) || ...
        sf('get',sfJustifiedCovStyle,'.isa') ~= sfIsa.style
    sfJustifiedCovStyle = sf('new','style');
    sf('set', sfJustifiedCovStyle,  ...
       'style.name',                         'Full coverage', ...
       'style.blockEdgeColor',         colorTable.sfLightGreen, ...
       'style.wireColor',              colorTable.sfLightGreen, ...
       'style.fontColor',              colorTable.sfLightGreen, ...
       'style.bgColor',                colorTable.lightGray);
end

if isempty(sfNoCovStyle) || ~sf('ishandle',sfNoCovStyle) || ...
        sf('get',sfNoCovStyle,'.isa') ~= sfIsa.style
    sfNoCovStyle = sf('new','style');
    sf('set', sfNoCovStyle,  ...
       'style.name',                         'No coverage', ...
       'style.blockEdgeColor',         colorTable.sfGray, ...
       'style.wireColor',              colorTable.sfGray, ...
       'style.fontColor',              colorTable.sfGray, ...
       'style.bgColor',                colorTable.lightGray);
end

if isempty(sfMissingCovStyle) || ~sf('ishandle',sfMissingCovStyle) || ...
        sf('get',sfMissingCovStyle,'.isa') ~= sfIsa.style
    sfMissingCovStyle = sf('new','style');
    sf('set', sfMissingCovStyle,  ...
       'style.name',                         'Missing coverage', ...
       'style.blockEdgeColor',         colorTable.sfRed, ...
       'style.wireColor',              colorTable.sfRed, ...
       'style.fontColor',              colorTable.sfRed, ...
       'style.bgColor',                colorTable.lightGray);
end




[slMissing, sfMissing] = convert_to_handle_vect(missingCovObjs);
[slCovered, sfCovered] = convert_to_handle_vect(fullCovObjs);
[slJustified, sfJustified] = convert_to_handle_vect(justifiedCovObjs);
[slFiltered, sfFiltered] = convert_to_handle_vect(filteredCovObjs);

sfMissing = collect_sublink_trans(sfMissing);
sfCovered = collect_sublink_trans(sfCovered);
sfFiltered = collect_sublink_trans(sfFiltered);
sfJustified = collect_sublink_trans(sfJustified);
allSFCovs = [sfMissing ; sfCovered; sfJustified; sfFiltered];
hasStateflow = ~isempty(allSFCovs);

% Build a list of all states and transitions
if hasStateflow
    sfChartIds = sf('get',allSFCovs ,'chart.id');
    sfMachIds = sf('get',sfChartIds,'.machine');
    sfMachIds = unique(sfMachIds);
    allSfStates = [];

    for chrt = sfChartIds(:)'
        allSfStates = [allSfStates sf('SubstatesIn', chrt)]; %#ok<AGROW>
    end
    allSfTrans = [];
    for st = allSfStates(:)'
        allSfTrans = [allSfTrans sf('TransitionsOf', st)]; %#ok<AGROW>
    end
    noCovTrans = setdiff(allSfTrans, allSFCovs);
    noCovStates = setdiff(allSfStates, allSFCovs);
else
    sfMachIds = [];
end

modelH = get_param(cvstruct.model.name,'Handle');
slMissing = setdiff(slMissing,modelH);
slCovered = setdiff(slCovered,modelH);
slJustified = setdiff(slJustified,modelH);
slFiltered = setdiff(slFiltered, modelH);

% For efficiency only apply screen colors to a system that has
% at least one block with coverage highlighting
slSystems = get_param(get_param([slMissing ; slFiltered ; slCovered; slJustified],'Parent'),'Handle');
if iscell(slSystems)
    slSystems = unique([slSystems{:}]);
end

% Cache warning state and suppress further warnings
[prevWarn, prevWarnId] = lastwarn;
cleanup_lastwarn = onCleanup(@() lastwarn(prevWarn, prevWarnId));
warnState = warning('query');
cleanup_warnState = onCleanup(@() warning(warnState));
warning('off','all');

if SlCov.CovStyle.IsFeatureEnabled()
    covResults.modelH = modelH;
    covResults.Systems = slSystems;
    covResults.FullCoverage = slCovered;
    covResults.PartialCoverage = slMissing;
    covResults.FilteredCoverage = slFiltered;
    covResults.JustifiedCoverage = slJustified;
    cvslhighlight('apply_style', infrmObj.covStyleSession, covResults);
else

    % Filtered blocks
    if ~isempty(slFiltered)
        cvslhighlight('apply',modelH,slFiltered,'black',colorTable.slGray);
    end

    if ~isempty(slSystems)
        cvslhighlight('apply',modelH,[],[],[],slSystems,colorTable.slGray);
    end

    % Fully covered blocks
    if ~isempty(slCovered)
        cvslhighlight('apply',modelH,slCovered,'black',colorTable.slGreen);
    end
    if ~isempty(slJustified)
        cvslhighlight('apply',modelH, slJustified,'black',colorTable.slLightGreen);
    end

    % Partially covered blocks
    if ~isempty(slMissing)
        cvslhighlight('apply',modelH,slMissing,'black',colorTable.slRed);
    end
end


if ~isempty(sfCovered)
    sf('SetAltStyle', sfFullCovStyle, sfCovered);
end
if ~isempty(sfJustified)
    sf('SetAltStyle', sfJustifiedCovStyle, sfJustified);
end

% Blocks that don't have coverage
if (hasStateflow)
    sf('SetAltStyle', sfNoCovStyle, [sfFiltered(:); noCovTrans(:) ; noCovStates(:)]);
end

if ~isempty(sfMissing)
    sf('SetAltStyle', sfMissingCovStyle, sfMissing);
end

% Redraw all the charts
for mchId = sfMachIds(:)'
    sf('Redraw',mchId);
end


function [slVect,sfIds] = convert_to_handle_vect(idVect)

slcvIds = cv('find',idVect,'slsfobj.origin',1);
sfcvIds = cv('find',idVect,'slsfobj.origin',2);
slVect = cv('get',slcvIds,'slsfobj.handle');
sfIds = cv('get',sfcvIds,'slsfobj.handle');
slVect = slVect (slVect ~= 0);
sfIds  = sfIds  (sfIds  ~= 0);


function allIds = collect_sublink_trans(mixedIds)

allIds = mixedIds;

transIsa = sf('get','default','trans.isa');
transIds = sf('find',allIds,'.isa',transIsa);

subLinks = sf('get',transIds,'.firstSubWire');
subLinks(subLinks==0) = [];


while( ~isempty(subLinks))
    allIds = [allIds ; subLinks]; %#ok<AGROW>
    subLinks = sf('get',subLinks,'.subLink.next');
    subLinks(subLinks==0) = [];
end


function out = get_sf_isa

persistent sfIsa;

if isempty(sfIsa)
    sfIsa.machine = sf('get','default','machine.isa');
    sfIsa.chart = sf('get','default','chart.isa');
    sfIsa.state = sf('get','default','state.isa');
    sfIsa.transition = sf('get','default','transition.isa');
    sfIsa.junction = sf('get','default','junction.isa');
    sfIsa.port = sf('get', 'default', 'port.isa');
    sfIsa.style = sf('get','default','style.isa');
end

out = sfIsa;


%===============================================
function [cvIds, infrmStrs, allFullCov] = compute_sf_sys(this, cvstruct, metricNames, toMetricNames, sysIdx, options)

sysEntry = cvstruct.system(sysIdx);
[allFullCov, covStr] = installInformerText(this,sysEntry,cvstruct, metricNames, toMetricNames, options);
cvIds = sysEntry.cvId;
infrmStrs = {covStr};


is_a_truth_table = 0;
if cv('get',sysEntry.cvId,'.origin') == 2
    sfId = cv('get',sysEntry.cvId,'.handle');
    if (sf('get',sfId,'.isa')==sf('get','default','state.isa'))
        is_a_truth_table = sf('get',sfId,'.truthTable.isTruthTable');
    end
end

if ~is_a_truth_table
    for blockI = sysEntry.blockIdx(:)'
        blkEntry = cvstruct.block(blockI);
        [fullCov, covStr] = installInformerText(this,blkEntry,cvstruct, metricNames, toMetricNames, options);
        cvIds = [cvIds blkEntry.cvId]; %#ok<AGROW>
        infrmStrs = [infrmStrs {covStr}]; %#ok<AGROW>
        allFullCov = [allFullCov fullCov]; %#ok<AGROW>
    end
end




function [instStruct,chartIds,removeSys] = compute_sf_cov_display(this, cvstruct, metricNames, toMetricNames, options)

sfIsa = get_sf_isa;

instStruct = [];
chartIds = [];
removeSys = [];

% Find all the Stateflow charts in the coverage data
sysIds = [cvstruct.system.cvId];
[sysHandles, sysOrigins, sysIsa] = cv('get',sysIds,'.handle','.origin','.refClass');
isChartSys = (sysOrigins==2 & sysIsa==sfIsa.chart);

sfChrtIds = sysHandles(isChartSys);

if isempty(sfChrtIds)
    return;
end
% See if there are duplicate chart ids (these are multi-instantiated library charts)
[srtIds, sortIdx] = sort(sfChrtIds);
dupSys = [0 ; srtIds(1:(end-1))==srtIds(2:end)];
dupSys = dupSys | [dupSys(2:end) ; 0];
unsortIdx = 1:length(srtIds);
unsortIdx(sortIdx) = unsortIdx;
chartIsDup = dupSys(unsortIdx);
isDupChartSys = false(1,length(sysIds));
isDupChartSys(isChartSys) = chartIsDup;
chartIds = sysHandles(isDupChartSys);

dupChartSys = find(isDupChartSys);
removeSys = dupChartSys;

for dupIdx = dupChartSys

    [cvIds, infrmStrs, allFullCov] = compute_sf_sys(this,cvstruct, metricNames, toMetricNames, dupIdx, options);
    childSysIdx = descendent_sys_ind(cvstruct, dupIdx);
    removeSys = [removeSys childSysIdx]; %#ok<AGROW>
    for childIdx = childSysIdx
        [ids, strs, fullCov] = compute_sf_sys(this,cvstruct, metricNames, toMetricNames, childIdx, options);
        cvIds = [cvIds ids]; %#ok<AGROW>
        infrmStrs = [infrmStrs strs]; %#ok<AGROW>
        allFullCov  = [allFullCov,  fullCov]; %#ok<AGROW>
    end

    % Cache the reference block to determine when the library
    % has been manually closed.
    [refBlockH, instanceH ] = cvstruct_instance_handle(cvstruct, dupIdx);

    thisElm = struct(   'instanceH',        instanceH, ...
                        'refBlockH',        refBlockH, ...
                        'cvIds',            cvIds, ...
                        'informerStrings',  {infrmStrs}, ...
                        'isFullCoverage',   allFullCov);

    if isempty(instStruct)
        instStruct = thisElm;
    else
        instStruct(end+1) = thisElm; %#ok<AGROW>
    end
end


function childSysIdx = descendent_sys_ind(cvstruct, parentIdx)
parentDepth = cvstruct.system(parentIdx).depth;

% Use the fact that systems are entered in topological order
childSysIdx = [];
childIdx = parentIdx+1;
while (childIdx<=length(cvstruct.system) && cvstruct.system(childIdx).depth>parentDepth)
    childSysIdx = [childSysIdx childIdx]; %#ok<AGROW>
    childIdx = childIdx + 1;
end

%====================
function [refBlockH, instanceH] = cvstruct_instance_handle(cvstruct, chartSysIdx)
cvId = cvstruct.system(chartSysIdx).cvId;
instancePath = Simulink.ID.getFullName(cv('get', cvId, '.origPath'));
instanceH  =  get_param(instancePath, 'handle');

refBlockH = get_param(get_param(instanceH,'ReferenceBlock'),'Handle');
%====================
function [fullCovObjs, justifiedCovObjs, missingCovObjs] = compute_sl_missing(this,...
                                                  fullCovObjs, justifiedCovObjs, missingCovObjs, dataEntry, cvstruct, metricNames, toMetricNames, options)
[allFullCov, covTxt]= installInformerText(this,dataEntry,cvstruct, metricNames, toMetricNames, options);

%undefined
if allFullCov == -1
    return
end
if ~isempty(this)
    this.insertText(dataEntry, covTxt);
end

cvId = dataEntry.cvId;
if allFullCov == 0
    missingCovObjs = [missingCovObjs cvId];
elseif allFullCov == 1
    fullCovObjs = [fullCovObjs cvId];
elseif allFullCov == 2
    justifiedCovObjs = [justifiedCovObjs cvId];
end
%====================

function [fullCovObjs, justifiedCovObjs, missingCovObjs] = compute_sl_cov_display(this, fullCovObjs, justifiedCovObjs, missingCovObjs, sysEntry, cvstruct, metricNames, toMetricNames, options)

[fullCovObjs, justifiedCovObjs, missingCovObjs] = compute_sl_missing(this, fullCovObjs, justifiedCovObjs, missingCovObjs, sysEntry, cvstruct, metricNames, toMetricNames, options);

for blockI = sysEntry.blockIdx(:)'
    blkEntry = cvstruct.block(blockI);
    [fullCovObjs, justifiedCovObjs, missingCovObjs] = compute_sl_missing(this, fullCovObjs, justifiedCovObjs, missingCovObjs, blkEntry, cvstruct, metricNames, toMetricNames, options);
end
%====================
function [fullCovObjs, justifiedCovObjs, missingCovObjs, filteredCovObjs] = addCodeCovData(this, cvstruct, fullCovObjs, justifiedCovObjs, missingCovObjs, filteredCovObjs, options)

persistent modeStr2Label;
if isempty(modeStr2Label)
    modeStr2Label = containers.Map(...
        {'SIL', 'PIL', 'ModelRefSIL', 'ModelRefPIL'},...
        {...
            getString(message('Slvnv:simcoverage:cvmodelview:LabelSILShort')),...
            getString(message('Slvnv:simcoverage:cvmodelview:LabelPILShort')),...
            getString(message('Slvnv:simcoverage:cvmodelview:LabelSILShort')),...
            getString(message('Slvnv:simcoverage:cvmodelview:LabelPILShort')) ...
        });
end

if options.generatWebViewReportData == 1
    commandType = 2;
else
    commandType = 1;
end

persistent codeCovDefs;
if isempty(codeCovDefs)
    codeCovDefs = {...
        'decisionsCov',     'numNonFilteredDecOutcomes',          'decisionsJustifiedCov', 1 ; ...
        'conditionsCov',    'numNonFilteredConditions',           'conditionsJustifiedCov', 2 ; ...
        'mcdcCondCov',      'numNonFilteredMcdcCond',             'mcdcCondJustifiedCov', 1 ; ...
        'statementsCov',    'numNonFilteredStatements',           'statementsJustifiedCov', 1 ; ...
        'relationalOpsCov', 'numNonFilteredRelationalOpOutcomes', 'relationalOpsJustifiedCov', 1 ...
                  };
end

modes = cvstruct.codeCovRes.keys();
for ii = 1:numel(modes)

    if modeStr2Label.isKey(modes{ii})
        modeStr = modeStr2Label(modes{ii});
    else
        modeStr = modes{ii};
    end

    covRes = cvstruct.codeCovRes(modes{ii});

    % Evaluate code coverage for the sub-systems.
    hasCoverage = false(numel(covRes.modelElements.depth), 1);
    fullCoverage = true(numel(covRes.modelElements.depth), 1);
    fullJustifiedCoverage = true(numel(covRes.modelElements.depth), 1);
    for jj = 1:size(codeCovDefs, 1)
        if isempty(covRes.modelElements.deep.(codeCovDefs{jj, 1}))
            continue
        end
        cov = covRes.modelElements.deep.(codeCovDefs{jj, 1})(:, end);
        if ~isempty(cov)
            justifiedCov = covRes.modelElements.deep.(codeCovDefs{jj, 3})(:, end);
            n = covRes.modelElements.deep.(codeCovDefs{jj, 2})(:, end);
            n = n * codeCovDefs{jj, 4};
            hasCoverage(n ~= 0) = true;
            fullCoverage(cov ~= n) = false;
            fullJustifiedCoverage((cov + justifiedCov) ~= n) = false;
        end
    end
    codeCovObjs = covRes.modelElements.modelCovId(hasCoverage, :)';
    missingCodeCovObjs = covRes.modelElements.modelCovId(~fullCoverage & ~fullJustifiedCoverage, :)';
    fullCodeCovObjs = covRes.modelElements.modelCovId(hasCoverage & fullCoverage, :)';
    fullJustifiedCodeCovObjs = covRes.modelElements.modelCovId(hasCoverage & ~fullCoverage & fullJustifiedCoverage, :)';

    % Evaluate code coverage for the blocks.
    blocksIdx = cat(1, covRes.modelElements.blocksIdx{:});

    blockHasCoverage = false(numel(blocksIdx), 1);
    blockFullCoverage = true(numel(blocksIdx), 1);
    blockFullJustifiedCoverage = true(numel(blocksIdx), 1);
    for jj = 1:size(codeCovDefs, 1)
        if isempty(covRes.modelElements.shallow.(codeCovDefs{jj, 1}))
            continue
        end
        cov = covRes.modelElements.shallow.(codeCovDefs{jj, 1})(blocksIdx, end);
        if ~isempty(cov)
            justifiedCov = covRes.modelElements.shallow.(codeCovDefs{jj, 3})(blocksIdx, end);
            n = covRes.modelElements.shallow.(codeCovDefs{jj, 2})(blocksIdx, end);
            n = n * codeCovDefs{jj, 4};
            blockHasCoverage(n ~= 0) = true;
            blockFullCoverage(cov ~= n) = false;
            blockFullJustifiedCoverage((cov + justifiedCov) ~= n) = false;
        end
    end
    allBlockObjs = covRes.modelElements.modelCovId(blocksIdx);

    % Combine sub-systems and blocks coverage data.
    codeCovObjs = [codeCovObjs allBlockObjs(blockHasCoverage, :)']; %#ok<AGROW>
    missingCodeCovObjs = [missingCodeCovObjs allBlockObjs(~blockFullCoverage & ~blockFullJustifiedCoverage, :)']; %#ok<AGROW>
    fullCodeCovObjs = [fullCodeCovObjs allBlockObjs(blockHasCoverage & blockFullCoverage, :)']; %#ok<AGROW>
    fullJustifiedCodeCovObjs = [fullJustifiedCodeCovObjs allBlockObjs(blockHasCoverage & ~blockFullCoverage & blockFullJustifiedCoverage, :)']; %#ok<AGROW>

    % If the model has changed since the coverage data was collected, ignore the
    % blocks that no longer exist.
    codeCovObjs(codeCovObjs == 0) = [];
    missingCodeCovObjs(missingCodeCovObjs == 0) = [];
    fullCodeCovObjs(fullCodeCovObjs == 0) = [];
    fullJustifiedCodeCovObjs(fullJustifiedCodeCovObjs == 0) = [];

    % Combine with previously computed coverage data (e.g. model coverage).
    filteredCovObjs(ismember(filteredCovObjs, codeCovObjs)) = [];
    missingCovObjs = unique([missingCovObjs missingCodeCovObjs]);
    fullCovObjs = unique([fullCovObjs fullCodeCovObjs fullJustifiedCodeCovObjs]);
    fullCovObjs(ismember(fullCovObjs, missingCovObjs)) = [];

    % Update the informer text for partially covered code.
    [~, idx] = ismember([missingCodeCovObjs fullJustifiedCodeCovObjs], covRes.modelElements.modelCovId);
    for kk = idx(:)'
        cvId = covRes.modelElements.modelCovId(kk);
        covStr = this.getText(cvId);
        if isempty(covStr)
            if this.showLink
                covStr = ['<b>' cvi.ReportScript.object_titleStr_and_link(cvId, [], commandType) '</b><br/>' newline '<br/>' newline newline];
            end
        else
            covMode = getString(message('Slvnv:simcoverage:cvmodelview:LabelNormalShort'));
            covStr = ['<u>' covMode ': </u>', '<br/>'  covStr newline]; %#ok<AGROW>
        end

        informerTxt = [covStr , '<u>', modeStr, ': </u>', getCodeCoverageInformerText(covRes.modelElements, kk)];

        this.insertText(struct('cvId', cvId), informerTxt, true);
    end

    % Update the informer text for fully covered code.
    for cvId = fullCodeCovObjs
        covStr = this.getText(cvId);
        if isempty(covStr)
            if this.showLink
                covStr = ['<b>' cvi.ReportScript.object_titleStr_and_link(cvId, [], commandType) '</b><br/>' newline '<br/>' newline newline];
            end
        else
            covMode = getString(message('Slvnv:simcoverage:cvmodelview:LabelNormalShort'));
            covStr = ['<u>' covMode ': </u>' covStr '<br/>' newline]; %#ok<AGROW>
        end
        this.insertText(struct('cvId', cvId), [covStr, '<u>' modeStr ': </u>', getString(message('Slvnv:simcoverage:cvmodelview:FullCoverage'))], true);
    end
end

%====================
function str = getCodeCoverageInformerText(modelElements, idx)

persistent codeCovDefs

if isempty(codeCovDefs)
    codeCovDefs = {...
        'decisionsCov',     'numNonFilteredDecOutcomes',          'decisionsJustifiedCov', 1, 'Decision'           ; ...
        'conditionsCov',    'numNonFilteredConditions',           'conditionsJustifiedCov', 2, 'Condition'          ; ...
        'mcdcCondCov',      'numNonFilteredMcdcCond',             'mcdcCondJustifiedCov', 1, 'MCDC'               ; ...
        'statementsCov',    'numNonFilteredStatements',           'statementsJustifiedCov', 1, 'Statement'          ; ...
        'relationalOpsCov', 'numNonFilteredRelationalOpOutcomes', 'relationalOpsJustifiedCov', 1, 'RelationalBoundary' ...
                  };
end

row = 1;
col = 1;
strTable = [];

if idx <= numel(modelElements.depth)
    srcField = 'deep';
else
    srcField = 'shallow';
end

for ii = 1:size(codeCovDefs, 1)
    % The metric is not enabled
    if isempty(modelElements.(srcField).(codeCovDefs{ii, 1}))
        continue
    end

    % No metric
    count = modelElements.(srcField).(codeCovDefs{ii, 2})(idx) * codeCovDefs{ii, 4};
    if count < 1
        continue
    end

    hit = modelElements.(srcField).(codeCovDefs{ii, 1})(idx);
    justifiedHit = modelElements.(srcField).(codeCovDefs{ii, 3})(idx);

    if justifiedHit > 0
        strTable{row,col} = sprintf('%s %2.0f%% ((%d+%d)/%d)', ...
                                    getString(message(['Slvnv:simcoverage:cvmodelview:', codeCovDefs{ii, 5}])), ...
                                    100*(hit+justifiedHit)/count, hit, justifiedHit, count); %#ok<AGROW>
    else
        strTable{row,col} = sprintf('%s %2.0f%% (%d/%d)', ...
                                    getString(message(['Slvnv:simcoverage:cvmodelview:', codeCovDefs{ii, 5}])), ...
                                    100*hit/count, hit, count); %#ok<AGROW>
    end

    % Update the cell insertion position
    if col==2
        col = 1;
        row = row + 1;
    else
        col = 2;
    end
end

if col==1
    rowCnt = row - 1;
else
    rowCnt = row;
    strTable{row,col} = ' ';
end

if row==1 && col==1
    str = '';
    return
end

tableInfo.table = '  CELLPADDING="2" CELLSPACING="1"';
tableInfo.cols = struct('align','LEFT');

template = {{'ForN',rowCnt, ...
             {'ForN',2, ...
              {'#.','@2','@1'}, ...
             }, ...
             '\n' ...
            }};

str = cvprivate('html_table', strTable,template,tableInfo);
