% CopyToOrigMap maps block handles in the copied model to the ones in the
% original model
%
% See also MappingUtil

%   Copyright 2014-2021 The MathWorks, Inc.

classdef CopyToOrigMap < 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.
    
    % A simple block-to-block mapper based on block path
    properties
        sysToMdl  % (path of system) => handle of model
        mdlCopy
        mdl
        map2Subsystem = false;
    end
    
    
    methods
        % Constructor
        function obj = CopyToOrigMap(mdl, mdlCopy, refMdlToMdlBlk)
            assert(ischar(mdlCopy));
            import Transform.*
            
            if isempty(strfind(mdl,'/'))
                obj.map2Subsystem = false;
            else
                obj.map2Subsystem = true;
            end
            util = MappingUtil(mdl, mdlCopy, refMdlToMdlBlk, obj.map2Subsystem);
            
            refMdls = [];
            mdlBlks = [];
            if ~isempty(refMdlToMdlBlk)
                refMdls = refMdlToMdlBlk.keys;
                mdlBlks = refMdlToMdlBlk.values;
            end
            sysPaths = {};
            delIdx = false(size(refMdls));
            for i=1:numel(mdlBlks)
                thisPath = util.getCopyPath(mdlBlks{i});
                if ~isempty(thisPath)
                    sysPaths = [sysPaths; thisPath]; %#ok<AGROW>
                else
                    % For subsystem slicing, if selected subsystem is under
                    % a child model, a path to a parent model returns
                    % empty and we remove those entries.
                    delIdx(i) = true;
                end   
            end
            if ~isempty(sysPaths)
                refMdls(delIdx) = [];
                obj.sysToMdl = containers.Map(sysPaths, refMdls);
            end
            obj.mdlCopy = mdlCopy;
            obj.mdl = mdl;
        end
        

        function bh = getOriginalBlock(obj, copyBH)
            copyName = Simulink.ID.getFullName(copyBH);
            util = BlockPathUtil;
            names = util.splitPath(copyName);
            n = length(names);
            bh = -1;
            
            blkInMdlref = false; % Assume
            if ~isempty(obj.sysToMdl)
                for i= n-1:-1:1
                    sysPath = util.getPath(names(1:i));
                    if obj.sysToMdl.isKey(sysPath)
                        origBP = util.getPath(names(i+1:end));
                        refMdl = obj.sysToMdl(sysPath);
                        refMdlName = get(refMdl, 'Name');
                        try
                            bh = get_param([refMdlName '/' origBP], 'Handle');
                            blkInMdlref = true;
                            break;
                        catch
                            continue;
                        end
                    end
                end
            end
            if ~blkInMdlref
                if ~obj.map2Subsystem
                    try
                        bn = util.getPath([obj.mdl; names(2:end)]);
                        bh = get_param(bn, 'Handle');
                    catch
                        bh = [];
                    end
                else
                    % Subsystem mapping
                    sysLen = length(util.splitPath(obj.mdl));
                    bn = util.getPath([obj.mdl; names(sysLen+2:end)]);
                    try
                        bh = get_param(bn, 'Handle');
                    catch
                        bh = [];
                    end
                end
            end
        end
        
    end
    
end

