function this_dir = make_file_info(dir_path, token_expr, depth, subdir)
% this_dir.name
% this_dir.num_files
% this_dir.file.tokens
% this_dir.subdir
    
% Default tokens are the file name and extension
if nargin < 2
    % token_expr = '.*';
    token_expr = '^(.*)\.(.*)$';
end

if nargin < 3
    depth = Inf;
end

if nargin < 4
    subdir = '';
    this_dir.name = dir_path;
else
    this_dir.name = subdir;    
end
this_dir_path = fullfile(dir_path, subdir); % current path

%% Get matching files
% Get files (not '.' or '..') matching the regular expression
match_entry = dir_filter(this_dir_path, {...
    {'not_dir'}, ...
    {'name_not' , {'.', '..'}}, ...
    {'name_regexp' , token_expr}});

% Generate cell array of full file paths
if ~isempty(match_entry)
    this_dir.num_files = length(match_entry);
    for i = length(match_entry):-1:1
        matched_tokens = regexp(match_entry(i).name, token_expr, 'tokens');
        % There should only be one match
        assert(length(matched_tokens) == 1);
        % There can still be multiple tokens from a single match
        this_dir.file(i).tokens = matched_tokens{1};
    end
else
    this_dir.num_files = 0;
    this_dir.file  = [];
end

%% Check subdirectories
% If we have not reached the maximum depth
has_subdirs = 0;
if depth > 0
    % Decrement depth
    depth = depth - 1;

    % Get the sub directories (not '.' or '..')
    sub_dirs = dir_filter(this_dir_path, {...
        {'is_dir'}, ...
        {'name_not' , {'.', '..'}}});
    has_subdirs = ~isempty(sub_dirs);
    
    % For each subdirectory get the desired file paths
    for i = length(sub_dirs):-1:1
        % Compile the next dir path
        next_dir_path = fullfile(dir_path, subdir);
        
        % Get and append new file paths
        this_dir.subdir(i) = make_file_info(next_dir_path, token_expr, depth, sub_dirs(i).name);
        this_dir.num_files = this_dir.num_files + this_dir.subdir(i).num_files;
    end
end

if ~has_subdirs
    this_dir.subdir = [];
end

end
