
%

%   Copyright 2013-2020 The MathWorks, Inc.

classdef InactiveSwitch < Transform.AbstractTransform
    properties
        pivotBlockType = 'Switch';
        redundant = [];
    end
    methods
        function yesno = applicable(obj, bh, cvd)
            yesno = strcmp(get(bh,'BlockType'), 'Switch');
        end

        function [inactiveV, inactiveE, contextH] = analyze(obj, bh, mdl, cvd, ~)
        %  Make sure the model is in compiled stage
            obj.model = mdl;

            unc = getInactiveSwitchInputs(bh, cvd);

            inactiveV = [];
            inactiveE = getInactiveInputs(unc);

            if isempty(obj.uncovered)
                obj.uncovered = unc;
            else
                obj.uncovered = [obj.uncovered unc];
            end

            contextH = [];
        end


        function obj = InactiveSwitch()
        % Constructor
            obj.uncovered= struct('handle', {}, 'index', {});
        end

        function transform(~, ~, ~)
        % Nothing to do
        end
        function transformCopy(~, ~, ~, ~, ~)
        % Nothing to do
        end
        
        function reset(this)
            this.redundant = [];
            this.uncovered = [];
        end
    end

    properties
        % State variables
        uncovered

        % constant properties
        model
    end

end

function uncovered = getInactiveSwitchInputs(bh, cvd)
    import Analysis.*;

    unc= struct('handle', {}, 'index', {});
    uncovered = unc(1:-1); % Empty structure

    % Switch block can be bus-expanded, use the original block to get
    % decision coverage info
    obj = get(bh,'Object');
    if obj.isSynthesized
        origBlock = obj.getTrueOriginalBlock;
    else
        origBlock = bh;
    end


    [~, detail] = cvd.getDecisionInfo(origBlock);
    % xxx(investigate)
    % Toyota benchmark model returns empty for a switch block.
    if ~isempty(detail)
        d = getActivities(detail);
        for j=1:numel(d)
            if ~d(j)
                % If one of the outcome is never executed
                % mark it as uncovered and remove the
                % corresponding edge
                [ blkH, idx] = getIncome(bh, j);
                if ~isempty(blkH)
                    s = struct('handle', bh, 'index', idx);
                    uncovered(end+1) = s; %#ok<AGROW>
                end
            end
        end
    end

end

function d = getActivities(detail)
% Create a D (n * m) matrix where n is the number of decision points
% and m is the number of outcome
    n = length(detail.decision);
    m = length(detail.decision(1).outcome);

    D = false(n,m);
    for i = 1:length(detail.decision)
        for j=1:length(detail.decision(i).outcome)
            D(i,j) = detail.decision(i).outcome(j).executionCount > 0;
        end
    end
    d = any(D, 1);
end

function E = getInactiveInputs(switches)
%
    E = [];
    if ~isempty(switches)
        % identify dead branches in switches
        for i=1:length(switches)
            bh = switches(i).handle;
            idx = switches(i).index;

            ph = get(bh, 'PortHandles');
            inportH = ph.Inport(idx);
            E = [E;inportH];
        end
    end
end
