classdef ToolchainInfoRegistry
%TOOLCHAININFOREGISTRY sl_customization/rtwtargetinfo registration class for
%ToolchainInfo
%
%   ToolchainInfoRegistry is an sl_customization registration class for
%   ToolchainInfo. You can use this class to create a custom tool
%   configuration.  To do this, you must edit an sl_customization.m file and
%   write the code that defines your tool configuration; you must
%   register the new TOOLSINFOREGISTRY object with a call to registerTargetInfo
%   inside the sl_customization.m file. A tool chain configuration must have a
%   unique name and be associated with a tool chain configuration class (a
%   subclass of coder.make.ToolchainInfo). Properties of the tool chain
%   configuration define the set of Simulink models/MATLAB Project that
%   it is compatible with.
%
%   See also CODER.MAKE.TOOLCHAININFO


%   Copyright 2011-2020 The MathWorks, Inc.

    % Note: ToolchainInfoRegistry does not inherit from handle; it is a value
    % class used to collect property values together. Copying the object
    % copies the property values (this behaviour is required by
    % RTW.TargetRegistry.addToolchainInfoRegistry so that the same handle
    % object doesn't get registered twice)

    properties
        % Unique string name for this configuration.
        Name = '';
        
        % Full path to file to load
        FileName = '';
        
        % Alternatively, you can give an handle to the object
        Handle = [];
                       
        % Cell array of strings listing Hardware Device Types that
        % support this configuration.
        %
        % An empty cell array matches any Hardware Device Type
        %
        % A model's "TargetHWDeviceType" Configuration Parameter will be
        % validated against this cell array to determine if this
        % configuration is valid for use.
        TargetHWDeviceType = {};
        
        % Cell array of strings listing platforms that
        % support this configuration.
        Platform = {};
    end
    
    properties (Hidden = true)        
        % An alias that can be used for display or shorthand.
        Alias = {};
        
        % Function handle that will be evaluated to determine if a model's
        % configuration set is compatible with this connectivity
        % configuration.
        %
        % The function handle should have the following signature:
        %
        % isConfigSetCompatible = HANDLE(configSet)
        %
        % configSet: Simulink.ConfigSet object, giving access
        %            to a model's configuration set.
        %
        % isConfigSetCompatible: logical value indicating whether this
        %                        connectivity configuration is compatible
        %                        with a model's configuration set.
        isConfigSetCompatibleFcn = [];
        
        % The MAT file where the ToolchainInfo object is stored.
        FileNameInfo = [];
        
        % Flag that indicates if toolchain is validated or not
        Validated = false;
        
        % The toolchain's validation report
        ValidationReport = '';
    end
    
    % property set method validation
    methods        
        function this = set.Name(this, Name)
            Name = convertStringsToChars(Name);
            this.checkNonEmptyString('Name', Name);
            this.Name = Name;
        end
        
        function this = set.Alias(this, NewAlias)
            NewAlias = convertStringsToChars(NewAlias);
	    if (~isempty(NewAlias))
		%Since Alias is optional, we should allow reset of Alias
            if isa(NewAlias, 'char')
            	this.checkNonEmptyString('Alias', NewAlias);
                NewAlias = {NewAlias};
            else
                this.checkCellofStrings('Alias', NewAlias);
            end
	    end
            this.Alias = NewAlias;
        end
        
        function this = set.FileName(this, FileName)
            FileName = convertStringsToChars(FileName);
            this.checkFileExists('FileName', FileName);
            this.FileName = FileName;
        end
                        
        function this = set.Handle(this, Handle)
            if ~isa(Handle, 'coder.make.ToolchainInfo')
                error(message('coder_compile:toolchain:BadHandleType','coder.make.ToolchainInfo'));
            end
            this.Handle = Handle;
        end
        
        function this = set.TargetHWDeviceType(this, TargetHWDeviceType)
            TargetHWDeviceType = convertStringsToChars(TargetHWDeviceType);
            if ischar(TargetHWDeviceType)
                TargetHWDeviceType = {TargetHWDeviceType};
            end
            this.checkCellofStrings('TargetHWDeviceType', TargetHWDeviceType);
            this.TargetHWDeviceType = TargetHWDeviceType;
        end        
        
        function this = set.Platform(this, Platform)
            Platform = convertStringsToChars(Platform);
            if ischar(Platform)
                Platform = {Platform};
            end
            this.checkCellofStrings('Platform', Platform);
            if numel(Platform)==1
                supportedPlatforms = {'win32','win64','glnxa64','maci64','*'};
            else
                supportedPlatforms = {'win32','win64','glnxa64','maci64'};
            end
            for i = 1:numel(Platform)
                if ~any(ismember(supportedPlatforms, Platform{i}))
                    if isequal(Platform{i}, '*')
                        error(message('coder_compile:toolchain:BadPlatformStar'));
                    end
                    error(message('coder_compile:toolchain:BadPlatform',Platform{i}));
                end
            end
            this.Platform = Platform;
       end
       
       function this = set.isConfigSetCompatibleFcn(this, isConfigSetCompatibleFcn)
            propStr = 'isConfigSetCompatibleFcn';
            if ~isa(isConfigSetCompatibleFcn, 'function_handle')
                error(message('coder_compile:toolchain:BadCompatibleFcn',propStr));                
            end
            this.isConfigSetCompatibleFcn = isConfigSetCompatibleFcn;
        end
        
        function tc = getToolchainInfo(this)
            %Always give preference to Handle.
            currentFileNameStatus = dir(this.FileName);
            if isempty(this.Handle) || isempty(this.FileNameInfo) || ~isequal(currentFileNameStatus,this.FileNameInfo)
                temp = load(this.FileName);
                variablesInTemp = fieldnames(temp);
                
                % Validate the contents of the toolchain mat file
                if numel(variablesInTemp) ~= 1
                    % The mat file must contain a single variable
                    DAStudio.error('coder_compile:toolchain:TooManyElementsInToolchainMATFile', this.FileName);
                elseif ~isa(temp.(variablesInTemp{1}), 'coder.make.ToolchainInfo')
                    % The variable must be a ToolchainInfo
                    DAStudio.error('coder_compile:toolchain:InvalidToolchainInMATFile', this.FileName)
                elseif numel(temp.(variablesInTemp{1})) ~= 1
                    % The variable must only contain one ToolchainInfo
                    DAStudio.error('coder_compile:toolchain:VectorToolchainInfoInMATFile', this.FileName);
                end
                
                tc = temp.(variablesInTemp{1});
                
                % Force the Name property to match the corresponding registry name
                tc.Name = this.Name;
                
                this.Handle = tc;
                this.FileNameInfo = currentFileNameStatus;
                tr = coder.targetreg.internal.TargetRegistry.getWithoutDataLoad();
                coder.make.internal.setToolchainInfo(tr, this);
            end
            tc = this.Handle;
            assert(isa(tc,'coder.make.ToolchainInfo') && isvalid(tc));
        end
    end
       
    methods (Access = 'private')
        function checkNonEmptyString(this, prop, propValue)  %#ok<INUSL>
            if isempty(propValue) || ~ischar(propValue)
                error(message('coder_compile:toolchain:BadStringType',prop));
            end
        end
        
        function checkFileExists(this, prop, propValue)
            this.checkNonEmptyString(prop, propValue);
            if (exist(propValue,'file') ~= 2)
                error(message('coder_compile:toolchain:BadToolchainMATFile', prop, propValue));
            end
        end
               
        function checkCellofStrings(~, prop, propValue)
            % check we have an empty or non-empty cell array
            if ~iscellstr(propValue)
                error(message('coder_compile:toolchain:BadCellType',prop));
            end
        end       
    end
end

% LocalWords:  rtwtargetinfo Toolchain TOOLSINFOREGISTRY TOOLCHAININFO
% LocalWords:  toolchain maci toolchain's
