function tcInfo = getToolchainInfo(sourceType, source, varargin)
%GETTOOLCHAININFO Get the ToolchainInfo object from a specified function or MAT file.
%   X=GETTOOLCHAININFO('filename', MAT_FILENAME) returns the ToolchainInfo object saved
%   in a MAT file.
%
%   X=GETTOOLCHAININFO('function_handle', FUNCTION_HANDLE) returns the
%   ToolchainInfo object generated when the function handle is invoked.
%
%   X=GETTOOLCHAININFO('function_name', FUNCTION_NAME) returns the
%   ToolchainInfo object generated when the function is invoked.
%
%   X=GETTOOLCHAININFO('toolchain_name', TOOLCHAIN_NAME) returns the
%   ToolchainInfo object associated with the given toolchain name.
%
%   X=GETTOOLCHAININFO('toolchain_name', TOOLCHAIN_NAME, TOOLCHAIN_ALIAS)
%   returns the ToolchainInfo object associated with the given toolchain
%   name and alias. 
%

% Copyright 2012-2020 The MathWorks, Inc.

tcInfo = [];

switch lower(sourceType)
    case 'function_name'
        % If a function name, convert it to a function handle
        fullFile = which(source);
        [~, ~, fext] = fileparts(fullFile);
        if any(strcmpi(fext, {'.m', '.p', ''}))
            source = str2func(source);
        end
        tcInfo = coder.make.internal.getToolchainInfo('function_handle', source, varargin{:});
        
    case 'function_handle'
        % Invoke the function handle
        try
            tcInfo = source();
        catch ex
            error(message('coder_compile:toolchain:ToolchainFuncHandleException', ...
                char(source), ex.message));
        end
        validateToolchainInfo(char(source), tcInfo, varargin{:});
        
    case 'filename'
        % If a MAT file, extract the ''tc'' variable from the MAT file
        [~, ~, fext] = fileparts(source);
        if strcmpi(fext, '.mat')
            if exist(source, 'file') ~= 2
                error(message('coder_compile:toolchain:NonexistentToolchainMATFile', ...
                    source));
            end
            var = load(source);
            if isfield(var, 'tc')
                tcInfo = var.tc;
            end
        end
        validateToolchainInfo(source, tcInfo, varargin{:});
        
    case 'toolchain_name'
        tcInfo = getFromToolchain(source, varargin{:});
        
    otherwise
        error(message('coder_compile:toolchain:InvalidGetToolchainInfoFirstArgument'));
end

% -------------------------------------------------------------------------
% Check the output if valid
% -------------------------------------------------------------------------
function validateToolchainInfo(source, tcInfo, option)
if isempty(tcInfo)
    error(message('coder_compile:toolchain:IncorrectToolchainRegistrationTool', source, source));
elseif ~isa(tcInfo, 'coder.make.ToolchainInfo')
    error(message('coder_compile:toolchain:IncorrectToolchainRegistrationToolOutput', source));
elseif numel(tcInfo)>1
    if ~(nargin>2 && strcmpi(option, 'allow-multiple'))
        error(message('coder_compile:toolchain:ToolchainRegistrationToolHasMultipleOutputs', source));
    end
end

% -------------------------------------------------------------------------
% Get the ToolchainInfo object associated with a specified toolchain.
% -------------------------------------------------------------------------
function tcInfo = getFromToolchain(tcName, varargin)

narginchk(0, 2);
if nargin==0
    tcName = '';
end
if ~isempty(tcName) && ~ischar(tcName)
    error(message('coder_compile:toolchain:InvalidToolchainNameFormat'))
end
if nargin>1 && ~ischar(varargin{1})
    error(message('coder_compile:toolchain:InvalidToolchainAliasFormat'))
end

% If default toolchain, get the equivalent toolchain name.
usingDefaultToolchain = isempty(tcName) || ...
    strcmpi(tcName, coder.make.internal.getInfo('default-toolchain'));
if usingDefaultToolchain
    tcName = coder.make.getDefaultToolchain();
end

% Get the ToolchainInfo object associated with this toolchain
tcInfo = coder.make.internal.getToolchainInfoFromRegistry(tcName, varargin{:});
if isempty(tcInfo)
    error(message('coder_compile:toolchain:ToolchainInfoNotFound', tcName));
end

% LocalWords:  Toolchain toolchain Func tc
