classdef CoderInstrumentationInfo < handle
% CODERINSTRUMENTATIONINFO provides an API to manage with 
% profiling_info.mat
% xxx(g928770, g1434797) - common API between this file and
% codeInstrPostCodeGen.m 

    %   Copyright 2013-2020 The MathWorks, Inc.
    methods (Static, Access = 'private')

        % this function accepts the path that is relative to the 
        % directory where generated code is kept
        function infoData = readInfo(MATDir, lCheckSimulinkFileGenControl)
            infoData = [];
            
            info_mat = fullfile(MATDir, 'profiling_info.mat');
            if ~exist(info_mat, 'file')
                % if the file doesn't exist try to create a full path
                % from the code gen folder in Simulink.fileGenControl
                if lCheckSimulinkFileGenControl
                    cfg = Simulink.fileGenControl('getConfig');
                    codeGenFolder = cfg.CodeGenFolder;
                    if isempty(codeGenFolder)
                        codeGenFolder = pwd;
                    end
                else
                    codeGenFolder = pwd;
                end
                info_mat = fullfile(codeGenFolder, MATDir, 'profiling_info.mat');
                if ~exist(info_mat, 'file')
                    return; % should error here
                end
            end
            
            infoData = load(info_mat);
        end
    end
    
    methods (Static)
    
        function writeInfo(MATDir, infoData)
            infoTarget = fullfile(MATDir, 'profiling_info.mat');
            save(infoTarget, '-struct', 'infoData');
        end
        
        function probes = getProbesFromRegistries(MATDir, lSimulinkWorkflow)
            infoData = coder.profile.CoderInstrumentationInfo.readInfo(...
                MATDir, lSimulinkWorkflow);
            lGlobalRegistry = infoData.lGlobalRegistry;
            
            probes = lGlobalRegistry.getAllProbes;
        end
        
        function taskRegistry = getTaskRegistry(MATDir)
            infoData = coder.profile.CoderInstrumentationInfo.readInfo(MATDir, true);
            if isempty(infoData) || ~isfield(infoData, 'topLevelRegistry')
                taskRegistry = [];
            else
                taskRegistry = infoData.topLevelRegistry;
            end
        end
        
        function targetInfo = getTargetInfo(MATDir, lSimulinkWorkflow)
            infoData = coder.profile.CoderInstrumentationInfo.readInfo(...
                MATDir, lSimulinkWorkflow);
            if isempty(infoData)
                targetInfo = [];
            else
                targetInfo = infoData.targetInfo;
            end
        end
        
        function globalRegistry = getGlobalRegistry(MATDir, lSimulinkWorkflow)
            infoData = coder.profile.CoderInstrumentationInfo.readInfo(...
                MATDir, lSimulinkWorkflow);
            if isfield(infoData, 'lGlobalRegistry')
                globalRegistry = infoData.lGlobalRegistry;
            else
                globalRegistry = [];
            end
        end
        
        function enabled = isInstrumentationEnabled(MATDir, modelRefBuildDirs, ...
                                                    pathToAnchor, SILPILWrapperUtils, ...
                                                    refModelsWithProfiling)
            enabled = false;

            infoData = coder.profile.CoderInstrumentationInfo.readInfo(MATDir, true);
            if isfield(infoData, 'componentRegistries') && ...
                    ~isempty(infoData.componentRegistries)
                componentRegistries = infoData.componentRegistries;
                for i = 1 : length(componentRegistries)
                    reg = componentRegistries{i};
                    if reg.isActive(SILPILWrapperUtils) && reg.getProbeNumber > 0
                        enabled = true;
                        return;
                    end
                end
            end
            
            lCodeInstrInfo = SILPILWrapperUtils...
                .getComponentArgs.getCodeInstrInfo;
            if isempty(lCodeInstrInfo)
                return;
            end
            
            modelRefRegistries =...
                coder.internal.getInstrRegistriesForRefModels(...
                    modelRefBuildDirs,...
                    lCodeInstrInfo, ...
                    pathToAnchor, ...
                    refModelsWithProfiling);
            for i = 1 : length(modelRefRegistries)
                reg = modelRefRegistries{i};
                if reg.isActive(SILPILWrapperUtils) && reg.getProbeNumber > 0
                    enabled = true;
                    return;
                end
            end

        end
        
        function setTaskRootBlockPath(MATDir, blockPath)
            infoData = coder.profile.CoderInstrumentationInfo.readInfo(MATDir, true);
            if ~isempty(infoData) && isfield(infoData, 'lGlobalRegistry') &&...
                    ~isempty(infoData.lGlobalRegistry)
                infoData.lGlobalRegistry.setTaskRootBlockPath(blockPath);
                
                coder.profile.CoderInstrumentationInfo.writeInfo(MATDir, infoData);
            end                
        end
                
        function addComponentRegistry(MATDir, registry, lSimulinkWorkflow)
            % the registry must be instance of ProbeComponentRegistry
            validateattributes(registry, {'coder.profile.ProbeComponentRegistry'}, {});
            if nargin < 3
                lSimulinkWorkflow = true;
            end

            infoData = coder.profile.CoderInstrumentationInfo.readInfo(...
                MATDir, lSimulinkWorkflow);
            if isempty(infoData)
                infoData.componentRegistries = {};
            end

            infoData.componentRegistries{end+1} = registry;

            coder.profile.CoderInstrumentationInfo.writeInfo(MATDir, infoData);
        end
        
        function updateExistingRegistries(MATDir)
            infoData = coder.profile.CoderInstrumentationInfo.readInfo(MATDir, true);
            if isfield(infoData, 'componentRegistries') && ...
                    ~isempty(infoData.componentRegistries)
                componentRegistries = infoData.componentRegistries;
                for i = 1 : length(componentRegistries)
                    reg = componentRegistries{i};
                    reg.checkRegisteredProbes;
                end
            end
        end

    end
    
end
