\RequirePackage{jbw-list}
\RequirePackage{ifthen}
\RequirePackage{jbw-prog-util}
\RequirePackage{pstricks}
\RequirePackage{jbw-load-pst-node}
\RequirePackage{jbw-parbox}

% Plain TeX dependencies: \newcount
% LaTeX internals dependencies:
%   \@namedef, \@nameuse, \@ifundefined, \@gobbletwo

% NODE is {NODE_TYPE}{LABEL}{TEXT}
% PRECEDENCE is {LABEL1}{LABEL2}{OPT_EDGE}
% OPT_EDGE is either empty (gets default behavior) or EDGE_TYPE

\newcount\jbwpd@ColumnA
\newcount\jbwpd@ColumnB
\newcount\jbwpd@HighestColumn

\newcommand{\PrecedenceDiagramTimeSep}{1.5cm}
\newcommand{\PrecedenceDiagramSimulSep}{0.4cm}
\newcommand{\PrecedenceDiagramNodeMaxWidth}{2.7cm}

\newcommand{\jbwpd@DiagramNumber}{0}

\newboolean{jbwpd@Horiz}

\newcommand{\jbwpd@StoreRegisterInMacroByName}[2]
  {% #1 is REGISTER
   % #2 is CS_NAME
   \Expand{\the#1}
     {% ##1 is the result of expanding \the#1
      \@namedef{#2}{##1}}}

\newcommand{\PrecedenceDiagram}[3][horiz]
  {% #1 is ORIENTATION
   % #2 is list of NODE
   % #3 is list of PRECEDENCE
   \hbox\bgroup
     \ifthenelse{\equal{#1}{horiz}}
       {\setboolean{jbwpd@Horiz}{true}}
       {\ifthenelse{\equal{#1}{vert}}
          {\setboolean{jbwpd@Horiz}{false}}
          {\PackageError{jbw-precedence-diagram}
           {Precedence diagram orientation must be either "horiz" or "vert".}
           {No additional help.}}}%
     %\TraceOn
     \dolist{#2}
       {}
       {% ##1 is {LABEL}{TEXT}
        \usetemplate{##1}
          {% ####1 is TYPE
           % ####2 is LABEL
           % ####3 is TEXT
           \@namedef{jbwpd@node@column@####2}{0}}}
       {}%
     \jbwpd@HighestColumn=0%
     %\TraceOn
     \jbwpd@ColumnA=\jbwpd@DiagramNumber\relax
     \advance\jbwpd@ColumnA by 1\relax
     \Expand{\the\jbwpd@ColumnA}
       {% ##1 is DIAGRAM_LABEL
        \global\def\jbwpd@DiagramNumber{##1}%
        \jbwpd@AssignColumns{#3}{#2}{##1}}}

\newboolean{jbwpd@ColumnsChanged}

\newcommand{\jbwpd@AssignSecondLabelHigherColumn}[2]
  {% #1 is LABEL1
   % #2 is LABEL2
   \jbwpd@ColumnA=\@nameuse{jbwpd@node@column@#1}\relax
   %\showthe\jbwpd@ColumnA
   %\TraceOn
   \IfNum{\jbwpd@ColumnA<\@nameuse{jbwpd@node@column@#2}\relax}
     {}
     {\advance\jbwpd@ColumnA by 1\relax
      \jbwpd@StoreRegisterInMacroByName{\jbwpd@ColumnA}{jbwpd@node@column@#2}%
      \IfNum{\jbwpd@HighestColumn<\jbwpd@ColumnA}
        {\jbwpd@HighestColumn=\jbwpd@ColumnA}
        {}%
      \setboolean{jbwpd@ColumnsChanged}{true}}}

\newcommand{\jbwpd@AssignColumns}[1]
  {% #1 is list of PRECEDENCE
   %\showthe\jbwpd@HighestColumn
   \setboolean{jbwpd@ColumnsChanged}{false}%
   \dolist{#1}
     {}
     {% ##1 is {LABEL1}{LABEL2}...
      \usetemplate{##1}
        {% ####1 is LABEL1
         % ####2 is LABEL2
         % ####3 is either empty or EDGE_TYPE
         \jbwpd@AssignSecondLabelHigherColumn{####1}{####2}}}
     {}%
   \ifthenelse{\boolean{jbwpd@ColumnsChanged}}
     {\jbwpd@AssignColumns{#1}}
     {\jbwpd@StartDiagram{#1}}}

\newcommand{\jbwpd@StartDiagram}[3]
  {% #1 is list of PRECEDENCE
   % #2 is list of NODE
   % #3 is DIAGRAM_LABEL
   %\TraceOn
   \ifthenelse{\boolean{jbwpd@Horiz}}
     {\hbox\bgroup\valign\bgroup\vfil##\vfil}
     {% For this case, we should probably also cancel the lineskip.
      % However, then we would have to reenable it inside the boxes.
      % And the boxes will usually be big enough that lineskip will
      % have no effect.  So we are lazy instead.
      \vbox\bgroup\halign\bgroup\hfil##\hfil}%
     % We are now inside the \bgroup, so stay indented.
     \cr
     \jbwpd@MakeColumns{0}{#2}{#3}{#1}}

\newcommand{\jbwpd@MakeColumns}[3]
  {% #1 is COL_NUMBER
   % #2 is list of NODE
   % #3 is DIAGRAM_LABEL
   \dolist{#2}
     {{true}}
     {% ##1 is {TYPE}{LABEL}{TEXT}
      % ##2 is IS_FIRST_ITEM
      \usetemplate{##1}
        {% ####1 is TYPE
         % ####2 is LABEL
         % ####3 is TEXT
         \edef\jbwpd@temp
           {\jbwpd@ColumnB=\@nameuse{jbwpd@node@column@####2}}%
         \jbwpd@temp
         \relax
         \IfNum{#1=\jbwpd@ColumnB}
           {\ifthenelse{\equal{##2}{true}}
              {}
              {\ifthenelse{\boolean{jbwpd@Horiz}}{\vskip}{\hskip}\PrecedenceDiagramSimulSep\relax}%
            \jbwpd@MakeNode{#3}{####1}{####2}{####3}%
            \DLNext{{false}}}
           {\DLNext{{##2}}}}}
     {}%
   \IfNum{#1<\jbwpd@HighestColumn}
     {\cr
      \noalign{\ifthenelse{\boolean{jbwpd@Horiz}}{\hskip}{\vskip}\PrecedenceDiagramTimeSep\relax}%
      \jbwpd@ColumnA=#1%
      \advance\jbwpd@ColumnA by 1\relax
      %\showthe\jbwpd@ColumnA
      \Expand{\the\jbwpd@ColumnA}
        {% ##1 is (COL_NUMBER + 1)
         \jbwpd@MakeColumns{##1}{#2}{#3}}}
     {\jbwpd@FinishDiagram{#3}}}

\newcommand{\jbwpd@AddHorizLinkPoints}[2]
  {% #1 is LABEL
   % #2 is CONTENT (horizontal material)
   \hbox
     {\rnode{jbwpdXstartX#1}{}%
      $\vcenter{\hbox{#2}}$%
      \rnode{jbwpdXendX#1}{}}}

\newdimen\jbwpd@savedlineskip
\newdimen\jbwpd@savedbaselineskip

\newcommand{\jbwpd@AddVertLinkPoints}[2]
  {% #1 is LABEL
   % #2 is CONTENT (horizontal material)
   $\vcenter
      {\jbwpd@savedlineskip=\lineskip
       \jbwpd@savedbaselineskip=\baselineskip
       \lineskip=0pt\relax
       \baselineskip=0pt\relax
       \halign{\hfil##\hfil\cr
            \rnode{jbwpdXstartX#1}{}%
         \cr\lineskip=\jbwpd@savedlineskip
            \baselineskip=\jbwpd@savedbaselineskip
            #2%
         \cr\rnode{jbwpdXendX#1}{}%
         \cr}}%
   $}

\newcommand{\jbwpd@MakeNode}[4]
  {% #1 is DIAGRAM_LABEL
   % #2 is TYPE
   % #3 is LABEL
   % #4 is TEXT
   %\TraceOn
   \ifthenelse{\boolean{jbwpd@Horiz}}
     {\jbwpd@AddHorizLinkPoints}
     {\jbwpd@AddVertLinkPoints}
   % Next two are arguments to command chosen by above ifthenelse
   {#1X#3}
   {\jbwpd@WrapNode{#2}{#3}%
      %{\begin{tabular}{@{}c@{}}#4\end{tabular}}%
      {\parboxwithmaxwidth{\PrecedenceDiagramNodeMaxWidth}{\centering#4}}%
   }%
  }

\newcommand{\DeclarePrecedenceDiagramNodeType}[2]
  {% #1 is NAME
   % #2 is DEFINITION
   \@namedef{jbwpd@ItemWrapper@#1}{#2}}

\DeclarePrecedenceDiagramNodeType{activity}{\fbox}
\DeclarePrecedenceDiagramNodeType{event}{\pscirclebox}
\DeclarePrecedenceDiagramNodeType{}{\hbox}
\DeclarePrecedenceDiagramNodeType{plain}{\hbox}
\DeclarePrecedenceDiagramNodeType{frame}{\fbox}
\DeclarePrecedenceDiagramNodeType{doubleframe}{\psdblframebox}
\DeclarePrecedenceDiagramNodeType{shadowframe}{\psshadowbox}
\DeclarePrecedenceDiagramNodeType{circle}{\pscirclebox}
\DeclarePrecedenceDiagramNodeType{oval}{\psovalbox}
\DeclarePrecedenceDiagramNodeType{diamond}{\psdiabox}
\DeclarePrecedenceDiagramNodeType{Rtriangle}{\pstribox[trimode=R]}
\DeclarePrecedenceDiagramNodeType{Utriangle}{\pstribox[trimode=U]}
\DeclarePrecedenceDiagramNodeType{Ltriangle}{\pstribox[trimode=L]}
\DeclarePrecedenceDiagramNodeType{Dtriangle}{\pstribox[trimode=D]}

% *** Should abstract commonality of \jbwpd@WrapNode and \jbwpd@DrawEdge.

\newcommand{\jbwpd@WrapNode}[3]
  {% #1 is TYPE
   % #2 is LABEL
   % #3 is CONTENTS (should emit a single box when executed)
   %\fbox{%
   \rnode{#2}%
     {%
      \IfBeginsWithStar{#1}
        {% ##1 is TYPE with leading * removed
         ##1}
        {\@ifundefined{jbwpd@ItemWrapper@#1}
           {\PackageError{jbw-precedence-diagram}
              {Undefined precedence diagram node type: #1}
              {No additional help.}}
           {\@nameuse{jbwpd@ItemWrapper@#1}}}
      % next line is argument of both branches of above \IfBeginsWithStar
      {#3}%
     }%
   %}%
  }

\newcommand{\DeclarePrecedenceDiagramEdgeType}[2]
  {% #1 is NAME
   % #2 is DEFINITION
   \@namedef{jbwpd@EdgeDrawer@#1}{#2}}

\DeclarePrecedenceDiagramEdgeType{}{\ncline[nodesep=3pt,arrows=->]}
\DeclarePrecedenceDiagramEdgeType{arrow}{\ncline[nodesep=3pt,arrows=->]}
\DeclarePrecedenceDiagramEdgeType{line}{\ncline[nodesep=3pt,arrows=-]}
\DeclarePrecedenceDiagramEdgeType{silent}{\@gobbletwo}

\newcommand{\jbwpd@DrawEdge}[1]
  {% #1 is EDGE_TYPE
   \IfBeginsWithStar{#1}
     {% ##1 is RAW_CODE
      ##1}
     {\@ifundefined{jbwpd@EdgeDrawer@#1}
        {\PackageError{jbw-precedence-diagram}
           {Undefined edge type: #1}
           {No additional help.}}
        {\@nameuse{jbwpd@EdgeDrawer@#1}}}}

\newcommand{\jbwpd@FinishDiagram}[2]
  {% #1 is DIAGRAM_LABEL
   % #2 is list of PRECEDENCE
       \cr
     \egroup\egroup % ends \?box\bgroup\?align\bgroup ...
     \dolist{#2}
       {}
       {% ##1 is {LABEL1}{LABEL2}{EDGE_TYPE}
        \usetemplate{##1}
          {% ####1 is LABEL1
           % ####2 is LABEL2
           % ####3 is EDGE_TYPE
           %\TraceExec
           \jbwpd@DrawEdge{####3}{jbwpdXendX#1X####1}{jbwpdXstartX#1X####2}}}
       {}%
   \egroup % ends \hbox\bgroup
  }

% Local variables:
% tex-main-file: "jbw-precedence-diagram-test.tex"
% end:
