function [template,info] = findTemplates(name,varargin)
% findTemplates - Find templates with specified properties
%
% [template,info] = Simulink.findTemplates(templatename) returns the names
% and TemplateInfo objects for all templates with names which match
% templatename. templatename is a string specifying a portion of a file
% name, which can contain the wildcard asterisk character "*". template is
% a cell array of strings specifying the absolute paths of matching
% templates, or empty if no templates are found. info is a cell array of
% sltemplate.TemplateInfo objects, or empty if no templates are found.
%
% [template,info] = Simulink.findTemplates(templatename,Name,Value) also
% specifies additional template properties as one or more Name, Value pair
% arguments. Options are: Type, Title, Group, Author, Description.  The
% supplied string Value is treated as a regular expression.
%
% Examples:
%
%   filename = Simulink.findTemplates('factory_default_model');
%
% Returns the full path to Simulink's default model template.
%
%   [filename,info] = Simulink.findTemplates('dsp*','Type','Model');
%   
% Returns the paths to all DSP model templates, and sltemplate.TemplateInfo
% objects for each of them.
%
%   filename = Simulink.findTemplates('work/')
%
% Returns all templates inside folders calls "work".
%
%   filename = Simulink.findTemplates('*','Author','Smith')
%
% Returns all templates for which the "Author" property includes the
% string "Smith".
%
% See also: Simulink.createFromTemplate

%   Copyright 2015-2018 The MathWorks, Inc.

narginchk(1,Inf);
name = char(name);

has_opts = nargin>1;
if has_opts
    p = inputParser;
    p.StructExpand = true;
    p.addParameter('Type','',@isscalarstring);
    p.addParameter('Group','',@isscalarstring);
    p.addParameter('Title','',@isscalarstring);
    p.addParameter('Author','',@isscalarstring);
    p.addParameter('Description','',@isscalarstring);
    p.parse(varargin{:});
    opts = p.Results;
end

function b = isscalarstring(v)
    b = ischar(v) || (isstring(v) && numel(v)==1);
end

% Get all templates, including "session templates"
all_info = num2cell(sltemplate.internal.Registrar.getAllTemplates);
all_templates = cellfun(@(x) x.FileName, all_info, 'UniformOutput', false);

if any(name=='/') || any(name==filesep) || any(name=='.')
    % Select templates for which the fully qualified file name matches
    % this pattern.
    match = regexp(all_templates,i_createPattern(name));
    match = ~cellfun(@isempty,match);
else
    % Select templates for which the "stem" part of the file name matches
    % this pattern.
    pattern = ['^' i_createPattern(name) '$'];
    match = false(size(all_templates));
    for i=1:numel(all_templates)
        [~,n] = fileparts(all_templates{i});
        if ~isempty(regexp(n,pattern,'once'))
            match(i) = true;
        end
    end
end

template = all_templates(match);
info = all_info(match);

% Now check against additional input arguments.
if has_opts
    match = true(size(template));
    fields = fieldnames(opts);
    for k=1:numel(fields)
        f = fields{k};
        optval = opts.(f);
        if isempty(optval)
            continue;
        end
        for i=1:numel(template)
            ti = info{i};
            if match(i) && isempty(regexpi(ti.(f),optval))
                % Not a match.
                match(i) = false;
            end
        end
    end
    template = template(match);
    info = info(match);
end

if numel(template)>1
    % To avoid the output depending on the order of entries in the cache,
    % sort results alphabetically by file name.
    [template,order] = sort(template);
    info = info(order);
end

info = cellfun(@(r){sltemplate.TemplateInfo(r)}, info);

end

function pattern = i_createPattern(original)
% We allow an asterisk as a wildcard.  Turn that into a regular expression
% by prefixing a dot.  Also escape dots, slashes and other regexp reserved characters.
reserved = {'\', '/', '.', '$', '[', ']', '(', ')', '{', '}', '+', '?', '|', '<', '>', '-', '&'};
escapedReserved = cellfun(@(rc) ['\' rc], reserved, 'UniformOutput', false);
pattern = string(original).replace(reserved, escapedReserved);
pattern = char(pattern.replace('*', '.*'));
end

