function tagStruct = parseTags(directory, varargin)
% parse m-files in directory and prints tagged comments
%
% Syntax: parseTags(directory, 'option-name', value)
%   or:   parseTags
%
% Call parseTags('demo') for a demonstration. By, default the current
%   directory and all subdirectories are scanned for the known tags:
%     o info (or comment)
%     o todo
%     o debug (or dbg)
%     o dev (or devel).
%
% The following option/value pairs are supported:
%  'knownTags' - a cell array of possible tag names in a simple form like
%     {'tag1', 'tag2'} or in a form with alternatives like {{'tag1', 'a1'},
%     {'tag2', 'a2', b2'}}. The alternatives are detected but are not
%     distinguished in the output. When no known tagname is found, the
%     first named tag is used.
%  'openTag' - regex string for the opening of a tagged comment
%  'closeTag' - regex string for closing a tagged comment

% MDT: MATLAB developement toolbox - for the everyday programmer
%   Copyright (C) 2013 Alexander Reinhold
%
% This program is free software: you can redistribute it and/or modify it 
%   under the terms of the GNU Lesser General Public License as published 
%   by the Free Software Foundation, either version 3 of the License, or 
%   (at your option) any later version.
%
% This program is distributed in the hope that it will be useful, but 
%   WITHOUT ANY WARRANTY; without even the implied warranty of 
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
%   Lesser General Public License for more details.
%
% You should have received a copy of the GNU Lesser General Public License 
%   along with this program.  If not, see <http://www.gnu.org/licenses/>.

%% set parameters
if nargin == 0, directory = cd;end
if strcmp(directory, 'demo')
    directory = which('parseTags');
    directory = [directory(1:end-11) filesep 'example'];
end
optionStruct = mapOptionStruct(varargin, ...
    'descend', -1, ...
    'knownTags', {{'info', 'comment'}, 'todo', {'debug', 'dbg'}, {'dev', 'devel'}}, ...
    'restrictedTags', [], ...
    'tagOpen', '[ \r\t]*%!\s*', ...
    'tagClose', '\s*%/[ \r\t]*');

%% handle knownTags & restrictedTags
% handle known tags
if ~iscell(optionStruct.knownTags)
    optionStruct.knownTags = {{optionStruct.knownTags}};
end
for iCell = 1:length(optionStruct.knownTags)
    if ~iscell(optionStruct.knownTags{iCell})
        optionStruct.knownTags{iCell} = optionStruct.knownTags(iCell);
    end
end
% handle restricted tags
if ~iscell(optionStruct.restrictedTags) && ischar(optionStruct.restrictedTags)
    optionStruct.restrictedTags = {optionStruct.restrictedTags};
end
% ensure restricted tag names are listed and assign numbers
restrictedVector = zeros(1, length(optionStruct.restrictedTags));
for iRestricted = 1:length(optionStruct.restrictedTags)
    nKnown = 0;
    for iKnown = 1:length(optionStruct.knownTags)
        for jKnown = 1:length(optionStruct.knownTags{iKnown})
            if strcmpi(optionStruct.knownTags{iKnown}{jKnown}, ...
                       optionStruct.restrictedTags{iRestricted})
                   nKnown = iKnown;
            end
        end
    end
    if nKnown ~= 0
        % restricted is a known tag name
        restrictedVector(iRestricted) = nKnown;
    else
        % new tag name must be stored
        optionStruct.knownTags = [optionStruct.knownTags ...
                                  {optionStruct.restrictedTags(iRestricted)}];
        restrictedVector(iRestricted) = length(optionStruct.knownTags);
    end
end
optionStruct.restrictedTags = restrictedVector;
% for iKnown = 1:length(optionStruct.knownTags)
%     disp(optionStruct.knownTags{iKnown})
% end
% restrictedVector
% return


%% get mfiles
if iscell(directory)
    mfiles = directory;
else
    mfiles = getFiles(directory, 'option', optionStruct);
end

%% gather tags from mfiles
tagStruct = getTags(mfiles, optionStruct);


%% output (or no output)
if nargout == 0
    printTags(tagStruct, mfiles, optionStruct.knownTags);
    clear tagStruct
end
