% The decision-table package is the easiest way to generate tables in the Decision Model and Notation (DMN) format.
%
%% decision-table.sty
%% Copyright 2020 Simon Vandevelde
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status “maintained”.
% 
% The Current Maintainer of this work is Simon Vandevelde.
%
% This work consists of the file decision-table.sty
%
%% This package creates the \dmntable command.
%% Requires the following input:
%%   1: table title
%%   2: hit policy
%%   3: input columns, separated by commas (e.g. 'weight, length')
%%   4: output columns, separated by commas (e.g. 'BMI')
%%   5: cell values, separated by commas (e.g. '>80, ---, weight/length*length,
%
%% The package depends on two other packages: 'colortbl' and 'booktabs'.

\ProvidesPackage{decision-table}[2020/08/22 v0.0.2 LaTeX package for DMN]


\RequirePackage{colortbl}  % Color in the cells.
\RequirePackage{booktabs}  % Special header format.


\definecolor{inputgreen}{RGB}{182, 215, 168}
\definecolor{inputblue}{RGB}{207, 226, 243}
\definecolor{glossaryorange}{RGB}{255, 123, 89}
\definecolor{executered}{RGB}{236, 155, 164}
\newcommand{\inputcol}[1]{\cellcolor{inputgreen} \textbf{#1}}
\newcommand{\outputcol}[1]{\cellcolor{inputblue} \textbf{#1}}
\newcommand{\glossarycol}[0]{\cellcolor{glossaryorange}}
\newcommand{\executecol}[0]{\cellcolor{executered}}
\newcommand{\dmnfont}[0]{\fontsize{7}{9} \fontfamily{put} \selectfont \setlength{\belowrulesep}{0pt}}

% Code to iterate over strings separated by comma's and executing a macro on each of them.
\makeatletter

% Functional foreach construct 
% 1 - Function to call on each comma-separated item in param 3
% 2 - Parameter to pass to function in param 1 as first parameter
% 3 - Comma-separated list of items to pass as second parameter to function in param 1
\def\foreach#1#2#3{%
  \@test@foreach{#1}{#2}#3,\@end@token%
}

% Internal helper function - Eats one input
\def\@swallow#1{}

% Internal helper function - Checks the next character after param 1 and param 2 and 
% continues loop iteration if \@end@token is not found 
\def\@test@foreach#1#2{%
  \@ifnextchar\@end@token%
    {\@swallow}%
    {\@foreach{#1}{#2}}%
}

% Internal helper function - Calls 1{2}{3} and recurses
% The magic of splitting the third parameter occurs in the pattern matching of the \def
\def\@foreach#1#2#3,#4\@end@token{%
  #1{#2}{#3}%
  \@test@foreach{#1}{#2}#4\@end@token%
}

%%% Macro's which are used in the above iteration function.
% Formats the inputcol as "\& \inputcol('input')".
\def\makeinputcol#1#2{&\inputcol{#2}}
% Formats the outputcol as "\& \outputcol('output')".
\def\makeoutputcol#1#2{&\outputcol{#2}}

\def\makecol#1#2{  % Format the cells. Needs to add in \\\hline after the right amount of cells.
    \ifnum\colcounter=\nbcols%  If we're at the end of a row, reset the counter and add the \\\hline
        \global\colcounter=0\relax
        \uppercase{\\} \hline \the\rowcounter
        \global\advance\rowcounter by 1
    \else
    \fi%5
    \global\advance\colcounter by 1
    \uppercase{&} {#2}
}

% Increments the counters by one, in order to count inputs or outputs using the above loop function.
\def\countinput#1#2{\global\advance\nbinputs by 1\relax}
\def\countoutput#1#2{\global\advance\nboutputs by 1\relax}

\makeatother

% Command to create a DMN table in a tabular environment.
% Requires the following input:
%   1: table title
%   2: hit policy
%   3: input columns, separated by commas (e.g. 'weight, length')
%   4: output columns, separated by commas (e.g. 'BMI')
%   5: cell values, separated by commas (e.g. '>80, ---, weight/length*length,
%                                               <80, ---, length/weight*weight')
\newcommand{\dmntable}[5]{
    % Create and instantiate counters.
    \newcount{\nbinputs}
    \newcount{\nboutputs}
    \newcount{\nbcols}  % The width of a table.
    \newcount{\colcounter}
    \newcount{\rowcounter}
    \nbinputs=0\relax
    \nboutputs=0\relax
    \nbcols=0\relax
    \colcounter=0\relax
    \rowcounter=2\relax

    \newcount\X
    {
        % Set the correct font.
        \dmnfont

        % Count the amount of inputs and outputs.
        \foreach{\countinput}{}{#3}
        \foreach{\countoutput}{}{#4}
        % Sum them together to find the number of columns of the table.
        \advance\nbcols by \nbinputs
        \advance\nbcols by \nboutputs

        % X is the first index number, always 1.
        \X=1
        \advance\nbinputs by 1\relax  % To make space for the index
        \begin{tabular}{|r|*{\nbcols}{l|}}
            \expandafter\cmidrule{1-\nbinputs}  % Makes sure the top hline is not the full width.
            \multicolumn{\nbinputs}{|l|}{#1} & \multicolumn{\nboutputs}{c}{}\\ % Set the input and output as multicolumn.
            \hline
            #2 \foreach{\makeinputcol}{}{#3} \foreach{\makeoutputcol}{}{#4} \\ % Generate input and outputheaders.
            \hline
            \the\X \foreach{\makecol}{}{#5} \\  % Generate the cell values
            \hline
        \end{tabular}
    }
}

\endinput
%%%
%%% End of file 'dmn.sty'
