%D \module
%D   [       file=tabl-ltb,
%D        version=2002.10.31, % updated 2016.01.08
%D          title=\CONTEXT\ Table Macros,
%D       subtitle=Line Tables,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D This module was made for some special project where we needed to typeset tables
%D spanning spanning many pages horizontally and vertically, with repeated header
%D lines and (entry) columns, tab tracking, color, etc. We do two passes over a
%D table, which is why the table can go into a buffer or file. As said, tables can
%D be real huge but performance is still quite okay (there is room for some speed
%D up). The code has been adapted to \MKIV\ but the functionality is the same as in
%D \MKII.

% \BH \BC .. \EC \BC .. \EC \EH % append
% \BR \BC .. \EC \BC .. \EC \ER
%
% or
%
% \NC .. \NC .. \NC \NR (todo: optional last \NC)

% alternative:
%
% (1) direct run, save content in macro, but only if needed
%
% todo
%
% (2) buffered table content
%
% \startbuffer
%   \startlinetablehead
%   \stoplinetablehead
%   \startlinetablebody
%   \stoplinetablebody
% \stopbuffer
%
% \processlinetablebuffer[buffer]
%
% in buffer : head and body
%
% (3) unbuffered run, multipass
%
% - run with starting width zero / prev run
% - clip on prev run
% - flush real widths

\writestatus{loading}{ConTeXt Table Macros / Line Tables}

\unprotect

\installcorenamespace{linetable}
\installcorenamespace{linetablepart}
\installcorenamespace{linetablewidth}
\installcorenamespace{linetableheight}
\installcorenamespace{linetabledepth}

% (For now) we share these three:

\aliased\let\tabl_lines_initialize_box  \tabl_tabulate_initialize_box
\aliased\let\tabl_lines_initialize_boxes\tabl_tabulate_initialize_boxes
\aliased\let\b_tabl_lines_current       \b_tabl_tabulate_current

\newconditional \c_tabl_lines_preroll
\newconditional \c_tabl_lines_in_table

\newdimension   \d_tabl_lines_width
\newdimension   \d_tabl_lines_height
%newdimension   \d_tabl_lines_depth

\newbox         \b_tabl_lines_cell

\newinteger     \c_tabl_lines_n_of_columns
\newinteger     \c_tabl_lines_n_of_rows
\newinteger     \c_tabl_lines_n_of_lines
\newinteger     \c_tabl_lines_n_of_parts
\newinteger     \c_tabl_lines_part           \c_tabl_lines_part\plusone
\newinteger     \c_tabl_lines_step           \c_tabl_lines_step\plusone
\newinteger     \c_tabl_lines_line
\newinteger     \c_tabl_lines_row
\newinteger     \c_tabl_lines_rows
\newinteger     \c_tabl_lines_column
\newinteger     \c_tabl_lines_subcol

\newconstant    \c_tabl_lines_hmode
\newconstant    \c_tabl_lines_page
\newconstant    \c_tabl_lines_repeat
\newconstant    \c_tabl_lines_split_state
\newconstant    \c_tabl_lines_head_state
\newconstant    \c_tabl_lines_mode

\newtoks        \t_tabl_lines_head

\newconditional \linetableautoheight  \linetableautoheight\conditionaltrue

\tabl_lines_initialize_box\zerocount % holds repeater

\pushoverloadmode

\permanent\tolerant\protected\def\setuplinetable[#S#1]#*[#S#2]#*[#S#3]%
  {\ifarguments\or
     \getparameters[\??linetable][#1]%
   \or
     \getparameters[\??linetable#1:][#2]%
   \or
     \getparameters[\??linetable#1:#2][#3]%
   \fi}

\permanent\def\linetableparameter#1%
  {\begincsname\??linetable#1\endcsname}

\permanent\protected\def\doifelselinetablecparameter#1%
  {\ifcsname\??linetable c:\the\c_tabl_lines_column#1\endcsname
     \expandafter\firstoftwoarguments
   \orelse\ifcsname\??linetable c:#1\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doiflinetablecparameterelse\doifelselinetablecparameter

\permanent\def\linetablecparameter#1%
  {\begincsname
     \??linetable
     \ifcsname\??linetable c:\the\c_tabl_lines_column#1\endcsname
       c:\the\c_tabl_lines_column
     \orelse\ifcsname\??linetable c:#1\endcsname
       c:%
     \fi
     #1%
   \endcsname}

\permanent\def\linetablerparameter#1% faster, leaner and meaner
  {\begincsname
     \??linetable
   % \ifnum\c_tabl_lines_row=\zerocount % geen ifcase
     \ifzero\c_tabl_lines_row
       \ifcsname\??linetable r:\v!header#1\endcsname
         r:\v!header
       \orelse\ifcsname\??linetable r:0#1\endcsname
         r:0%
       \fi
     \else
       \ifcsname\??linetable r:\the\c_tabl_lines_row#1\endcsname
         r:\the\c_tabl_lines_row
       \orelse\ifcsname\??linetable r:\v!oddeven\c_tabl_lines_row#1\endcsname
         r:\v!oddeven\c_tabl_lines_row
       \fi
     \fi
     #1%
   \endcsname}

\protected\def\tabl_lines_set
  {\edef\p_lines{\linetableparameter\c!lines}%
   \ifx\p_lines\v!fit
     \tabl_lines_set_indeed
   \else
     \global\c_tabl_lines_n_of_lines\p_lines
   \fi}

\protected\def\tabl_lines_set_indeed
  {% whitespace already added by vertical strut
  %\triggerpagebuilder
   \scratchdimen
     \ifdim\pagegoal<\maxdimen
       {\pagegoal-\pagetotal}%
     \else
       \textheight
     \fi
   \getrawnoflines\scratchdimen
   \global\c_tabl_lines_n_of_lines\noflines
   \ifconditional\c_tabl_lines_preroll\orelse\ifnum\c_tabl_lines_n_of_lines<\plustwo
     \page
     \tabl_lines_set
   \fi}

\def\tabl_lines_step_cell
  {\advanceby\scratchdimen{\linetablecparameter\c!width}%
   \global\advanceby\c_tabl_lines_column\plusone
   \advanceby\scratchskip{\linetablecparameter\c!distance}}

\permanent\tolerant\protected\def\startlinetablecell[#S#1]%
  {\global\setbox\b_tabl_lines_cell\hbox\bgroup
   \ifparameter#1\or
     \getparameters[\??linetable c:\the\c_tabl_lines_column][#1]%
   \fi
   \global\c_tabl_lines_step{\linetablecparameter\c!nx}%
   \ifcase\c_tabl_lines_step\or
     \scratchdimen{\linetablecparameter\c!width}
     \scratchskip{\linetablecparameter\c!distance}
   \else
     \scratchdimen  \zeropoint
     \scratchskip   \zeroskip
     \scratchcounter\c_tabl_lines_column
     \dorecurse\c_tabl_lines_step\tabl_lines_step_cell
     \global\c_tabl_lines_column\scratchcounter
   \fi
   \c_tabl_lines_mode
     \ifconditional\c_tabl_lines_preroll
       \ifdim\scratchdimen>\zeropoint \zerocount \else \plustwo \fi
     \else
       \zerocount
     \fi
   \ifcase\c_tabl_lines_mode
     \ifcase\c_tabl_lines_hmode
       % nothing
     \or
       % fit, keep it simple
     \or
       \c_tabl_lines_mode\plusone % line
     \else
       % some already calculated height
     \fi
   \fi
   \setbox\scratchbox\hbox
     \bgroup
     \dontcomplain
     \hskip{\linetablecparameter\c!leftoffset}%
     % 0 = width, unknown height
     % 1 = width, fixed height
     % 2 = no width, auto hsize
     \ifnum\c_tabl_lines_mode<\plustwo
       \advanceby\scratchdimen{-\linetablecparameter\c!leftoffset-\linetablecparameter\c!rightoffset}%
     \fi
     \ifcase\c_tabl_lines_mode
       \dosetraggedcommand{\linetablecparameter\c!align}%
       \vtop \ifdim\d_tabl_lines_height>\zeropoint to\d_tabl_lines_height \fi \bgroup
         \hsize\scratchdimen
         \raggedcommand
     \else
       \setalignmentswitch{\linetablecparameter\c!align}%
       \hbox \ifcase\c_tabl_lines_mode \or to\scratchdimen \fi \bgroup
         \ifcase\alignmentswitch\hss\or\hss\fi
     \fi
     \dousestyleparameter{\linetablecparameter\c!style}%
     \dousecolorparameter{\linetablecparameter\c!color}%
     \begstrut \ignorespaces}

\permanent\protected\def\stoplinetablecell
  {\unskip \endstrut
   \ifcase\c_tabl_lines_mode
     \endgraf
   \else
     \ifcase\alignmentswitch\else\hss\fi
   \fi
   \egroup
   \hskip{\linetablecparameter\c!rightoffset}\relax
   \egroup
   \ifconditional\c_tabl_lines_preroll
     \box\scratchbox
   \else
     \tabl_lines_wrap_up
   \fi
   \egroup}

\def\tabl_lines_wrap_up
  {\ifcstok{\linetablecparameter\c!background}\v!color
     \ifconditional\linetableautoheight
       \tabl_lines_wrap_up_auto
     \else
       \tabl_lines_wrap_up_line
      \fi
   \else
     \box\scratchbox
   \fi}

% \startuseMPgraphic{one}
%     path p, q ;
%     numeric r ;
%     r := RuleThickness ;
%     p := unitsquare xysized(RuleWidth,RuleHeight+RuleDepth) ;
%     q := p topenlarged -r bottomenlarged -r ;
%     draw q ;
%     setbounds currentpicture to p;
% \stopuseMPgraphic
%
% \setuplinetable[r][odd] [type=mp,mp=one,backgroundcolor=gray,rulethickness=1pt]
% \setuplinetable[r][even][type=mp,mp=one,backgroundcolor=green,rulethickness=1pt]
%
% \startlinetable
%     \dorecurse{10}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR}
% \stoplinetable

\def\tabl_lines_wrap_up_auto
  {\edef\p_height{\linetablerparameter{x\c!height}}%
   \edef\p_depth {\linetablerparameter{x\c!depth }}%
   \hpack
     {\blackrule
        [ \c!color=\linetablecparameter\c!backgroundcolor,
           \c!type=\linetablecparameter\c!type,
             \c!mp=\linetablecparameter\c!mp,
  \c!rulethickness=\linetablecparameter\c!rulethickness,
         \c!height=\ifchkdimension\p_height\or\lastchkdimension\else\ht\scratchbox\fi,
          \c!depth=\ifchkdimension\p_depth \or\lastchkdimension\else\dp\scratchbox\fi,
          \c!width=\wd\scratchbox]%
      \hkern-\wd\scratchbox\box\scratchbox}}

\def\tabl_lines_wrap_up_auto_r
  {\hpack
     {\blackrule
        [ \c!color=\linetablerparameter\c!backgroundcolor,
           \c!type=\linetablerparameter\c!type,
             \c!mp=\linetablerparameter\c!mp,
  \c!rulethickness=\linetablerparameter\c!rulethickness,
         \c!height=\ht\scratchbox,
          \c!depth=\dp\scratchbox,
          \c!width=\wd\scratchbox]%
      \hkern-\wd\scratchbox\box\scratchbox}}

\def\tabl_lines_wrap_up_line
  {\backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}}

\def\tabl_lines_save_part
  {\global\setbox\b_tabl_lines_current\c_tabl_lines_part
   \ifcase\c_tabl_lines_part\relax
     \box\scratchbox % just storing
   \else
     \vbox
       {\ifvoid\b_tabl_lines_current\c_tabl_lines_part\else\unvbox\b_tabl_lines_current\c_tabl_lines_part\fi
        \ifcstok{\linetablerparameter\c!background}\v!color
          \backgroundline[\linetablerparameter\c!backgroundcolor]{\box\scratchbox}%
        \orelse\ifempty{\linetablerparameter\c!type}%
          \box\scratchbox
        \else
          \tabl_lines_wrap_up_auto_r
        \fi
        \endgraf
        \linetablerparameter\c!after}%
   \fi}

\def\tabl_lines_flush_parts
  {\global\advanceby\c_tabl_lines_line\plusone
   \ifnum\c_tabl_lines_line<\c_tabl_lines_n_of_lines
     % keep collecting
   \else
     \ifconditional\c_tabl_lines_preroll
       % forget about them
     \else
       \dorecurse\c_tabl_lines_n_of_parts
         {\c_tabl_lines_part\recurselevel
          \dp\b_tabl_lines_current\c_tabl_lines_part\strutdepth
          % noindent en endgraf needed else whitespace mess-up!
          \whitespace % here not after verticalstrut
          \ifzeropt\topskipgap\else
            \verticalstrut
            \nobreak
            \kern-\struttotal
            \kern-\parskip
            \nobreak
            \nointerlineskip % fix topskip
          \fi
          \noindent\strut
          \hpack to \hsize{\box\b_tabl_lines_current\c_tabl_lines_part\hss}%
          \endgraf
          \ifnum\c_tabl_lines_part<\c_tabl_lines_n_of_parts\relax
            \linetableparameter\c!inbetween
          \fi}%
       \ifnum\c_tabl_lines_rows<\c_tabl_lines_n_of_rows
         \linetableparameter\c!inbetween
       \else
         % after, later
       \fi
       \c_tabl_lines_head_state\plusthree
       \global\setbox\b_tabl_lines_current\zerocount\emptybox % here
     \fi
     % reset \c_tabl_lines_row will be an option, currently
     % starts at zero after split
     \global\c_tabl_lines_row\zerocount
     \global\c_tabl_lines_line\zerocount
     \global\c_tabl_lines_page\zerocount
     \global\d_tabl_lines_width\zeropoint
     \tabl_lines_set
   \fi}

\def\tabl_lines_start_part
  {\global\c_tabl_lines_subcol\zerocount
   \setbox\scratchbox\hbox\bgroup
   \dousestyleparameter{\linetablerparameter\c!style}%
   \dousecolorparameter{\linetablerparameter\c!color}%
   \ignorespaces}

\def\tabl_lines_stop_part
  {\ifnum\c_tabl_lines_part>\zerocount
     \unskip \unskip % remove last intercolumn skip (distance+fill)
   \fi
   \egroup
   \ifconditional\c_tabl_lines_preroll
   \orelse\ifcase\c_tabl_lines_part
     % we're collecting the repeater
   \orelse\ifdim{\hsize-\wd\scratchbox}>{\linetableparameter\c!stretch}%
   \else
     \setbox\scratchbox\hpack to \hsize{\unhbox\scratchbox}%
   \fi}

\def\tabl_lines_check_part
  {\global\advanceby\d_tabl_lines_width\wd\b_tabl_lines_cell
   \global\advanceby\c_tabl_lines_column\c_tabl_lines_step
   \global\advanceby\c_tabl_lines_subcol\c_tabl_lines_step
   \relax
   %\message{\the\c_tabl_lines_column,\the\c_tabl_lines_subcol}\wait
   % from now on the column counter is already incremented
   \ifcase\c_tabl_lines_split_state
     \ifconditional\c_tabl_lines_preroll
     \else
       \box\b_tabl_lines_cell
       % the columncounter is one ahead !
       \hskip\scratchskip
     \fi
     %%%
     \donefalse
     \ifcase\c_tabl_lines_repeat
     \orelse\ifnum\c_tabl_lines_repeat={r\c_tabl_lines_column-\plustwo}% calculate ahead
       \donetrue % collecting repeater
     \fi
     %%%%
     \ifdone
       % collecting repeater
     \orelse\ifnum\c_tabl_lines_column>\csname\??linetablepart\the\c_tabl_lines_part\endcsname\relax
       \donetrue
     \fi
     \ifdone
       \tabl_lines_stop_part
       \ifconditional\c_tabl_lines_preroll \else
         \tabl_lines_save_part
       \fi
       \ifcase\c_tabl_lines_page \or
         \global\c_tabl_lines_page \plustwo
       \else
         \global\c_tabl_lines_page \plusone
       \fi
       \global\advanceby\c_tabl_lines_part\plusone
       \global\d_tabl_lines_width\wd\b_tabl_lines_current\zerocount
       \tabl_lines_start_part
     \fi
   \else
     \donefalse
     \scratchconditiononefalse
     \ifcase\c_tabl_lines_repeat\else
       % calculate ahead
       \ifnum\c_tabl_lines_repeat={\c_tabl_lines_column-\plustwo}%
         \donetrue % collecting repeater
       \fi
     \fi
     \ifdone
       \scratchconditiononetrue
       % collecting repeater
     \orelse\ifdim\d_tabl_lines_width>\hsize
       \donetrue
     \else
       \global\advanceby\d_tabl_lines_width\scratchskip
       \ifdim\d_tabl_lines_width>\hsize % ?
         \donetrue
       \fi
     \fi
     \ifdone
       \tabl_lines_stop_part
       \tabl_lines_save_part
       \ifcase\c_tabl_lines_page \or
         \global\c_tabl_lines_page \plustwo
       \else
         \global\c_tabl_lines_page \plusone
       \fi
       \global\advanceby\c_tabl_lines_part\plusone
       \ifnum\c_tabl_lines_part>\c_tabl_lines_n_of_parts
         \global\c_tabl_lines_n_of_parts\c_tabl_lines_part
         \tabl_lines_initialize_box\c_tabl_lines_part
       \fi
       \global\d_tabl_lines_width\wd\b_tabl_lines_cell
       \tabl_lines_start_part
       \ifscratchconditionone \orelse \ifcase\c_tabl_lines_repeat \else
         % check for left/right page
         \ifcase\c_tabl_lines_page\donetrue\or\donetrue\or\donefalse\fi
         \ifdone
           % insert repeater
           \global\advanceby\d_tabl_lines_width\wd\b_tabl_lines_current\zerocount
           \ifconditional\c_tabl_lines_preroll\kern\wd\else\unhcopy\fi\b_tabl_lines_current\zerocount
         \fi
       \fi
     \fi
     \ifconditional\c_tabl_lines_preroll \else
       \box\b_tabl_lines_cell
       % the columncounter is one ahead !
      %\dorecurse\c_tabl_lines_step{\strut\hfil}%
       \strut
       \hskip\scratchskip
     \fi
   \fi}

\permanent\protected\def\startlinetablerun % to do: quit when nested
  {\bgroup
   \dontcomplain
   \c_tabl_lines_in_table\conditionaltrue
   % autowidth
   \ifcstok{\linetableparameter\c!maxwidth}\v!fit
     \setuplinetable[\c!maxwidth=\zeropoint]%
   \fi
   \processaction
     [\linetableparameter\c!stretch]
     [ \v!no=>{\setuplinetable[\c!stretch=\maxdimen]},% no stretch
      \v!yes=>{\setuplinetable[\c!stretch=\zeropoint]}]% max stretch
   \c_tabl_lines_repeat{\linetableparameter\c!nleft}%
   \c_tabl_lines_split_state % =
     \ifdim{\linetableparameter\c!maxwidth}>\zeropoint
       \zerocount \else \plusone
     \fi
   % optional prevdepth correction
   \ifconditional\c_tabl_lines_preroll
     \global\c_tabl_lines_n_of_rows\zerocount
   \else
     \linetableparameter\c!before
   \fi
   \global\c_tabl_lines_rows\zerocount
   \global\c_tabl_lines_n_of_columns\zerocount
   \global\c_tabl_lines_n_of_parts\zerocount
   \scratchcounter\zerocount
   \def\docommand##1%
     {\global\advanceby\c_tabl_lines_n_of_parts\plusone
      \advanceby\scratchcounter##1%
      \xdefcsname\??linetablepart\the\c_tabl_lines_n_of_parts\endcsname{\the\scratchcounter}}%
   \processcommacommand[\linetableparameter\c!n]\docommand
   \tabl_lines_initialize_boxes\c_tabl_lines_n_of_parts
   \global\c_tabl_lines_part\ifcase\c_tabl_lines_repeat\plusone\else\zerocount\fi % repeater
   \global\c_tabl_lines_step\plusone
   \global\c_tabl_lines_line\zerocount
   \global\c_tabl_lines_row \zerocount
   \global\c_tabl_lines_column\zerocount
   \global\c_tabl_lines_subcol\zerocount
   \global\d_tabl_lines_width\zeropoint
   \ifconditional\c_tabl_lines_preroll\orelse\ifdim\pagetotal>\zeropoint
     \verticalstrut\kern-\struttotal
   \fi
   \tabl_lines_set
   \tabl_lines_check_page
   \enforced\let\BR\tabl_lines_BR
   \enforced\let\ER\tabl_lines_ER
   \enforced\let\BH\tabl_lines_BR
   \enforced\let\EH\tabl_lines_ER
   \enforced\let\BC\tabl_lines_BC
   \enforced\let\EC\tabl_lines_EC
   \enforced\let\NC\tabl_lines_NC
   \enforced\let\NR\tabl_lines_NR
   \tabl_lines_flush_head}

\permanent\protected\def\stoplinetablerun
  {\global\c_tabl_lines_line\maxcard
   \c_tabl_lines_head_state\zerocount % blocked
   \tabl_lines_flush_parts
   \ifconditional\c_tabl_lines_preroll \else
     \linetableparameter\c!after
   \fi
   \global\c_tabl_lines_part\zerocount
   \global\c_tabl_lines_n_of_parts\zerocount
   \egroup}

\permanent\def\checklinecolumndimension#1#2#3%
  {\global\edefcsname#1\number#3\endcsname
     {\expandafter\ifrelax\csname#1\number#3\endcsname
        \the#2\b_tabl_lines_cell
      \orelse\ifdim\csname#1\number#3\endcsname<#2\b_tabl_lines_cell
        \the#2\b_tabl_lines_cell
      \else
        \csname#1\number#3\endcsname
      \fi}}

\def\tabl_lines_check_width {\checklinecolumndimension\??linetablewidth \wd\c_tabl_lines_column}
\def\tabl_lines_check_height{\checklinecolumndimension\??linetableheight\ht\c_tabl_lines_row}
\def\tabl_lines_check_depth {\checklinecolumndimension\??linetabledepth \dp\c_tabl_lines_row}

\permanent\tolerant\protected\def\tabl_lines_BR[#1]% #1 not yet implemented
  {\ifnum\c_tabl_lines_head_state=1\else
     \global\advanceby\c_tabl_lines_row\plusone
     \global\advanceby\c_tabl_lines_rows\plusone
   \fi
   \global\c_tabl_lines_column\plusone
   \global\c_tabl_lines_subcol\plusone
   \d_tabl_lines_height\zeropoint
   \edef\p_height{\linetablerparameter\c!height}%
   \ifempty\p_height
     \c_tabl_lines_hmode \zerocount
   \orelse\ifx\p_height\v!fit
     \c_tabl_lines_hmode \plusone
   \orelse\ifx\p_height\v!line
     \c_tabl_lines_hmode \plustwo
   \else
     \d_tabl_lines_height{\p_height-\strutdepth}%
   \fi
   \tabl_lines_start_part}

\permanent\protected\def\tabl_lines_BC
  {\startlinetablecell}

\permanent\protected\def\tabl_lines_EC
  {\stoplinetablecell
   \ifconditional\c_tabl_lines_preroll
     \tabl_lines_check_width
     \tabl_lines_check_height
     \tabl_lines_check_depth
   \fi
   \tabl_lines_check_part}

\permanent\protected\def\tabl_lines_ER
  {% \stoplinetablecell
   % no \box\b_tabl_lines_cell, i.e. dummy columnn, last \NC \NR
   \tabl_lines_stop_part
   \tabl_lines_save_part
   \advanceby\c_tabl_lines_column \minusone
   \ifnum\c_tabl_lines_column>\c_tabl_lines_n_of_columns
     \global\c_tabl_lines_n_of_columns\c_tabl_lines_column
   \fi
   \tabl_lines_flush_parts
   \global\c_tabl_lines_column\zerocount
   \global\d_tabl_lines_width \zeropoint
   \ifcase\c_tabl_lines_repeat
     \global\c_tabl_lines_part\plusone
   \else
     \global\c_tabl_lines_part\zerocount % repeater
   \fi
   \tabl_lines_check_page
   \tabl_lines_flush_head}

\def\tabl_lines_check_page
  {\global\c_tabl_lines_page\zerocount
   \ifcase\c_tabl_lines_repeat\orelse\ifcase\c_tabl_lines_page
     \ifcstok{\linetableparameter\c!repeat}\v!no
       \global\c_tabl_lines_page\doifelseoddpage\plusone\plustwo
     \fi
   \fi}

\def\tabl_lines_flush_head
  {\ifcase\c_tabl_lines_head_state
     % 0 blocked
   \or
     % 1 doing head
   \or
     % 2 head done
   \or
     % 3 trigger flush
     \c_tabl_lines_head_state\plusone
     \expand\t_tabl_lines_head\relax
     \c_tabl_lines_head_state\plustwo
   \fi}

\permanent\protected\def\tabl_lines_NC % first time special treatment
  {\relax
   \ifcase\c_tabl_lines_column
     \tabl_lines_BR
   \else
     \tabl_lines_EC
   \fi
   \tabl_lines_BC} % beware, this will result in BR BC EC BC NR

\permanent\protected\def\tabl_lines_NR
  {\stoplinetablecell % dummy
   \tabl_lines_ER}

\permanent\protected\def\startlinetable
  {\startlinetablerun}

\permanent\protected\def\stoplinetable
  {\stoplinetablerun}

\permanent\protected\def\startlinetableanalysis
  {\bgroup
   \c_tabl_lines_preroll\conditionaltrue
   \settrialtypesetting
   \startlinetablerun}

\permanent\protected\def\stoplinetableanalysis
  {\stoplinetablerun
   \egroup
   \global\c_tabl_lines_n_of_rows\c_tabl_lines_rows
   \dorecurse\c_tabl_lines_n_of_rows % global, from last run {\linetableparameter\c!n}
     {\edefcsname\??linetable r:##1x\c!height\endcsname{\csname\??linetableheight##1\endcsname}%
      \edefcsname\??linetable r:##1x\c!depth \endcsname{\csname\??linetabledepth ##1\endcsname}%
      \gletcsname\??linetableheight##1\endcsname\zeropoint
      \gletcsname\??linetabledepth ##1\endcsname\zeropoint}
   \dorecurse\c_tabl_lines_n_of_columns % global, from last run {\linetableparameter\c!n}
     {\edefcsname\??linetable c:##1\c!width\endcsname{\csname\??linetablewidth##1\endcsname}%
      \gletcsname\??linetablewidth##1\endcsname\zeropoint}} % init next table

% todo: store in box instead of macro

\permanent\protected\lettonothing\stoplinetablehead

\permanent\protected\def\startlinetablehead#1\stoplinetablehead
  {\ifconditional\c_tabl_lines_in_table
     \t_tabl_lines_head\emptytoks
   \fi
   \c_tabl_lines_head_state\plusthree % full
   \t_tabl_lines_head{#1}%
   \ifconditional\c_tabl_lines_in_table
     \tabl_lines_flush_head
   \fi}

\permanent\protected\def\tabl_lines_BH
  {\ifrelax\EC
     % signal, grabbing lines
   \else
     \t_tabl_lines_head\emptytoks
   \fi
   \push_macro_BC
   \push_macro_EC
   \enforced\permanent\protected\def\BC##1\EC{\toksapp\t_tabl_lines_head{##1}}%
   \enforced\permanent          \let\EC\relax} % signal

\permanent\protected\def\tabl_lines_EH
  {\pop_macro_EC
   \pop_macro_BC
   \expandafter\startlinetablehead\expand\t_tabl_lines_head\stoplinetablehead}

\permanent\let\startlinetablebody\relax
\permanent\let\stoplinetablebody \relax

\permanent\tolerant\protected\def\processlinetablebuffer[#1]%
  {\bgroup
   \enforced\let\startlinetable\relax
   \enforced\let\stoplinetable \relax
   \startlinetableanalysis\getbuffer[#1]\stoplinetableanalysis
   \startlinetablerun     \getbuffer[#1]\stoplinetablerun
   \egroup}

\permanent\tolerant\protected\def\processlinetablefile[#1]% maybe accept #1 as well as [#1]
  {\bgroup
   \enforced\let\startlinetable\relax
   \enforced\let\stoplinetable \relax
   \startlinetableanalysis\readfile{#1}\donothing\donothing\stoplinetableanalysis
   \startlinetablerun     \readfile{#1}\donothing\donothing\stoplinetablerun
   \egroup}

\popoverloadmode

\setuplinetable
  [\c!n=\maxcard,
   \c!lines=\maxcard,
   \c!nx=\plusone,
   \c!nleft=\zerocount,
   \c!repeat=\v!yes, % when nleft > 0, repeat on both pages
   \c!before=,
   \c!after=,
   \c!inbetween=\page,
   \c!distance=\zeropoint,
   \c!stretch=\v!no,
   \c!align=\c!right,
   \c!leftoffset=.25\exheight,
   \c!rightoffset=\linetableparameter\c!leftoffset,
   \c!maxwidth=\zeropoint,
   \c!width=5\emwidth,
   \c!height=\v!fit, % \v!line = faster
   \c!background=,
   \c!backgroundcolor=,
   \c!rulethickness=\linewidth]

\protect

\continueifinputfile{tabl-ltb.mkxl}

\setuplinetable[n=6,m={2,2,2},lines=25] % m ?

\setuplinetable[c][1]   [width=2cm,background=color,backgroundcolor=red]
\setuplinetable[c][4]   [width=3cm,background=color,backgroundcolor=yellow]
\setuplinetable[c][6]   [width=3cm,background=color,backgroundcolor=magenta]
\setuplinetable[r][odd] [background=color,backgroundcolor=gray]
\setuplinetable[r][even][background=color,backgroundcolor=green]

\starttext

\showframe \showstruts

\setuppagenumbering[alternative=doublesided]\page[left]

\startlinetable
\NC aaa\crlf aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR
\dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR}
\stoplinetable

\startlinetable
\NC[style=slanted,color=green,background=color,backgroundcolor=darkred,nx=2,uitlijnen=middle] xxx
                 \NC yy \NC ddddd \NC eeee \NC ff \NC \NR
\dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR}
\stoplinetable

% \startbuffer[lt]
% \NC aaa\crlf aaa \NC bb \NC c  \NC ddddd \NC ee   \NC ff \NC \NR
% \NC aaa\crlf aaa \NC b  \NC cc \NC ddd   \NC eeee \NC f  \NC \NR
% \stopbuffer
%
% \processlinetablebuffer[lt]

\stoptext