%

% Copyright 2015-2016 The MathWorks, Inc.

function [hitNums, codeCovRes, justifiedHitNums] = getECCodeResInfo(indata, codeInfo, metricName, ignoreDescendants, covMode)

if isempty(ignoreDescendants)
    ignoreDescendants = false;
end

hitNums = [];
codeCovRes = [];
justifiedHitNums = 0;

if isa(indata, 'cv.cvdatagroup')
    % Scan all the 'cvdata' objects in the 'cvdatagroup' until we find one
    % that contains code coverage data and references the file/function.
    allData = indata.getAll(covMode);
else
    allData = {indata};
end

blockCvId = codeInfo.blockCvId;
useBlockInfo = ~isempty(codeInfo.fileName);
isBlockCvIdGood = ~isempty(blockCvId);
if ~useBlockInfo && ~isBlockCvIdGood
    return
end

if ~isBlockCvIdGood || useBlockInfo
    % If there is no coverage ID, look for code coverage data using 'block' as a source location specification.
    fileName = codeInfo.fileName;
    fcnName = codeInfo.fcnName;
else
    % If there is a coverage ID, look for code coverage data using the model-to-code traceability information.
    [metricCovField, metricNumField, factor, metricJustifCovField] = getCodeCovResStructInfoForMetric(metricName);

    isTop = false;
    try
        if cv('get', blockCvId, '.isa')==1
            for ii = 1:numel(allData)
                normalModeRootId = cvprivate('getNormalModeRootId', allData{ii}.rootId);
                if normalModeRootId~=0
                    if normalModeRootId==allData{ii}.rootId
                        topCvId = cv('get', cv('get', normalModeRootId, '.topSlsf'),'.treeNode.child');
                    else
                        topCvId = cv('get', normalModeRootId, '.topSlsf');
                    end
                    isTop = topCvId==blockCvId;
                    if isTop
                        % Stop on match but override the set of cvdata
                        allData = allData(ii);
                        break
                    end
                end
            end
        end
    catch
        isTop = false;
    end
    if ~isTop && (isempty(metricCovField) || (factor < 1))
        % We don't map the code cyclomatic complexity to blocks.
        return
    end

    if isTop && ~ignoreDescendants
        fileName = '';
        fcnName = '';
        blockCvId = [];
    end
end

for ii = 1:numel(allData)
    data = allData{ii};
    for jj = 1:numel(data)
        cvd = data(jj);
        resObj = cvd.codeCovData;
        if isempty(resObj)
            continue
        end
        resObj.refreshModelCovIds(cvd);
        covRes = resObj.toStruct();
            
        if isempty(blockCvId) || useBlockInfo
            % Look for the source location in the code coverage data.
            [fileIdx, fcnIdx] = findSourceLocInCodeCovRes(covRes, fileName, fcnName);
            if isempty(fileIdx)
                continue
            end

            [hitNums, codeCovRes, justifiedHitNums] = getCodeResInfoForMatchedSourceLoc(covRes, fileIdx, fcnIdx, metricName);
            if ~isempty(hitNums)
                return
            end
        else
            % Look for the block in the code coverage data.
            blockIdx = find(covRes.modelElements.modelCovId == blockCvId, 1, 'first');
            if isempty(blockIdx)
                continue
            end

            if ignoreDescendants || blockIdx > numel(covRes.modelElements.depth)
                % Use the 'shallow' field if 'ignoreDesendants' is set or the block is a leaf.
                covField = 'shallow';
            else
                covField = 'deep';
            end
            
            if ~isfield(covRes.modelElements.(covField), metricCovField) || ...
                    isempty(covRes.modelElements.(covField).(metricCovField))
                % The metric was not evaluated.
                continue
            end

            hitNums2 = [covRes.modelElements.(covField).(metricCovField)(blockIdx, end) ...
                covRes.modelElements.(covField).(metricNumField)(blockIdx, end) * factor];
            if hitNums2(2) < 1
                continue
            end
            hitNums = hitNums2;
            justifiedHitNums = covRes.modelElements.(covField).(metricJustifCovField)(blockIdx, end);
            codeCovRes = struct('covRes', covRes, 'blockIdx', blockIdx);
            return
        end
    end
end

