classdef (Hidden = true) XILSubsystemUtils < handle
%XILSUBSYSTEMUTILS - utility class for XIL Subsystem workflows
%
%   This is an undocumented class. Its methods and properties are likely to
%   change without warning from one release to the next.
    
%   Copyright 2020-2023 The MathWorks, Inc.

    methods (Static)
        function res = isAtomicSubsystem(harnessModel)
            % given a harnessModel, return true if the Atomic subsystem
            % workflow is active
            res = coder.connectivity.XILSubsystemUtils.isMatchingWorkflow(...
                harnessModel, 'Atomic');
        end
        
        function res = isRLS(harnessModel)
            % given a harnessModel, return true if the RLS workflow is 
            % active
            res = coder.connectivity.XILSubsystemUtils.isMatchingWorkflow(...
                harnessModel, 'ReusableLibrary');
        end
        
        function res = isSubsystemWorkflow(harnessModel)
            % given a harnessModel, return true if any subsystem workflow 
            % is active
            res = coder.connectivity.XILSubsystemUtils.isMatchingWorkflow(...
                harnessModel, {'Atomic', 'ReusableLibrary'});
        end
        
         function validName = getValidSubsystemName(name)
            % make sure we use a valid name for the subsystem folder, use
            % hex replacement style so that, e.g. subsystem! and subsystem?
            % generate two different names
            validName = matlab.lang.makeValidName(name, 'ReplacementStyle', 'hex');
         end
        
         function [xilMdlRefs, xilSimModes] = updateModelRefList(harnessModel, ...
                 silMdlRefs, pilMdlRefs)

             if coder.connectivity.XILSubsystemUtils.isAtomicSubsystem(harnessModel)
                 % If this is a simulation for Atomic Subsystem, we need to
                 % redirect the model reference update from the hidden 
                 % model to the model under test, i.e. the model that 
                 % generates code for the subsystem under test.
                 % In this workflow only one model block is expected.
                 assert(isscalar([silMdlRefs pilMdlRefs]), ...
                    'Exactly one model block should be present at this stage');
                 harnessInfo = Simulink.harness.internal.getHarnessInfoForHarnessBD(harnessModel);
                 modelUnderTest = harnessInfo.model;
                 if ~isempty(silMdlRefs)
                     silMdlRefs = {modelUnderTest};
                     pilMdlRefs = {};
                 else
                     silMdlRefs = {};
                     pilMdlRefs = {modelUnderTest};
                 end                
             end

             xilMdlRefs = [silMdlRefs pilMdlRefs];

             % Simulation mode for each model SIL or PIL model block
             xilSimModes = [...
                 repmat(...
                 {Simulink.ModelReference.internal.SimulationMode.SimulationModeSIL}, ...
                 size(silMdlRefs)) ...
                 repmat(...
                 {Simulink.ModelReference.internal.SimulationMode.SimulationModePIL}, ...
                 size(pilMdlRefs))];

         end
         
         function hasEntryPoint = hasEntryPoint(ssInterface)
             % return a boolean to flag if the subsystem interface contains
             % at least one (active or non-active) entry point
             hasEntryPoint = ~isempty(rtw.connectivity.CodeInfoUtils.getEntryPoints(ssInterface));
         end

         function hasActiveEntryPoint = hasActiveEntryPoint(ssInterface)
             % return a boolean to flag if the subsystem interface contains
             % at least one valid entry point
             stopAtFirst = true;
             hasActiveEntryPoint = ~isempty( ...
                 rtw.connectivity.CodeInfoUtils.getActiveEntryPoints( ...
                 ssInterface, stopAtFirst));
         end

         function [isAtomicWorkflow, entryPoints] = getEntryPointsForAtomicSusbystemCoverage(harnessModel, modelName, buildInfoInstr)

             entryPoints = {};
             isAtomicWorkflow = coder.connectivity.XILSubsystemUtils.isAtomicSubsystem(harnessModel);
             if isAtomicWorkflow
                 buildDir = buildInfoInstr.getLocalBuildDir();
                 codeDesc = coder.getCodeDescriptor(fullfile(buildDir, 'codedescriptor.dmr'));
                 harnessInfo = Simulink.harness.internal.getHarnessInfoForHarnessBD(harnessModel);
                 sid = get_param(harnessInfo.ownerHandle, 'SID');

                 subsysInter = coder.connectivity.SubsystemCodeDescriptorUtils. ...
                     getInterfaceForSubsystem([modelName ':' sid], codeDesc);

                 allFunctionInterfaces = ...
                     rtw.connectivity.CodeInfoUtils.getActiveEntryPoints(subsysInter);
                 numFunctions = numel(allFunctionInterfaces);
                 entryPoints = cell(numFunctions, 1);
                 allSrcs = buildInfoInstr.getSourceFiles(1,1);
                 for idx = 1:numFunctions
                     currFcn = allFunctionInterfaces{idx};
                     entryPoints{idx}{1} = coder.internal.CodeDescriptorUtils.computeFunctionKey(currFcn);
                     currFileName = currFcn.Prototype.SourceFile;
                     srcIdx = contains(allSrcs, currFileName);
                     assert(any(srcIdx), 'could not map codedescriptor source to buildInfo');
                     % assign filename  to corresponding fullfile path
                     entryPoints{idx}{2} = allSrcs{srcIdx};
                 end
             end
         end

         function res = isTopLevelBuildForATS(parentModel)
             res = strcmp(get_param(parentModel, 'XILComponentBuildForATS'), 'on');
         end
     end

    
    methods(Static, Access = private)
        
        function res = isMatchingWorkflow(harnessModel, workflow)
            res = false;
            if ~isempty(harnessModel) 
                mgr = Simulink.PluginMgr;
                res = ismember('XILSubsystemPlugin', mgr.getRegisteredPluginsID) && ...
                    any(strcmp(get_param(harnessModel, 'XILSubsystemWorkflow'), workflow));
            end
        end
    end
end
