function FixPartiallyRemovedSubsysPorts(sliceXfrmr, mdl, cachePortInfo)
% This is a brute force inefficient algorithm for retaining port 
% positions based on the current implementation where you do not know 
% which ports to retain.  
%
% In the future this algorithm shouldcan be eliminate by extending the model IR 
% to include  virtual blocks and then using that information to tag the 
% port blocks that should be retained.  This will eliminate the need to compute
% a bounding extent for a system.

%   Copyright 2014 The MathWorks, Inc.
    
    origSubsysHs = cachePortInfo.keys();
    hasChanges = false;
    
    
    for idx=1:numel(origSubsysHs)
        origH = origSubsysHs{idx};
        
        startX = NaN;
        startY = NaN;
        
        if valid_handle(origH)
            blockIndex = 1;
            
            cPortInfo = cachePortInfo(origH);
            portInfo = get_param(origH,'PortHandles');
            
            % Inputs
            inPorts = portInfo.Inport;
            origInports = cPortInfo.Inport;
            if (numel(inPorts)>0 && numel(inPorts)<numel(origInports))
                [matches,indices] = ismember(inPorts, origInports);
                
                % We require the remaining ports to match their original handles
                if (all(matches))
                    update_start_point(origH);
                    missingPortIndices = setdiff(1:numel(origInports),indices);
                    addDummyPorts(origH, missingPortIndices,'in');
                    hasChanges = true;
                end
            end
            
            % Outputs
            outPorts = portInfo.Outport;
            origOutports = cPortInfo.Outport;
            if (numel(outPorts)>0 && numel(outPorts)<numel(origOutports))
                [matches,indices] = ismember(outPorts, origOutports);
                
                % We require the remaining ports to match their original handles
                if (all(matches))
                    update_start_point(origH);
                    missingPortIndices = setdiff(1:numel(origOutports),indices);
                    addDummyPorts(origH, missingPortIndices,'out');
                    hasChanges = true;
                end
            end
        end
    end
    

    if hasChanges
         Transform.fixAllDisconnectedPorts(sliceXfrmr, mdl, true);
    end
    
    
    function update_start_point(sysH)
        if ~isnan(startY)
            return;
        end
        
       
        % Expensive and painful but what can we do?
        sysObj = get_param(sysH,'Object');
        childObjs = sysObj.getChildren();
        
        if isa(childObjs(1),'Stateflow.Chart')
            p = childObjs(1).getParent();
            sysExtent = p.Position;
        else
            sysExtent = childObjs(1).Position;
        end
        
        for k=2:numel(childObjs)
            if isa(childObjs(k),'Stateflow.Chart')
                p = childObjs(k).getParent();
                childPos = p.Position;
            elseif strncmp(class(childObjs(k)),'Simulink',8) && strcmp(childObjs(k).Type, 'block')
                childPos = childObjs(k).Position;
            else
                break;
            end
            
            sysExtent = [min(sysExtent(1:2), childPos(1:2)) max(sysExtent(3:4), childPos(3:4))];
        end
        
        startY = sysExtent(1) - 30;
        startX = sysExtent(2);
    end
    
    
    
    function blockPos = next_blockPos()
        
        width = 5;
        height = 5;
        
        sepX = 15;
        
        blockIndex = blockIndex+1;
        left = startX + (blockIndex-1)*(width+sepX);
        top = startY;
        
        blockPos = [left top left+width  top+height];
    end


    function addDummyPorts(origH, missingPortIndices, ty)
        
        sysName = getfullname(origH);
        
        for ind = missingPortIndices
            
            switch(ty)
            case 'in'
                blkName = sprintf('_i%d_', blockIndex);
                blkSrc = 'built-in/Inport';
            case 'out'
                blkName = sprintf('_o%d_', blockIndex);
                blkSrc = 'built-in/Outport';
            end
            blockPos = next_blockPos();
            
            sliceXfrmr.addBlock( blkSrc, ...
                      [ sysName '/' blkName], ...
                      'MakeNameUnique',         'on', ...
                      'ForegroundColor',        'white', ...
                      'BackgroundColor',        'white', ...
                      'Position',               blockPos, ...
                      'Port',                   num2str(ind), ...
                      'ShowName',               'off');
            
        end            
    end
    
end





function out = valid_handle(blkH)
    try
        name = get_param(blkH,'Name');  %#ok<NASGU>
        out = true;
    catch Mex                           %#ok<NASGU>
        out = false;
    end
end    
    
