% MappingUtil  An object that computes the mapping between blocks in the
% original model and the copied model.
%
% See also CopyToOrigMap

%   Copyright 2014-2021 The MathWorks, Inc.

classdef MappingUtil < handle
%% Note
% This mapping assumes that the model copy has inlined all the model 
% reference blocks, i.e., the contents of the referenced model are copied
% into the subsystems which replace the model blocks.
    
    properties
        mdl
        mdlCopy
        refMdlToMdlBlk
        map2Subsystem
    end
    
    methods
        function obj = MappingUtil(mdl, mdlCopy, refMdlToMdlBlk, map2Subsystem)
            obj.mdl = mdl;
            obj.mdlCopy = mdlCopy;
            obj.refMdlToMdlBlk = refMdlToMdlBlk;
            obj.map2Subsystem = map2Subsystem;
        end
        
        function copyPath = getCopyPath(obj, bh)
            copyPath = getBlockCopyPath(bh, obj.refMdlToMdlBlk, ...
                obj.mdl, obj.mdlCopy,obj.map2Subsystem);
        end
    
    end
end

function copyPath = getBlockCopyPath(bh, refMdlToMdlBlk, sys, mdlCopy, map2Subsystem)
% Handle the case where the block handle is in a referenced model.
mdlH = bdroot(bh);
rootH = get_param(bdroot(sys), 'Handle');

[yesno, graph_bh] = Analysis.isRootOfMdlref(refMdlToMdlBlk, bh);
if yesno
    bh = graph_bh;
end

blockPath = { Simulink.ID.getFullName(bh)} ;
mdlNames = {get(mdlH, 'Name')};

while mdlH ~= rootH
    % Repeatedly look for parent model until found the root Model
    if ~isempty(refMdlToMdlBlk) && refMdlToMdlBlk.isKey(mdlH)
        loopBH = refMdlToMdlBlk(mdlH);
    else
        copyPath = '';
        return
    end
    bP = Simulink.ID.getFullName(loopBH);
    bObj = get(loopBH,'Object');
    if bObj.isSynthesized
        pObj = bObj.getParent;
        if ~isempty(pObj) ...
                && pObj.isSynthesized...
                && strcmp( get(pObj.getOriginalBlock,'BlockType'),'ModelReference')
            % If synthesized subsystem is created, we should map back to
            % referenced model.
            bP = getfullname(pObj.Handle);
        end
    end
    blockPath = [bP; blockPath]; %#ok<AGROW>
    mdlH = bdroot(loopBH);
    mdlNames = [get(mdlH,'Name'); mdlNames]; %#ok<AGROW>
end
% For Subsystem mapping, the mapping should be done from selected subsystem
% to an extracted subsystem. 
if map2Subsystem
    if length(mdlNames) == 1 ... % sys and bh is in the same model 
            && isempty(strfind(blockPath{1},sys)) % bh is not under sys.
        % This block path is for harness parts for dynamic slicing.
        copyPath = '';
        return
    end
    mdlNames{1} = get_param(sys, 'Parent');
end
copyPath = computeBlockCopyPath(blockPath, mdlNames, mdlCopy);

try
    if ~strcmpi(get_param(copyPath,'Type'),'block')
        %g1494705: Annontation has the same name as a
        %removed subsystem, and maps to the same path
        %in the sliced model.
        copyPath = '';
    end
catch Mex
    %Due to blocks that have been removed
    copyPath = '';
end
end

function copyPath = computeBlockCopyPath(blockPath, mdlNames, mdlCopy)
assert(length(blockPath) >= 1);
relPath = cell(length(blockPath), 1);

for i=1:length(blockPath)
    % Strip out the model name 
    n = length(mdlNames{i});
    relPath{i} = blockPath{i}(n+1:end);
end
% copyPath = strcat(mdlCopy, relPath{:});
%% Cannot use strcat because it removes trailing whitespaces
copyPath = mdlCopy;
for i=1:numel(relPath)
    copyPath = [copyPath relPath{i}]; %#ok<AGROW>
end
end
