%D \module
%D   [       file=strc-itm,
%D        version=2008.10.20,
%D          title=\CONTEXT\ Structure Macros,
%D       subtitle=Itemgroups,
%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.

\writestatus{loading}{ConTeXt Structure Macros / Itemgroups}

\unprotect

\newdimension\d_strc_itemgroups_max_width
\newinteger  \c_strc_itemgroups_max_items

\registerctxluafile{strc-itm}{autosuffix}

%D As we analyze/register widths and such we could as well push and pop the numbers
%D at the \LUA\ end (which saves a few calls).
%D
%D Cleaning up this module happened around the time when Kate Bush came up with the
%D nicest numbered list of words: 50 Words For Snow. It's therefore no surprise that
%D I had that cd running several times when updating this code. One of the
%D highlights of 2011.
%D
%D This module needs to be rewritten but that is tricky with respect to
%D compatibilitity. Basically each major variant (regular, text, columns,
%D horizontal, etc) needs to be on its own.

% todo: check breaks
% todo: check grouping
% todo: fixedconversion

% \startitemize[n,packed]
% \item test \item test \item test
% \stopitemize
%
% \startitemize[n,packed,reverse]
% \item test \item test \item test
% \stopitemize
%
% \startitemize[n,packed,reverse] \item test \item test \stopitemize
% \startitemize[continue]
% \item test \startitemize[n,packed] \item test \item test \stopitemize
% \item test
% \item test
% \stopitemize
% \startitemize[continue] \item test \stopitemize
%
% \startitemize[n,packed] \item test \item test \stopitemize
% \startitemize[continue] \item test            \stopitemize
% \startitemize[continue] \item test            \stopitemize
%
% \setupwhitespace[big]
% \starttext
%     test \startitemize[joinedup]                \item test \item test \stopitemize test \par
%     test \startitemize[joinedup,nowhite]        \item test \item test \stopitemize test \par
%     test \startitemize[joinedup,nowhite,before] \item test \item test \stopitemize test \par
%     test \startitemize[joinedup,nowhite,after]  \item test \item test \stopitemize test \par
% \stoptext
%
% test / example
%
% \startnarrower[left] \startcolumns[n=3] \startitemize
% \item \input ward \item \input ward \item \input ward
% \stopitemize \stopcolumns\stopnarrower \blank
%
% \startnarrower[left] \startitemize[columns,three]
% \item \input ward \item \input ward \item \input ward
% \stopitemize \stopnarrower \blank
%
% \setupitemize[leftmargin=1.5em] \startitemize[columns,three]
% \item \input ward \item \input ward \item \input ward
% \stopitemize \blank
%
% beware, we don't group (yet) as we want to keep the left/right skip
%
% \startitemize
% \startitem \stopitem
% some intermediate text that will properly indent
% \startitem \stopitem
% \stopitem
%
% so we need to keep that property
%
% \startitemize
%   \starthead {xx} test \stophead
%   \startitem test \stopitem
%   \startitem test \stopitem
% \stopitemize
%
% Sometimes the user demands get pretty weird:
%
% \startitemize
%   \item test
%   \item test
%   \headsym{xx} test \par test
% \stopitemize
%
% aligned items
%
% \startitemize[n,fit,broad][itemalign=flushright]
%      \dorecurse{100}{\item The first item.}
% \stopitemize
%
% \setupitemgroup[itemize][each][fit]
% \setupitemgroup[itemize][each][distance=.5em,factor=1,itemalign=flushright]
%
% \startitemize[n]
%      \dorecurse{100}{\item The first item.}
% \stopitemize
%
% \defineitemgroup[gbitemize]
% \setupitemgroup[gbitemize][each][headstyle=bold]
%
% \startgbitemize
% \txt{italian} some italians like this kind of cross||breed between
%   an itemize and a description
% \txt{sicilians} i wonder how many sicilian mathematicians do a thesis
%   on the math involved in predicting the next big bang of the vulcano
% \stopgbitemize
%
% \startitemize[n,repeat]
%     \noitem \startitemize[a] \item Item 1.a. \item Item 1.b. \stopitemize
%     \noitem \startitemize[a] \item Item 2.a. \item Item 2.b. \stopitemize
% \stopitemize
%
% \startitemize[n,repeat][width=0pt]
%   \noitem \startitemize[a][width=2em] \item Item 1.a. \item Item 1.b. \stopitemize
%   \noitem \startitemize[a][width=2em] \item Item 2.a. \item Item 2.b. \stopitemize
% \stopitemize
%
% \startbuffer
% \item
%   \startitemize[n]
%   \item item 1.1
%   \item item 1.2
%   \startitemize[n] \item item 1.2.1 \item item 1.2.2 \stopitemize
%   \item item 1.3
%   \stopitemize
% \item
%   \startitemize[n] \item item 2.1 \item item 2.2 \stopitemize
% \item item 3
%   \startitemize[n] \item item 3.1 \item item 3.2 \stopitemize
% \item
%   \startitemize[n] \item item 4.1 \item item 4.2 \stopitemize
% \stopbuffer
%
% \startitemize[n,repeat,6*broad,packed] \getbuffer \stopitemize \blank[3*big]
% \startitemize[n,repeat,packed]         \getbuffer \stopitemize \blank[3*big]
% \setupitemize[each][atmargin][width=3em]
% \startitemize[n,repeat,packed]         \getbuffer \stopitemize
%
% todo: assume startitem ... stopitem and do an autostopitem .. cleaner for
% elements
%
% \startitemize[text][space=medium]
% \item one \item two \item three
% \stopitemize
%
% For Giuseppe "Oblomov" Bilotta, inspired on a suggestion by Taco
% Hoekwater.
%
% \def\MyItemCommand#1{{\bf#1}\quad}
% \setupitemgroup[itemize][command=\MyItemCommand]
%
% \startitemize
% \item {test} is this okay?
% \item {test} is this okay?
% \item {test} is this okay?
% \stopitemize

\newconditional\c_strc_itemgroups_sub
\newconditional\c_strc_itemgroups_head
\newconditional\c_strc_itemgroups_intro
\newconditional\c_strc_itemgroups_randomize
\newconditional\c_strc_itemgroups_horizontal
\newconditional\c_strc_itemgroups_collecting
\newconditional\c_strc_itemgroups_auto_intro
\newconditional\c_strc_itemgroups_pack
\newconditional\c_strc_itemgroups_paragraph
\newconditional\c_strc_itemgroups_text
\newconditional\c_strc_itemgroups_no_par
\newconditional\c_strc_itemgroups_text_saved
\newconditional\c_strc_itemgroups_first
\newconditional\c_strc_itemgroups_before
\newconditional\c_strc_itemgroups_after
\newconditional\c_strc_itemgroups_nowhite
\newconditional\c_strc_itemgroups_joined
\newconditional\c_strc_itemgroups_reverse
\newconditional\c_strc_itemgroups_continue
\newconditional\c_strc_itemgroups_fitting
\newconditional\c_strc_itemgroups_indented_first
\newconditional\c_strc_itemgroups_inline
\newconditional\c_strc_itemgroups_columns
\newconditional\c_strc_itemgroups_concat
\newconditional\c_strc_itemgroups_txt
\newconditional\c_strc_itemgroups_extra
\newconditional\c_strc_itemgroups_repeat
\newconditional\c_strc_itemgroups_inline_head
\newconditional\c_strc_itemgroups_symbol
\newconditional\c_strc_itemgroups_overlay

% 0=before/after 1=auto 2=inbetween (default)

\newconstant   \c_strc_itemgroups_spacing_mode   \c_strc_itemgroups_spacing_mode\plustwo
\newconditional\c_strc_itemgroups_auto_concat    \c_strc_itemgroups_auto_concat \conditionaltrue

% 0=loose 1=tight 2=verytight

\newinteger    \c_strc_itemgroups_optimize       \c_strc_itemgroups_optimize\plusone % tight

\newboundary   \c_strc_itemgroups_boundary
\newbox        \b_strc_itemgroups

\newdimension  \d_strc_itemgroups_list_width
\newdimension  \d_strc_itemgroups_asked_width

%newdimension  \d_strc_itemgroups_max_width % defined already, used at the Lua end
%newinteger    \c_strc_itemgroups_max_items % idem

\def\d_strc_itemgroups_max_width_reference{\d_strc_itemgroups_max_width} % no alias!

\newinteger    \c_strc_itemgroups_n_of_items
\newinteger    \c_strc_itemgroups_nesting
\newinteger    \c_strc_itemgroups_column_depth

\def           \v_strc_itemgroups_counter        {itemgroup:\currentparentitemgroup}
\lettonothing  \m_strc_itemgroups_repeat_start
\def           \v_strc_itemgroups_unknown_symbol {?}
\lettonothing  \m_strc_itemgroups_indenting
\lettonothing  \m_strc_itemgroups_destination

\mutable\let   \currentitemlevel                 \!!zerocount % public
\mutable\def   \currentnofitems                  {\the\c_strc_itemgroups_max_items}
\mutable\def   \currentitemindex                 {\the\c_strc_itemgroups_n_of_items}
\mutable\def   \currentitemnumber                {\strc_counters_raw_sub\v_strc_itemgroups_counter\currentitemlevel} % public

\newtoks       \itemgroupcommands                % maybe public

\mutable\def          \currentitemgroupsymbol        {n} % here we cannot use a _ in the name
\mutable\lettonothing \currentitemgroupconversionset     % here we cannot use a _ in the name
\mutable\lettonothing \currentitemgroupsegments

\def\strc_itemgroups_register_status
  {\clf_registeritemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\c_strc_itemgroups_n_of_items{\itemgroupparameter\c!maxwidth}}

\def\strc_itemgroups_check_n_of_items % we could do this at the lua end and save a call (i.e. will be dimen and counter)
  {\clf_analyzeitemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\relax
   \edef\currentnofitems{\the\c_strc_itemgroups_max_items}}

\permanent\protected\def\upcomingnofitems#1%
  {\the\numexpr
     \clf_analyzeupcomingitemgroup{#1}{\c_strc_itemgroups_nesting+\plusone}%
     \c_strc_itemgroups_max_items
   \relax}

% todo: \dodosetreference -> \strc_counters_register_component (to be checked)

\def\strc_itemgroups_insert_reference % we will make a decent number helper
  {\iftrialtypesetting \orelse \ifempty\currentitemreference \else
     \strc_itemgroups_insert_reference_indeed
   \fi}

\def\strc_itemgroups_insert_extra_reference
  {\iftrialtypesetting \orelse \ifempty\currentitemreference \else
     \expanded{\textreference[\currentitemreference]{\strc_itemgroups_extra_symbol}}%
   \fi}

\def\strc_itemgroups_insert_reference_indeed % maybe we need a 'frozen counter' numberdata blob / quick hack .. .mive this to strc-ref
  {% needs testing, gave problems:
   \setnextinternalreference
   % no need to collect nodes in \b_strc_destination_nodes here ... maybe at some point
   \strc_references_start_destination_nodes
   % this is somewhat over the top ... we should use the counter's reference
   \clf_setdestinationattribute
     {%
         metadata {%
             kind            \s!item
         \ifx\currentreferencecoding\s!xml
             xmlroot         {\xmldocument}% only useful when text
         \fi
             catcodes        \catcodetable
         }%
         references {%
             internal        \locationcount % no: this spoils references
           % block           {\currentsectionblock}%
             view            {\interactionparameter\c!focus}%
             prefix          {\referenceprefix}%
             reference       {\currentitemreference}%
         }%
         prefixdata {%
             prefix          {\namedcounterparameter\v_strc_itemgroups_counter\c!prefix}%
             separatorset    {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixseparatorset}%
             conversion      {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversion}%
             conversionset   {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversionset}%
             set             {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixset}%
             segments        {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixsegments}%
           % segments        {\askedprefixsegments}%
             connector       {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconnector}%
         }%
         numberdata {%
             numbers         {\v_strc_itemgroups_counter}%
             separatorset    {\namedcounterparameter\v_strc_itemgroups_counter\c!numberseparatorset}%
           % conversion      {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversion}%
           % conversionset   {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversionset}%
           % fixedconversion {\currentitemgroupconversionset}%
             conversionset   {fixed::\currentitemgroupconversionset}% temp hack
           %
           % for the moment no stopper, we need to make references configurable first
           % stopper         {\namedcounterparameter\v_strc_itemgroups_counter\c!numberstopper}%
             segments        {\namedcounterparameter\v_strc_itemgroups_counter\c!numbersegments}%
         }%
     }%
   \relax
   \strc_references_stop_destination_nodes
   \global\currentdestinationattribute\lastdestinationattribute
   % will become an option:
   \ifnum\lastdestinationattribute>\zerocount
     \dontleavehmode\hbox attr \destinationattribute\lastdestinationattribute\bgroup
       \strc_references_flush_destination_nodes
     \egroup
   \fi}

%D Defining and setup:

\installcorenamespace{itemgroup}
\installcorenamespace{itemgroupoption}
\installcorenamespace{itemgroupsetting}
\installcorenamespace{itemgroupkeyword}
\installcorenamespace{itemgroupalign}
\installcorenamespace{itemgrouplocal}
\installcorenamespace{itemgroupglobal}
\installcorenamespace{itemgroupdistance}
\installcorenamespace{itemgroupstack}
\installcorenamespace{itemgroupfirst}
\installcorenamespace{itemgroupstart}

\installcommandhandler \??itemgroup {itemgroup} \??itemgroup

\aliased\let\setupitemgroups\setupitemgroup

\appendtoks
    \protected\frozen\instance\edefcsname\e!start\currentitemgroup           \endcsname{\startitemgroup[\currentitemgroup]}%
    \protected\frozen\instance\edefcsname\e!stop \currentitemgroup           \endcsname{\stopitemgroup}%
    \protected\frozen\instance\edefcsname\e!setup\currentitemgroup\e!endsetup\endcsname{\setupitemgroup[\currentitemgroup]}% obsolete
    \let\currentparentitemgroup\currentitemgroup
    \definecounter[\v_strc_itemgroups_counter]%
\to \everydefineitemgroup

%D Global states

\def\strc_itemgroups_store_continue_state#options#settings%
   {\xdefcsname\??itemgroupoption \currentitemgroup\endcsname{\strc_itemgroups_process_options{#options}}%
    \gdefcsname\??itemgroupsetting\currentitemgroup\endcsname{\setupcurrentitemgroup[#settings]}}

\def\strc_itemgroups_fetch_continue_state
  {\csname\??itemgroupoption \currentitemgroup\endcsname
   \csname\??itemgroupsetting\currentitemgroup\endcsname}

\def\strc_itemgroups_reset_continue_state
  {\gletcsname\??itemgroupoption \currentitemgroup\endcsname\relax
   \gletcsname\??itemgroupsetting\currentitemgroup\endcsname\relax}

% These will become keywords. We will also add a feature to keep the while set
% together.

\definevspacing[\v!item @\v!no]        [penalty:0]     % allow
\definevspacing[\v!item @\v!yes]       [penalty:10000] % never
\definevspacing[\v!item @\v!tight]     [penalty:500]   % discourage
\definevspacing[\v!item @\v!verytight] [penalty:5000]  % discourage more

\definevspacing[\v!item @-5] [penalty:-5]
\definevspacing[\v!item @5]  [penalty:5]

\def\strc_itemgroups_insert_break_when_needed#break%
  {\ifcase\c_strc_itemgroups_optimize
     % loose
   \orelse\ifconditional\c_strc_itemgroups_text
     % horizontal
   \else
     #break\relax
   \fi}

\def\strc_itemgroups_insert_breakallow{\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_breakallow_indeed}
\def\strc_itemgroups_insert_breakno   {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_breakno_indeed   }
\def\strc_itemgroups_insert_break     {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_break_indeed     }
\def\strc_itemgroups_insert_nobreak   {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_nobreak_indeed   }

\def\strc_itemgroups_insert_breakallow_indeed
  {\vspacing[\v!item @\v!no]}

\def\strc_itemgroups_insert_breakno_indeed
  {\vspacing[\v!item @\v!yes]}

\def\strc_itemgroups_insert_break_indeed
  {\flushnotes
   \vspacing[\v!item @-5]}

\def\strc_itemgroups_insert_nobreak_indeed
  {\flushnotes
   \ifinsidecolumns % todo
     \vspacing[\v!item @5]%
   \orelse\ifcase\c_strc_itemgroups_optimize
   \or
     % tight
     \vspacing[\v!item @\v!tight]%
   \else
     % verytight
     \vspacing[\v!item @\v!verytight]%
   \fi}

\protected\def\strc_itemgroups_process_options#options%
  {\processcommacommand[#options]\strc_itemgroups_process_option} % expansion of options is handy for xml

% \installcommalistprocessorcommand \strc_itemgroups_process_option_list \strc_itemgroups_process_option
%
% \protected\def\strc_itemgroups_process_options#options%
%   {\expanded{\strc_itemgroups_process_option_list[#options]}} % expansion of options is handy for xml

\mutable\lettonothing\itemgroupfirst
\mutable\lettonothing\itemgroupsecond

\def\strc_itemgroups_process_option#option%
  {\edef\scratchstringone{#option}%
   \ifempty\scratchstringone\else
     \splitatasterisk\scratchstringone\itemgroupfirst\itemgroupsecond
     \ifempty\itemgroupsecond
        \let\itemgroupsecond\itemgroupfirst
        \let\itemgroupfirst\!!plusone
     \fi
     \ifcsname\??itemgroupkeyword\itemgroupsecond\endcsname
       \lastnamedcs
     \else
       \strc_itemgroups_set_symbol\scratchstringone
     \fi
   \fi}

\def\strc_itemgroups_process_set_option_pack
  {\ifcase\c_strc_itemgroups_nesting \else
     \c_strc_itemgroups_pack\conditionaltrue
   \fi}

\def\strc_itemgroups_process_set_option_unpack
  {\ifcase\c_strc_itemgroups_nesting\else
     \c_strc_itemgroups_pack\conditionalfalse
   \fi}

\defcsname\??itemgroupkeyword\!!zerocount\endcsname
  {} % ignore 0

\defcsname\??itemgroupkeyword\v!packed\endcsname
  {\strc_itemgroups_process_set_option_pack}

\defcsname\??itemgroupkeyword\v!unpacked\endcsname
  {\strc_itemgroups_process_set_option_unpack}

\defcsname\??itemgroupkeyword\v!nointro\endcsname
  {\c_strc_itemgroups_intro\conditionalfalse}

\defcsname\??itemgroupkeyword\v!intro\endcsname
  {\c_strc_itemgroups_intro\conditionaltrue}

\defcsname\??itemgroupkeyword\v!autointro\endcsname
  {\c_strc_itemgroups_auto_intro\conditionaltrue}

\defcsname\??itemgroupkeyword\v!broad\endcsname
  {\ifempty\itemgroupfirst
     \let\itemgroupfirst\!!plusone
   \fi
   \letitemgroupparameter\c!factor\itemgroupfirst}

\defcsname\??itemgroupkeyword\v!text\endcsname
  {\c_strc_itemgroups_text\conditionaltrue
   \c_strc_itemgroups_inline\conditionaltrue
   \c_strc_itemgroups_joined\conditionaltrue
   \strc_itemgroups_process_set_option_pack}

\defcsname\??itemgroupkeyword\v!before\endcsname
  {\c_strc_itemgroups_before\conditionaltrue}

\defcsname\??itemgroupkeyword\v!after\endcsname
  {\c_strc_itemgroups_after\conditionaltrue}

\defcsname\??itemgroupkeyword\v!nowhite\endcsname
  {\c_strc_itemgroups_nowhite\conditionaltrue}

\defcsname\??itemgroupkeyword\v!margin\endcsname % signal
  {\setitemgroupparameter\c!width{-2em}}

\defcsname\??itemgroupkeyword\v!inmargin\endcsname % signal
  {\setitemgroupparameter\c!width{-2em}}

\defcsname\??itemgroupkeyword\v!atmargin\endcsname% signal
  {\ifnum\c_strc_itemgroups_nesting>\plusone
     \setitemgroupparameter\c!width{0em}%
   \fi}

\defcsname\??itemgroupkeyword\v!intext\endcsname
  {\c_strc_itemgroups_inline\conditionaltrue}

\defcsname\??itemgroupkeyword\v!headintext\endcsname
  {\c_strc_itemgroups_inline_head\conditionaltrue}

\defcsname\??itemgroupkeyword\v!loose\endcsname
  {\c_strc_itemgroups_optimize\zerocount}

\defcsname\??itemgroupkeyword\v!tight\endcsname % new per 2023-07-16
  {\c_strc_itemgroups_optimize\plusone}

\defcsname\??itemgroupkeyword\v!verytight\endcsname % new per 2023-07-16
  {\c_strc_itemgroups_optimize\plustwo}

\defcsname\??itemgroupkeyword\v!tight:\v!first\endcsname % new per 2023-07-16
  {\c_strc_itemgroups_optimize\plusthree}

\defcsname\??itemgroupkeyword\v!tight:\v!last\endcsname % new per 2023-07-16
  {\c_strc_itemgroups_optimize\plusfour}

\defcsname\??itemgroupkeyword\v!fit\endcsname
  {\c_strc_itemgroups_fitting\conditionaltrue}

\defcsname\??itemgroupkeyword\v!nofit\endcsname
  {\c_strc_itemgroups_fitting\conditionalfalse}

\defcsname\??itemgroupkeyword\v!paragraph\endcsname
  {\c_strc_itemgroups_paragraph\conditionaltrue
   \strc_itemgroups_process_set_option_pack}

\defcsname\??itemgroupkeyword\v!joinedup\endcsname
  {\c_strc_itemgroups_joined\conditionaltrue
   \strc_itemgroups_process_set_option_pack}

\defcsname\??itemgroupkeyword\v!notjoinedup\endcsname
  {\c_strc_itemgroups_joined\conditionalfalse}

\defcsname\??itemgroupkeyword\v!serried\endcsname
  {\edef\itemgroupfirst{-\ifempty\itemgroupfirst1\else\itemgroupfirst\fi}%
   \letitemgroupparameter\c!factor\itemgroupfirst}

\defcsname\??itemgroupkeyword\v!stopper\endcsname
  {\letitemgroupparameter\c!placestopper\v!yes} % keep {}

\defcsname\??itemgroupkeyword\v!nostopper\endcsname
  {\letitemgroupparameter\c!placestopper\v!no} % keep {}

\defcsname\??itemgroupkeyword\v!repeat\endcsname
  {\c_strc_itemgroups_repeat\conditionaltrue}

\defcsname\??itemgroupkeyword\v!norepeat\endcsname
  {\c_strc_itemgroups_repeat\conditionalfalse}

\defcsname\??itemgroupkeyword\v!reverse\endcsname
  {\c_strc_itemgroups_reverse\conditionaltrue}

\defcsname\??itemgroupkeyword\v!columns\endcsname
  {\c_strc_itemgroups_columns\conditionaltrue}

\defcsname\??itemgroupkeyword\v!overlay\endcsname
  {\c_strc_itemgroups_overlay\conditionaltrue}

\defcsname\??itemgroupkeyword\v!one  \endcsname{\letitemgroupparameter\c!n\plusone}
\defcsname\??itemgroupkeyword\v!two  \endcsname{\letitemgroupparameter\c!n\plustwo}
\defcsname\??itemgroupkeyword\v!three\endcsname{\letitemgroupparameter\c!n\plusthree}
\defcsname\??itemgroupkeyword\v!four \endcsname{\letitemgroupparameter\c!n\plusfour}
\defcsname\??itemgroupkeyword\v!five \endcsname{\letitemgroupparameter\c!n\plusfive}
\defcsname\??itemgroupkeyword\v!six  \endcsname{\letitemgroupparameter\c!n\plussix}
\defcsname\??itemgroupkeyword\v!seven\endcsname{\letitemgroupparameter\c!n\plusseven}
\defcsname\??itemgroupkeyword\v!eight\endcsname{\letitemgroupparameter\c!n\pluseight}
\defcsname\??itemgroupkeyword\v!nine \endcsname{\letitemgroupparameter\c!n\plusnine}

\defcsname\??itemgroupkeyword\v!standard\endcsname
  {\setitemgroupparameter  \c!width        {1.5\emwidth}%
   \setitemgroupparameter  \c!distance     {.5\emwidth}%
  %\letitemgroupparameter  \c!factor       \!!zerocount
   \letitemgroupparameter  \c!factor       {\zerocount}%
   \setitemgroupparameter  \c!packcriterium{\zerocount}%
   \resetitemgroupparameter\c!inner
   \resetitemgroupparameter\c!beforehead
   \letitemgroupparameter  \c!afterhead    \blank
   \letitemgroupparameter  \c!before       \blank
   \letitemgroupparameter  \c!inbetween    \blank
   \letitemgroupparameter  \c!after        \blank}

\def\strc_itemgroups_initialize_local
  {\c_strc_itemgroups_inline\conditionalfalse
   \c_strc_itemgroups_concat\conditionalfalse
   \c_strc_itemgroups_txt\conditionalfalse
   \c_strc_itemgroups_no_par\conditionalfalse
   %
   \c_strc_itemgroups_reverse\conditionalfalse
   \c_strc_itemgroups_intro\conditionalfalse
   \c_strc_itemgroups_auto_intro\conditionalfalse
   \c_strc_itemgroups_before\conditionalfalse
   \c_strc_itemgroups_after\conditionalfalse
   \c_strc_itemgroups_nowhite\conditionalfalse
   \c_strc_itemgroups_randomize\conditionalfalse
   \c_strc_itemgroups_horizontal\conditionalfalse
   \c_strc_itemgroups_collecting\conditionalfalse
   \c_strc_itemgroups_intro\conditionalfalse
   \c_strc_itemgroups_continue\conditionalfalse
   % this will be a constant
   \c_strc_itemgroups_head\conditionalfalse
   \c_strc_itemgroups_sub\conditionalfalse
   \c_strc_itemgroups_symbol\conditionalfalse
   \c_strc_itemgroups_columns\conditionalfalse
   \c_strc_itemgroups_overlay\conditionalfalse
   % to be checked
   \lettonothing\m_strc_itemgroups_destination
   \lettonothing\strc_itemgroups_used_symbol   % ** start value
   \lettonothing\strc_itemgroups_margin_symbol
   \lettonothing\strc_itemgroups_extra_symbol
   %
   \global\letitemgroupparameter\c!maxwidth\!!zeropoint
   }

\defcsname\??itemgroupfirst\v!intro\endcsname
  {\c_strc_itemgroups_intro\conditionaltrue}

\defcsname\??itemgroupfirst\v!continue\endcsname
  {\c_strc_itemgroups_continue\conditionaltrue}

\defcsname\??itemgroupfirst\v!random\endcsname
  {\c_strc_itemgroups_randomize\conditionaltrue
   \c_strc_itemgroups_collecting\conditionaltrue}

\defcsname\??itemgroupkeyword\v!horizontal\endcsname
  {\c_strc_itemgroups_horizontal\conditionaltrue
   \c_strc_itemgroups_collecting\conditionaltrue
   \c_strc_itemgroups_inline\conditionaltrue
   \c_strc_itemgroups_joined\conditionaltrue
   \strc_itemgroups_process_set_option_pack}

\def\strc_itemgroups_preset_stage_one#options%
  {\processcommacommand[#options]\strc_itemgroups_preset_stage_one_indeed}

% \installcommalistprocessorcommand \strc_itemgroups_preset_stage_one_list \strc_itemgroups_preset_stage_one_indeed
%
% \def\strc_itemgroups_preset_stage_one#options%
%   {\expanded{\strc_itemgroups_preset_stage_one_list[#options]}}

\def\strc_itemgroups_preset_stage_one_indeed#option%
  {\ifcsname\??itemgroupfirst#option\endcsname
     \lastnamedcs
   \fi}

\ifdefined\dotagsetitemgroup \else \aliased\let\dotagsetitemgroup\relax             \fi
\ifdefined\dotagsetitem      \else \aliased\let\dotagsetitem     \gobbleoneargument \fi

\def\strc_itemgroups_tag_start_group
  {\dostarttaggedchained\t!itemgroup\currentparentitemgroup\currentitemgroup\??itemgroup
   \dotagsetitemgroup}

\def\strc_itemgroups_tag_stop_group
  {\dostoptagged}

\def\strc_itemgroups_before_command
  {\ifconditional\c_strc_itemgroups_nowhite
     \ifconditional\c_strc_itemgroups_before
       \ifcase\c_strc_itemgroups_nesting\or\itemgroupparameter\c!before\fi
     \else
       \nowhitespace
     \fi
   \orelse\ifconditional\c_strc_itemgroups_joined
     % \empty
   \else
     \itemgroupparameter\c!before
   \fi}

\def\strc_itemgroups_after_command
  {\ifconditional\c_strc_itemgroups_nowhite
     \ifconditional\c_strc_itemgroups_after
       \ifcase\c_strc_itemgroups_nesting\or\itemgroupparameter\c!after\fi
     \else
       \nowhitespace
     \fi
   \orelse\ifconditional\c_strc_itemgroups_joined
     % \empty
   \else
     \itemgroupparameter\c!after
   \fi}

\def\strc_itemgroups_between_command
  {\ifconditional\c_strc_itemgroups_nowhite
     \nowhitespace
   \orelse\ifconditional\c_strc_itemgroups_joined
     % \empty
   \else
     \itemgroupparameter\c!inbetween
   \fi}

\def\strc_itemgroups_before_head_command
  {\ifconditional\c_strc_itemgroups_nowhite
     \nowhitespace
   \orelse\ifconditional\c_strc_itemgroups_joined
     % \empty
   \else
     \itemgroupparameter\c!beforehead
   \fi}

\def\strc_itemgroups_after_head_command
  {\ifconditional\c_strc_itemgroups_nowhite
     \nowhitespace
   \orelse\ifconditional\c_strc_itemgroups_joined
     % \empty
   \else
     \itemgroupparameter\c!afterhead
   \fi}

% compatible setup command:

\let\strc_itemgroups_normal_setup\setupitemgroup

\permanent\overloaded\tolerant\protected\def\setupitemgroup[#S#category]#spacer[#S#levels]#spacer[#S#options]#spacer[#S#settings]% category level|each options|settings settings|options
  {\ifarguments
     % nothing to set up
   \or
     \edef\strc_itemgroups_setup_what{#levels}%
     \strc_itemgroups_normal_setup[#category]% == settings
   \or
     \edef\strc_itemgroups_setup_what{#levels}%
     \strc_itemgroups_setup_each{#category}{#levels}%
   \or
     \edef\strc_itemgroups_setup_what{#levels}%
     \ifx\strc_itemgroups_setup_what\v!each
       \strc_itemgroups_setup_each{#category}{#options}%
     \else
       \strc_itemgroups_setup_list{#levels}{#category}{#options}%
     \fi
   \or
     \edef\strc_itemgroups_setup_what{#levels}%
     \ifx\strc_itemgroups_setup_what\v!each
       \strc_itemgroups_setup_each{#category}{#options}%
       \strc_itemgroups_setup_each{#category}{#settings}%
     \else
       \strc_itemgroups_setup_list{#levels}{#category}{#options}%
       \strc_itemgroups_setup_list{#levels}{#category}{#settings}%
     \fi
   \fi}

\def\strc_itemgroups_setup_each#category#whatever%
  {\ifhastok={#whatever}%
     \strc_itemgroups_normal_setup[#category][#whatever]%
   \else
     \strc_itemgroups_normal_setup[#category][\c!option={#whatever}]%
   \fi}

\def\strc_itemgroups_setup_list_level_a#category#whatever#level%
  {\strc_itemgroups_normal_setup[#category:#level][#whatever]}

\def\strc_itemgroups_setup_list_level_b#category#whatever#level%
  {\strc_itemgroups_normal_setup[#category:#level][\c!option={#whatever}]}

\def\strc_itemgroups_setup_list#subcategories#category#whatever%
  {\ifhastok={#whatever}%
     \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}%
   \else
     \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}%
   \fi}

\def\strc_itemgroups_increment_item_counter
  {\ifconditional\c_strc_itemgroups_sub \else
     \ifconditional\c_strc_itemgroups_symbol \else % \ifempty\strc_itemgroups_extra_symbol
       \strc_counters_increment_sub\v_strc_itemgroups_counter\currentitemlevel
     \fi
   \fi}

\protected\def\strc_itemgroups_insert_item_counter
  {\ifconditional\c_strc_itemgroups_repeat
     \ifcase\c_strc_itemgroups_nesting
       % skip
     \or
       \strc_itemgroups_insert_item_counter_indeed % this could become an option
     \else
       \strc_itemgroups_insert_item_counter_indeed
     \fi
   \else
     \strc_itemgroups_insert_item_counter_indeed
   \fi}

\installcorenamespace{itemstopper}

\defcsname\??itemstopper\v!yes\endcsname
  {\itemgroupparameter\c!stopper}

\defcsname\??itemstopper\v!display\endcsname
  {\ifconditional\c_strc_itemgroups_inline\else
     \itemgroupparameter\c!stopper
   \fi}

\defcsname\??itemstopper\v!inline\endcsname
  {\ifconditional\c_strc_itemgroups_inline
     \itemgroupparameter\c!stopper
   \fi}

\def\strc_itemgroups_insert_item_counter_indeed % quite slow ... every time this setup .. but it
  {\begingroup                                  % can be optimized ... best move some to strc-num
   \setupcounter
     [\v_strc_itemgroups_counter]%
     [\c!prefix=\itemgroupparameter\c!prefix,
      \c!prefixstopper=\itemgroupparameter\c!prefixstopper,
      \c!prefixseparatorset=\itemgroupparameter\c!prefixseparatorset,
      \c!prefixconversion=\itemgroupparameter\c!prefixconversion,
      \c!prefixconversionset=\itemgroupparameter\c!prefixseparatorset,
      \c!prefixset=\itemgroupparameter\c!prefixset,
      \c!prefixsegments=\itemgroupparameter\c!prefixsegments,
      \c!prefixconnector=\itemgroupparameter\c!prefixconnector,
      \c!criterium=\itemgroupparameter\c!criterium,
      \c!start=\itemgroupparameter\c!start,
      \c!numberorder=\ifconditional\c_strc_itemgroups_reverse\v!reverse\else\v!normal\fi,
      \c!numberstopper=\begincsname\??itemstopper\itemgroupparameter\c!placestopper\endcsname,
      \c!numberconversionset=\v_strc_itemgroups_counter,
      \c!numbersegments=\currentitemgroupsegments]%
   % there will be a fixedconversion key
   \expanded{\defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
  %\expanded{\strc_sets_define_conversion_set[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
   %
   \convertedcounter[\v_strc_itemgroups_counter]% [\number\currentitemlevel]%
   \strc_itemgroups_insert_reference
   \endgroup}

% needs testing (maybe it need to happen later)
%
% \appendtoks
%    \setupcounter
%      [\v_strc_itemgroups_counter]%
%      [\c!prefix=\itemgroupparameter\c!prefix,
%       \c!prefixstopper=\itemgroupparameter\c!prefixstopper,
%       \c!prefixseparatorset=\itemgroupparameter\c!prefixseparatorset,
%       \c!prefixconversion=\itemgroupparameter\c!prefixconversion,
%       \c!prefixconversionset=\itemgroupparameter\c!prefixseparatorset,
%       \c!prefixset=\itemgroupparameter\c!prefixset,
%       \c!prefixsegments=\itemgroupparameter\c!prefixsegments,
%       \c!prefixconnector=\itemgroupparameter\c!prefixconnector,
%       \c!criterium=\itemgroupparameter\c!criterium,
%       \c!numberorder=\ifconditional\c_strc_itemgroups_reverse\v!reverse\else\v!normal\fi,
%       \c!numberstopper=\expdoif{\itemgroupparameter\c!placestopper}\v!yes{\itemgroupparameter\c!stopper},
%       \c!numberconversionset=\v_strc_itemgroups_counter,
%       \c!numbersegments=\currentitemgroupsegments]%
% \to\itemgroupcommands
%
% \def\strc_itemgroups_insert_item_counter_indeed % quite slow ... every time this setup .. but it
%   {\begingroup                                  % can be optimized ... best move some to strc-num
%    % there will be a fixedconversion key
%   %\expanded{\defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
%    \expanded{\strc_sets_define_conversion_set[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
%    %
%    \convertedcounter[\v_strc_itemgroups_counter]% [\number\currentitemlevel]%
%    \strc_itemgroups_insert_reference
%    \endgroup}

\lettonothing\strc_itemgroups_temp_symbol
\lettonothing\strc_itemgroups_used_symbol
\lettonothing\strc_itemgroups_asked_symbol
\lettonothing\strc_itemgroups_margin_symbol
\lettonothing\strc_itemgroups_extra_symbol

\def\strc_itemgroups_set_symbol#symbol%
  {\edef\strc_itemgroups_temp_symbol{#symbol}%
   \ifempty\strc_itemgroups_temp_symbol \else
     \doifelsesymboldefined\strc_itemgroups_temp_symbol
        \strc_itemgroups_set_symbol_symbol
        {\doifelseconversiondefined\strc_itemgroups_temp_symbol
           \strc_itemgroups_set_symbol_conversion
           \donothing}%
   \fi}

\def\strc_itemgroups_set_symbol_symbol
  {\let\currentitemgroupsymbol\strc_itemgroups_temp_symbol
   \strc_itemgroups_store_global_symbol\currentitemgroupsymbol
   \strc_itemgroups_store_local_symbol\v_strc_itemgroups_unknown_symbol
   \let\strc_itemgroups_used_symbol\strc_itemgroups_set_symbol_symbol_item
   \lettonothing\strc_itemgroups_asked_symbol}

\def\strc_itemgroups_set_symbol_conversion
  {\let\currentitemgroupsymbol\strc_itemgroups_temp_symbol
   \strc_itemgroups_store_global_symbol\currentitemgroupsymbol
   \strc_itemgroups_store_local_symbol\strc_itemgroups_insert_item_counter
   \let\strc_itemgroups_used_symbol\strc_itemgroups_set_symbol_conversion_item
   \lettonothing\strc_itemgroups_asked_symbol}

\def\strc_itemgroups_set_symbol_symbol_item
  {\symbol[\currentitemgroupsymbol]}

\def\strc_itemgroups_set_symbol_conversion_item
  {\ifconditional\c_strc_itemgroups_text
     % maybe block stopper here, but one can as well clone an itemgroup then
     \itemgroupparameter\c!lefttext
     \strc_itemgroups_fetch_local_symbol
     \itemgroupparameter\c!righttext
   \else
     \itemgroupparameter\c!left
     \strc_itemgroups_fetch_local_symbol
     \itemgroupparameter\c!right
   \fi}

\def\strc_itemgroups_calculate_list_width#level%
  {\let\m_strc_itemgroups_saved\currentitemgroup
   \cdef\currentitemgroup{\currentparentitemgroup:\number#level}%
   \ifdim\d_strc_itemgroups_max_width>\zeropoint
     \d_strc_itemgroups_list_width\d_strc_itemgroups_max_width
   \orelse\ifnum\itemgroupparameter\c!factor>\zerocount
     \d_strc_itemgroups_list_width\itemgroupparameter\c!step\relax
     \ifzeropt\d_strc_itemgroups_list_width \d_strc_itemgroups_list_width=.5em\fi
     \multiplyby\d_strc_itemgroups_list_width \itemgroupparameter\c!factor
     \advanceby\d_strc_itemgroups_list_width{\itemgroupparameter\c!width}%
   \else
     \d_strc_itemgroups_list_width{\itemgroupparameter\c!width}%
   \fi
   \advanceby\d_strc_itemgroups_list_width{\itemgroupparameter\c!distance}%
   \let\currentitemgroup\m_strc_itemgroups_saved}

\lettonothing\p_itemgroups_options
\lettonothing\p_itemgroups_extra_options

\permanent\tolerant\protected\def\startitemgroup[#S#category]#spacer[#S#options]#spacer[#S#settings]%
  {\begingroup % (1)
   \nofarguments\lastarguments
   \cdef\currentitemgroup{#category}% no nested mixing of itemgroups
   \let\currentparentitemgroup\currentitemgroup
   \global\advanceby\c_strc_itemgroups_nesting\plusone
   \def\currentitemlevel{\the\c_strc_itemgroups_nesting}%
   \expanded{\chaintocurrentitemgroup{\currentparentitemgroup:\currentitemlevel}}%
   \cdef\currentitemgroup{\currentparentitemgroup:\currentitemlevel}%
   %
   \edef\p_itemgroups_options{\itemgroupparameter\c!option}%
   \lettonothing\p_itemgroups_extra_options
   \ifcase\nofarguments
     \strc_itemgroups_start_indeed{}%
   \or
     \strc_itemgroups_start_indeed{}%
   \or
     \ifhastok={#options}%
       \strc_itemgroups_start_indeed{#options}%
     \else
       \edef\p_itemgroups_extra_options{#options}%
       \strc_itemgroups_start_indeed{}%
     \fi
   \or
     \edef\p_itemgroups_extra_options{#options}%
     \strc_itemgroups_start_indeed{#settings}%
   \fi}

\def\strc_itemgroups_start_indeed#settings%
  {\ifempty\p_itemgroups_options
     \let\p_itemgroups_options\p_itemgroups_extra_options
   \orelse\ifempty\p_itemgroups_extra_options
     % ok
   \else
     \edef\p_itemgroups_options{\p_itemgroups_options,\p_itemgroups_extra_options}%
   \fi
   \begingroup % (2)
   \the\itemgroupcommands
   \c_strc_itemgroups_text_saved\c_strc_itemgroups_text
   \strc_itemgroups_initialize_local
   \strc_itemgroups_preset_stage_one\p_itemgroups_options
   \iftrialtypesetting
     \strc_counters_save\v_strc_itemgroups_counter
   \fi
\globalpushmacro\c_strc_itemgroups_n_of_items
\global\c_strc_itemgroups_n_of_items\zerocount
   \strc_itemgroups_check_n_of_items
   \ifempty\p_itemgroups_options
     \strc_itemgroups_setup_symbol_default
     \strc_itemgroups_reset_continue_state
     \setupcurrentitemgroup[#settings]%
   \else
     \strc_itemgroups_process_options\p_itemgroups_options
     \setupcurrentitemgroup[#settings]%
     \ifconditional\c_strc_itemgroups_continue
       \strc_itemgroups_setup_symbol_continue
       \strc_itemgroups_fetch_continue_state
     \else
       \strc_itemgroups_setup_symbol_asked
       \strc_itemgroups_store_continue_state\p_itemgroups_options{#settings}%
     \fi
   \fi
   %
   \ifhmode
     \ifconditional\c_strc_itemgroups_auto_concat
       \ifnum\lastboundary=\c_strc_itemgroups_boundary
         \c_strc_itemgroups_concat\conditionaltrue
       \fi
     \fi
     \ifconditional\c_strc_itemgroups_text_saved
     \orelse\ifconditional\c_strc_itemgroups_text
     \orelse\ifconditional\c_strc_itemgroups_no_par
     \else
       \par
     \fi
   \fi
   %
   \ifconditional\c_strc_itemgroups_pack
     \ifnum\currentnofitems>\itemgroupparameter\c!packcriterium\relax\else
       \c_strc_itemgroups_pack\conditionalfalse
     \fi
   \fi
   %
   \ifconditional\c_strc_itemgroups_text % also does inline
     % ignore
   \orelse\ifnum\c_strc_itemgroups_nesting=\plusone % NIEUW
     \doadaptleftskip {\itemgroupparameter\c!margin}%
     \doadaptleftskip {\itemgroupparameter\c!leftmargin}%
     \doadaptrightskip{\itemgroupparameter\c!rightmargin}%
   \fi
   %
   \doadaptleftskip {\itemgroupparameter\c!leftmargindistance}%
   \doadaptrightskip{\itemgroupparameter\c!rightmargindistance}%
   %
   \edef\m_strc_itemgroups_spacing{\itemgroupparameter\c!spacing}%
   \ifx\m_strc_itemgroups_spacing\v!before
     \c_strc_itemgroups_spacing_mode\zerocount
   \orelse\ifx\m_strc_itemgroups_spacing\v!inbetween
     \c_strc_itemgroups_spacing_mode\plusone
   \orelse\ifx\m_strc_itemgroups_spacing\v!auto
     \c_strc_itemgroups_spacing_mode\plustwo
   \fi
   %
   \usealignparameter\itemgroupparameter
   \edef\m_strc_itemgroups_indenting{\itemgroupparameter\c!indenting}%
   \ifnum\c_strc_itemgroups_nesting>\zerocount
     \c_strc_itemgroups_first\conditionaltrue
     \ifconditional\c_strc_itemgroups_continue \else
       \strc_counters_restart_sub\v_strc_itemgroups_counter\currentitemlevel{(\itemgroupparameter\c!start)-\plusone}%
     \fi
   \fi
   \ifempty\strc_itemgroups_used_symbol
     \strc_itemgroups_set_symbol\strc_itemgroups_asked_symbol % ** default value
     \ifempty\strc_itemgroups_used_symbol
       \let\currentitemgroupsymbol\currentitemlevel % ** fall back
     \fi
   \fi
   \ifconditional\c_strc_itemgroups_auto_intro\ifnum\prevgraf<\plusthree
     \c_strc_itemgroups_intro\conditionaltrue
   \fi\fi
   \ifconditional\c_strc_itemgroups_paragraph
     \ifnum\c_strc_itemgroups_nesting>\plusone
       \resetitemgroupparameter\c!inbetween
     \fi
   \fi
   \ifconditional\c_strc_itemgroups_pack
     \resetitemgroupparameter\c!inbetween
   \fi
   \ifconditional\c_strc_itemgroups_columns
     \ifinsidecolumns\orelse\ifcase\c_strc_itemgroups_column_depth
       \global\c_strc_itemgroups_column_depth\c_strc_itemgroups_nesting % global ?
       \strc_itemgroups_before_command
       \strc_itemgroups_tag_start_group
       \strc_itemgroups_start_columns
     \fi
   \fi
   \ifconditional\c_strc_itemgroups_fitting
     \ifdim\d_strc_itemgroups_max_width>\zeropoint
       \letitemgroupparameter\c!width\d_strc_itemgroups_max_width_reference
     \fi
   \fi
   \strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
   \ifdim\d_strc_itemgroups_list_width>\zeropoint\relax
     \ifconditional\c_strc_itemgroups_inline\else
       \frozen\advanceby\leftskip\d_strc_itemgroups_list_width\relax
     \fi
   \fi
   \ifempty\m_strc_itemgroups_repeat_start
     \let\currentitemgroupconversionset \currentitemgroupsymbol
     \edef\currentitemgroupsegments     {\currentitemlevel}%
   \else
     \edef\currentitemgroupconversionset{\currentitemgroupconversionset,\currentitemgroupsymbol}%
     \edef\currentitemgroupsegments     {\m_strc_itemgroups_repeat_start:\currentitemlevel}%
   \fi
   \d_strc_itemgroups_asked_width{\itemgroupparameter\c!width}%
   \startcollectitems}

\let\startcollectitems\relax
\let\stopcollectitems \relax

\letcsname\??itemgroupalign\v!flushleft \endcsname\relax
\letcsname\??itemgroupalign\v!right     \endcsname\relax
\letcsname\??itemgroupalign\v!flushright\endcsname\hfill
\letcsname\??itemgroupalign\v!left      \endcsname\hfill
\letcsname\??itemgroupalign\v!middle    \endcsname\hfil
\letcsname\??itemgroupalign\v!center    \endcsname\hfil

\def\strc_itemgroups_left_sym_filler
  {\csname\??itemgroupalign\itemgroupparameter\c!symalign\endcsname}

% symbols + states

\def\strc_itemgroups_store_global_symbol#symbol%
  {\gletcsname\??itemgroupglobal\currentitemgroup:\currentitemlevel\endcsname#symbol}

\def\strc_itemgroups_store_local_symbol#symbol%
  {\gletcsname\??itemgrouplocal\currentitemgroup:\currentitemlevel\endcsname#symbol}

\def\strc_itemgroups_fetch_global_symbol
  {\csname\??itemgroupglobal\currentitemgroup:\currentitemlevel\endcsname}

\def\strc_itemgroups_fetch_local_symbol
  {\csname\??itemgrouplocal\currentitemgroup:\currentitemlevel\endcsname}

\def\strc_itemgroups_setup_symbol_default
  {\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}%
   \strc_itemgroups_store_global_symbol\empty}

\def\strc_itemgroups_setup_symbol_continue
  {\ifcsname\??itemgroupglobal\currentitemgroup:\currentitemlevel\endcsname
     \let\strc_itemgroups_asked_symbol\strc_itemgroups_fetch_global_symbol
   \else
     \let\strc_itemgroups_asked_symbol\currentitemlevel
   \fi}

\def\strc_itemgroups_setup_symbol_asked
   {\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}}

\ifdefined\strc_itemgroups_start_columns

    % already defined in page-mix

\else

    % will be redefined in page-mix

    \ifdefined\startcolumns \else
        \protected\def\startcolumns[#S#settings]{}
        \protected\def\stopcolumns              {}
    \fi

    \def\strc_itemgroups_start_columns
      {\startcolumns
         [\c!n=\itemgroupparameter\c!n,
          \c!height=,
          \c!rule=\v!off,
          \c!balance=\v!yes,
          \c!align=\v!no]}

    \def\strc_itemgroups_stop_columns
      {\stopcolumns}

\fi

\permanent\protected\def\stopitemgroup
  {\stopcollectitems
   \ifconditional\c_strc_itemgroups_text
     \removeunwantedspaces
     \space
     \ignorepars % \ignorespaces
   \else
     \par
   \fi
   \strc_itemgroups_register_status
 % \ifconditional\c_strc_itemgroups_first \else
   \ifnum\c_strc_itemgroups_n_of_items>\zerocount % different criterium
     \dostoptagged
     \dostoptagged
   % \endgroup % (3)
   \fi
   \ifnum\c_strc_itemgroups_column_depth=\c_strc_itemgroups_nesting\relax
     \strc_itemgroups_stop_columns
     \global\c_strc_itemgroups_column_depth\zerocount % global ?
     \strc_itemgroups_tag_stop_group
     \strc_itemgroups_after_command
     \dontrechecknextindentation
   \orelse\ifnum\c_strc_itemgroups_nesting=\plusone
     \strc_itemgroups_insert_breakallow
     \strc_itemgroups_tag_stop_group
     \strc_itemgroups_after_command
     \useindentnextparameter\itemgroupparameter
   \else
     % nieuw, not yet nobreak handling
     \strc_itemgroups_tag_stop_group
     \ifcase\c_strc_itemgroups_spacing_mode
       \strc_itemgroups_after_command
     \or
       % was \strc_itemgroups_after_command
      %\ifempty\strc_itemgroups_after_command % here it's unset
       \ifempty{\directitemgroupparameter\c!after}%
         \strc_itemgroups_inbetween_command
       \else
         \strc_itemgroups_after_command
       \fi
     \else
       % was nothing
       \strc_itemgroups_inbetween_command
     \fi
     \dontrechecknextindentation
   \fi
   % new test, needed in sidefloats (surfaced in volker's proceedings)
   \iftrialtypesetting
     \strc_counters_restore\v_strc_itemgroups_counter % could happen in LUA
   \fi
   \globalpopmacro\c_strc_itemgroups_n_of_items
   \global\advanceby\c_strc_itemgroups_nesting\minusone
   \xdef\currentitemlevel{\the\c_strc_itemgroups_nesting}%
  %\ifconditional\c_strc_itemgroups_text
     \endgroup % (2)
     \endgroup % (1)
  %\else
  %  \endgroup % (2)
  %  \endgroup % (1)
  %  \par % hm, already done, and dangerous as \c_strc_itemgroups_text is already forgotten
  %\fi
   \dorechecknextindentation}

% The items.

\def\strc_itemgroups_start_item_first
  {\c_strc_itemgroups_first\conditionalfalse
 % \begingroup % (3)
   \ifcase\c_strc_itemgroups_nesting
                                           % 0
   \or
     \strc_itemgroups_start_item_first_one % 1
   \else
     \strc_itemgroups_start_item_first_two % 2+
   \fi}

\def\strc_itemgroups_start_item_first_one
  {\ifcase\c_strc_itemgroups_column_depth
     \ifconditional\c_strc_itemgroups_intro\strc_itemgroups_insert_breakno\fi
     \strc_itemgroups_before_command
     \strc_itemgroups_tag_start_group
     \ifconditional\c_strc_itemgroups_intro\strc_itemgroups_insert_breakno\fi
   \fi}

\newinteger\c_strc_itemgroups_prev_level

\def\strc_itemgroups_inbetween_command
  {\nameditemgroupparameter{\currentparentitemgroup:\the\c_strc_itemgroups_prev_level}\c!inbetween}

\def\strc_itemgroups_start_item_first_two
  {\ifconditional\c_strc_itemgroups_paragraph\else
     \c_strc_itemgroups_prev_level{\c_strc_itemgroups_nesting-\plusone}%
     \ifcase\c_strc_itemgroups_spacing_mode
       \strc_itemgroups_before_command
     \or
      %\ifempty\strc_itemgroups_before_command % should possibly expand to empty
       \ifempty{\directitemgroupparameter\c!before}%
         \strc_itemgroups_inbetween_command
       \else
         \strc_itemgroups_before_command
       \fi
     \else
       \strc_itemgroups_inbetween_command
     \fi
     \strc_itemgroups_tag_start_group
   \fi}

\def\strc_itemgroups_start_item_next
  {%\dostoptagged % moved
   %\dostoptagged % moved
   \ifconditional\c_strc_itemgroups_text
     \ifhmode
       % WS: make the distance between items customizable, think about better default values -> see itemize-1.tex
       \strc_itemgroups_set_text_item_distance% HH: moved out and made configurable (sort of)
       \removeunwantedspaces
       \ifnum{\c_strc_itemgroups_n_of_items+\plusone}=\c_strc_itemgroups_max_items
         \itemgroupparameter\c!lasttextseparator
       \else
         \itemgroupparameter\c!textseparator
       \fi
       \ifempty\m_strc_itemgroups_text_distance
         % safeguard
       \else
         \hskip\m_strc_itemgroups_text_distance\relax
       \fi
     \fi
   \else
     \strc_itemgroups_between_command
   \fi}

% c_strc_itemgroups_concat:
%
% the problem is that we use leftskip so concat cannot reliable take the height into
% account; it's .. rather tricky when white space in there anyway (due to \par) .. so
% we rely on a special blank method
%
% \startitemize[n]
%     \item bla
%     \item \startitemize[a]
%         \item bla $\displaystyle\int^{x^{y^4}}$ \item bla
%     \stopitemize
% \stopitemize

\mutable\lettonothing\currentitemreference

\noaligned\tolerant\permanent\protected\def\startitemgroupitem[#reference]% we can reuse more
  {\strc_itemgroups_begin
   \def\currentitemreference{#reference}%
   \ifconditional\c_strc_itemgroups_text
     % begin of item
   \orelse\ifconditional\c_strc_itemgroups_no_par
     % special
   \else
     \par
   \fi
   \ifconditional\c_strc_itemgroups_concat
     \strc_itemgroups_insert_breakno
   \fi
 % \ifconditional\c_strc_itemgroups_first
 %   \strc_itemgroups_start_item_first
 % \else
 %   \strc_itemgroups_start_item_next
 % \fi
 % now:
   \strc_itemgroups_increment_item_counter
   \ifnum\c_strc_itemgroups_n_of_items>\zerocount % different criterium
     \dostoptagged % moved here
     \dostoptagged % moved here
     \strc_itemgroups_start_item_next
   \else
     \strc_itemgroups_start_item_first
   \fi
   \ifconditional\c_strc_itemgroups_concat
     \spac_overlay_lines % see spac-ver.mkvi ... a typical potential problem
     \c_strc_itemgroups_concat\conditionalfalse
   \fi
   \dostarttaggednodetail\t!item
  % \dotagsetitem\empty
   \dostarttaggednodetail\t!itemtag
   \strc_itemgroups_insert_item
   \dostoptagged
   \ifconditional\c_strc_itemgroups_pack
     \setupwhitespace[\v!none]%
   \fi
   \itemgroupparameter\c!inner % will become obsolete (better use setups)
   \strc_itemgroups_margin_symbol
   \let\strc_itemgroups_margin_symbol\relax
   \dostarttaggednodetail\t!itemcontent
   \begstrut % \strut
   \nobreak                            % else problems with intext items
   \seteffectivehsize % NEW !
   \boundary\c_strc_itemgroups_boundary % was signal
   \itemgroupparameter\c!command}

\noaligned\protected\permanent\def\stopitemgroupitem
  {\ifhmode
     \endstrut % new per 2017-12-15
   \fi
   \ifconditional\c_strc_itemgroups_text
     % nothing
   \else
     \endgraf
   \fi
   \strc_itemgroups_end}

\lettonothing\strc_itemgroups_begin
\lettonothing\strc_itemgroups_end

\tolerant\permanent\protected\def\startitemgrouphead[#reference]%
  {\ifconditional\c_strc_itemgroups_first \else
     \strc_itemgroups_insert_breakallow
   \fi
   \ifconditional\c_strc_itemgroups_pack \else
     \strc_itemgroups_before_head_command
   \fi
   \ifconditional\c_strc_itemgroups_first
     \ifconditional\c_strc_itemgroups_intro \else
       \ifcase\c_strc_itemgroups_nesting
         \strc_itemgroups_insert_breakallow
       \fi
     \fi
   \fi
  %\strc_itemgroups_start_item[#reference]%
   \startitemgroupitem[#reference]%
   \pickupgroupedcommand
     \strc_itemgroups_start_head_indeed
     \strc_itemgroups_stop_head_indeed
     \strc_itemgroups_head_body_indeed}

\permanent\protected\def\stopitemgrouphead
  {\dostoptagged
   \stopitemgroupitem}

\protected\def\strc_itemgroups_start_head_indeed
  {\c_strc_itemgroups_head\conditionaltrue
   \dotagsetitem\s!head% % weird place
   \dostarttaggednodetail\t!itemhead
   \useitemgroupstyleandcolor\c!headstyle\c!headcolor
   \ignorepars} % \ignorespaces

\protected\def\strc_itemgroups_stop_head_indeed
  {\removeunwantedspaces
   \dostoptagged
   \ifconditional\c_strc_itemgroups_inline_head
       \space
       \ignorepars % \ignorespaces
   \else
     \ifconditional\c_strc_itemgroups_text
       \space
       \ignorepars % \ignorespaces
     \else
       \par
     \fi
     \strc_itemgroups_insert_breakno
     \ifconditional\c_strc_itemgroups_pack\else\strc_itemgroups_after_head_command\fi
     \strc_itemgroups_insert_breakno
  \fi}

\protected\def\strc_itemgroups_head_body_indeed
  {\dostarttaggednodetail\t!itembody
   \noindentation
   \ignorepars} % \ignorespaces

% Simple commands.

\protected\def\strc_itemgroups_start_do_item
  {\startitemgroupitem}

\protected\def\strc_itemgroups_start_no_item
  {\lettonothing\currentitemreference
   \strc_itemgroups_increment_item_counter
  %\advanceby\c_strc_itemgroups_n_of_items\plusone
   \setbox\b_strc_itemgroups\emptyhbox
   \strc_itemgroups_check_for_repeated
   \ignorepars} % \ignorespaces

\protected\def\strc_itemgroups_start_button[#destination]%
  {\edef\m_strc_itemgroups_destination{#destination}%
   \startitemgroupitem}

\protected\def\strc_itemgroups_start_symbol#text%
  {\def\strc_itemgroups_extra_symbol{#text}%
   \c_strc_itemgroups_symbol\conditionaltrue
   \startitemgroupitem
   \dotagsetitem\s!symbol}

\protected\def\strc_itemgroups_start_dummy
  {\strc_itemgroups_start_symbol
  %\strut\strut} % two ?
   \begstrut}

\protected\def\strc_itemgroups_start_subitem
  {\c_strc_itemgroups_sub\conditionaltrue
   \startitemgroupitem
   \dotagsetitem\s!sub}

\protected\def\strc_itemgroups_start_edge#text%
  {\strc_itemgroups_start_symbol
     {\strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
      \scratchskip\itemgroupparameter\c!distance\relax
      \dostarttaggednodetail\t!ignore % for the moment, maybe an attribute
      \hbox to \d_strc_itemgroups_list_width
        {\begingroup#text\endgroup\hskip\scratchskip}%
      \dostoptagged}}

\protected\def\strc_itemgroups_start_margin#text%
  {\def\strc_itemgroups_margin_symbol % brrr
     {\dostarttaggednodetail\t!ignore % for the moment, maybe an attribute
      \llap
        {\begingroup
         \useitemgroupstyleandcolor\c!marstyle\c!marcolor
         #text% keep em/ex local
         \endgroup
         \hskip{\leftskip+\leftmargindistance}}%
      \dostoptagged}%
   \startitemgroupitem
   \dotagsetitem\s!margin}

\protected\def\strc_itemgroups_start_text#text%
  {\def\strc_itemgroups_extra_symbol{#text}%
   \c_strc_itemgroups_symbol\conditionaltrue
   \c_strc_itemgroups_txt\conditionaltrue
   \startitemgroupitem}

\protected\tolerant\def\strc_itemgroups_start_items[#1]%
  {\strc_itemgroups_start_edge
     {\localcontrolledloop
        \plusone
        \ifchknumber#1\or\lastchknumber\else0\itemgroupparameter\c!items\fi
        \plusone
        {\strc_itemgroups_used_symbol\hss}%
      \unskip}}

\protected\permanent\def\startspecialitemgroupitem[#name]% todo: frozen
  {\ifcsname\??itemgroupstart#name\endcsname
      \expandafter\lastnamedcs
    \else
      \expandafter\strc_itemgroups_start_do_item
    \fi}

\protected\permanent\def\stopspecialitemgroupitem % todo: frozen
  {\stopitemgroupitem}

\letcsname\??itemgroupstart\v!item\endcsname\strc_itemgroups_start_do_item
\letcsname\??itemgroupstart\v!sub \endcsname\strc_itemgroups_start_subitem
\letcsname\??itemgroupstart\v!sym \endcsname\strc_itemgroups_start_symbol
\letcsname\??itemgroupstart\v!ran \endcsname\strc_itemgroups_start_edge
\letcsname\??itemgroupstart\v!its \endcsname\strc_itemgroups_start_items
\letcsname\??itemgroupstart\v!mar \endcsname\strc_itemgroups_start_margin
\letcsname\??itemgroupstart\v!txt \endcsname\strc_itemgroups_start_text
\letcsname\??itemgroupstart\v!no  \endcsname\strc_itemgroups_start_no_item

\def\strc_itemgroups_optimize_breaks_both
  {\ifcase\c_strc_itemgroups_max_items
   \orelse\ifnum\c_strc_itemgroups_max_items=\plusthree
     \ifnum\c_strc_itemgroups_n_of_items>\plusone
       \strc_itemgroups_insert_nobreak
     \fi
   \orelse\ifnum\c_strc_itemgroups_max_items>\plusthree
     \ifnum\c_strc_itemgroups_n_of_items=\plustwo
       \ifconditional\c_strc_itemgroups_intro
         \strc_itemgroups_insert_breakno
       \else
         \strc_itemgroups_insert_nobreak
       \fi
     \orelse\ifnum\c_strc_itemgroups_max_items=\c_strc_itemgroups_n_of_items\relax
       \strc_itemgroups_insert_nobreak
     \orelse\ifnum\c_strc_itemgroups_n_of_items>\plustwo
       \strc_itemgroups_insert_break
     \orelse\ifconditional\c_strc_itemgroups_intro
     \else
       \strc_itemgroups_insert_break
     \fi
   \fi}

\def\strc_itemgroups_optimize_breaks_first
  {\ifcase\c_strc_itemgroups_max_items
   \orelse\ifnum\c_strc_itemgroups_max_items=\plusthree
     \ifnum\c_strc_itemgroups_n_of_items<\plusthree   % !
       \strc_itemgroups_insert_nobreak                % !
     \else                                            % !
       \strc_itemgroups_insert_break                  % !
     \fi                                              % !
   \orelse\ifnum\c_strc_itemgroups_max_items>\plusthree
     \ifnum\c_strc_itemgroups_n_of_items=\plustwo
       \ifconditional\c_strc_itemgroups_intro
         \strc_itemgroups_insert_breakno
       \else
         \strc_itemgroups_insert_nobreak
       \fi
     \orelse\ifnum\c_strc_itemgroups_max_items=\c_strc_itemgroups_n_of_items\relax
       \strc_itemgroups_insert_break                  % !
     \orelse\ifnum\c_strc_itemgroups_n_of_items>\plustwo
       \strc_itemgroups_insert_break
     \orelse\ifconditional\c_strc_itemgroups_intro
     \else
       \strc_itemgroups_insert_break
     \fi
   \fi}

\def\strc_itemgroups_optimize_breaks_last
  {\ifcase\c_strc_itemgroups_max_items
   \orelse\ifnum\c_strc_itemgroups_max_items=\plusthree
     \ifnum\c_strc_itemgroups_n_of_items>\plustwo % !
       \strc_itemgroups_insert_nobreak            % !
     \else                                        % !
       \strc_itemgroups_insert_break              % !
     \fi                                          % !
   \orelse\ifnum\c_strc_itemgroups_max_items>\plusthree
     \ifnum\c_strc_itemgroups_n_of_items=\plustwo
      \ifconditional\c_strc_itemgroups_intro
        \strc_itemgroups_insert_breakno
      \else
        \strc_itemgroups_insert_break             % !
      \fi
     \orelse\ifnum\c_strc_itemgroups_max_items=\c_strc_itemgroups_n_of_items\relax
       \strc_itemgroups_insert_nobreak
     \orelse\ifnum\c_strc_itemgroups_n_of_items>\plustwo
       \strc_itemgroups_insert_break
     \orelse\ifconditional\c_strc_itemgroups_intro
     \else
       \strc_itemgroups_insert_break
     \fi
   \fi}

\def\strc_itemgroups_optimize_breaks
  {\ifcase\c_strc_itemgroups_column_depth
     \ifcase\c_strc_itemgroups_optimize  % loose
     \or \strc_itemgroups_optimize_breaks_both  % tight
     \or \strc_itemgroups_optimize_breaks_both  % verytight
     \or \strc_itemgroups_optimize_breaks_first % tight:first
     \or \strc_itemgroups_optimize_breaks_last  % tight:last
     \fi
   \fi}

\def\strc_itemgroups_handle_text_item
  {\scratchdimen\wd\b_strc_itemgroups
   \advanceby\scratchdimen{\itemgroupparameter\c!distance}%
   \ifdim\scratchdimen>\d_strc_itemgroups_list_width
     \advanceby\scratchdimen -\d_strc_itemgroups_list_width
   \else
     \scratchdimen\zeropoint
   \fi
   \llap{\hbox to \d_strc_itemgroups_list_width{\ifconditional\c_strc_itemgroups_sub\llap{+\enspace}\fi\box\b_strc_itemgroups\hss}}% was: \hfill
   \hskip\scratchdimen}

\def\strc_itemgroups_handle_lapped_item_positive
  {\llap
     {\dontcomplain
      \hbox to \d_strc_itemgroups_list_width
        {\ifconditional\c_strc_itemgroups_sub
           \dostarttaggednodetail\t!ignore
           \llap{+\enspace}%
           \dostoptagged
         \fi
         \strc_itemgroups_left_sym_filler
         \box\b_strc_itemgroups % can already have a forced widt, only factor handled here
         \hfil
         \hskip{\itemgroupparameter\c!distance}}}}

\def\strc_itemgroups_handle_lapped_item_negative
  {\llap
     {\ifconditional\c_strc_itemgroups_sub
        \dostarttaggednodetail\t!ignore
        \llap{+\enspace}%
        \dostoptagged
      \fi
      \box\b_strc_itemgroups
      \hskip\leftmargindistance}}

\def\strc_itemgroups_handle_groups_text_item
  {\hbox
     {\ifconditional\c_strc_itemgroups_sub
        \dostarttaggednodetail\t!ignore
        +\enspace
        \dostoptagged
      \fi
      \scratchwidth\wd\b_strc_itemgroups
      \box\b_strc_itemgroups
      \ifzerodim\scratchwidth\else
        \hskip\interwordspace % not configureable (yet), could be \c!textdistance
      \fi}%
   \nobreak}

\def\strc_itemgroups_handle_groups_inline_item
  {\hbox to \d_strc_itemgroups_list_width
     {\ifconditional\c_strc_itemgroups_sub
        \dostarttaggednodetail\t!ignore
        \llap{+\enspace}%
        \dostoptagged
      \fi
      \box\b_strc_itemgroups
      \hss}} % was: \hfill

\protected\def\strc_itemgroups_start_head_sym#text%
  {\def\strc_itemgroups_extra_symbol{#text}%
   \c_strc_itemgroups_symbol\conditionaltrue
   \c_strc_itemgroups_head\conditionaltrue
  %\strc_itemgroups_start_head}
   \startitemgrouphead}

\def\strc_itemgroups_make_symbol_box
  {\setbox\b_strc_itemgroups\autodirhbox
     {\ifconditional\c_strc_itemgroups_head
        \ifconditional\c_strc_itemgroups_symbol
          \strc_itemgroups_insert_extra_reference
          \useitemgroupstyleandcolor\c!symstyle\c!symcolor
          \strc_itemgroups_extra_symbol
        \else
          \useitemgroupstyleandcolor\c!headstyle\c!headcolor
          \strc_itemgroups_used_symbol
        \fi
      \else
        \ifconditional\c_strc_itemgroups_symbol
          \strc_itemgroups_insert_extra_reference
          \useitemgroupstyleandcolor\c!symstyle\c!symcolor
          \strc_itemgroups_extra_symbol
        \else
          \useitemgroupstyleandcolor\c!style\c!color
          \strc_itemgroups_used_symbol
        \fi
      \fi}%
   \lettonothing\strc_itemgroups_extra_symbol
   \c_strc_itemgroups_symbol\conditionalfalse}

\def\strc_itemgroups_make_fitting_box
  {\ifdim\wd\b_strc_itemgroups>{\itemgroupparameter\c!maxwidth}%
     \expanded{\global\setitemgroupparameter{\c!maxwidth}{\the\wd\b_strc_itemgroups}}%
   \fi
   \ifdim\d_strc_itemgroups_max_width>\zeropoint
     \setbox\b_strc_itemgroups\simplealignedbox
       {{\d_strc_itemgroups_max_width+(\itemgroupparameter\c!distance)}}%
       {\itemgroupparameter\c!itemalign}%
       {\box\b_strc_itemgroups\hskip{\itemgroupparameter\c!distance}}%
   \fi}

\def\strc_itemgroups_make_aligned_box
  {\ifempty{\itemgroupparameter\c!itemalign}\else
     \setbox\b_strc_itemgroups\simplealignedbox
       {{\d_strc_itemgroups_asked_width+(\itemgroupparameter\c!distance)}}%
       {\itemgroupparameter\c!itemalign}%
       {\box\b_strc_itemgroups\hskip{\itemgroupparameter\c!distance}}%
   \fi}

\def\strc_itemgroups_make_destination_box
  {\iftrialtypesetting \orelse \ifempty\m_strc_itemgroups_destination \else
     \setbox\b_strc_itemgroups\hbox{\directgotobox{\box\b_strc_itemgroups}[\m_strc_itemgroups_destination]}%
   \fi}

\def\strc_itemgroups_check_indenting
  {\c_strc_itemgroups_indented_first\conditionalfalse
   \ifempty\m_strc_itemgroups_indenting \else
     % we'd like to use \useindentingparameter\itemgroupparameter but ...
     \expanded{\setupindenting[\v!reset,\v!yes,\m_strc_itemgroups_indenting]}%
     \ifconditional\c_spac_indentation_indent_first % better is to have a mode
       \ifcstok{\itemgroupparameter\c!alignsymbol}\v!yes\else
         \c_strc_itemgroups_indented_first\conditionaltrue
       \fi
     \fi
   \fi}

\def\strc_itemgroups_check_for_repeated
  {\ifconditional\c_strc_itemgroups_repeat
     \ifempty\m_strc_itemgroups_repeat_start
       \edef\m_strc_itemgroups_repeat_start{\currentitemlevel}%
     \fi
   \else
     \lettonothing\m_strc_itemgroups_repeat_start
   \fi}

\newconditional\c_strc_itemgroups_ignore

\noaligned\permanent\protected\def\startignoreditem % kind of private
  {\global\c_strc_itemgroups_ignore\conditionaltrue
   \startitem}

\noaligned\permanent\protected\def\stopignoreditem % kind of private
  {\stopitem
   \global\c_strc_itemgroups_ignore\conditionalfalse}

\def\strc_itemgroups_insert_item
  {\ifconditional\c_strc_itemgroups_text % again?
    % begin of item
   \orelse\ifconditional\c_strc_itemgroups_no_par % again?
    % begin of item
   \else
     \par % done twice?
   \fi
   \iftrialtypesetting\else
     \global\advanceby\c_strc_itemgroups_n_of_items\plusone
   \fi
   \ifconditional\c_strc_itemgroups_ignore\else
     \strc_itemgroups_optimize_breaks
     \strc_itemgroups_check_indenting
     \dontleavehmode
     \ifconditional\c_strc_itemgroups_indented_first
       \hskip-\parindent
     \fi
     \strc_itemgroups_make_symbol_box
     \strc_itemgroups_make_destination_box
     \ifconditional\c_strc_itemgroups_fitting
       \strc_itemgroups_make_fitting_box
     \orelse\ifdim\d_strc_itemgroups_asked_width>\zeropoint
       \strc_itemgroups_make_aligned_box
     \fi
     \lettonothing\m_strc_itemgroups_destination
     \ht\b_strc_itemgroups\strutheight % just in case a symbols is not yet available in
     \dp\b_strc_itemgroups\strutdepth  % the current run (more a mkii mp side artifact)
     \strc_itemgroups_check_for_repeated
     \ifdim\d_strc_itemgroups_asked_width<\zeropoint\relax
       \strc_itemgroups_handle_lapped_item_negative
     \else
       \ifzeropt\d_strc_itemgroups_asked_width
         \strc_itemgroups_calculate_list_width\plusone
       \else
         \strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
       \fi
       \ifconditional\c_strc_itemgroups_text
         \strc_itemgroups_handle_groups_text_item
       \orelse\ifconditional\c_strc_itemgroups_inline
         \strc_itemgroups_handle_groups_inline_item
       \orelse\ifconditional\c_strc_itemgroups_txt
         \strc_itemgroups_handle_text_item
       \else
         \strc_itemgroups_handle_lapped_item_positive
       \fi
     \fi
     \c_strc_itemgroups_head\conditionalfalse
     \c_strc_itemgroups_sub\conditionalfalse
     \ifconditional\c_strc_itemgroups_indented_first
       \hskip\parindent
     \fi
   \fi
   \ignorepars} % \ignorespaces

\def\strc_itemgroups_start_item_nop
  {\lettonothing\currentitemreference
   \strc_itemgroups_increment_item_counter
   \global\advanceby\c_strc_itemgroups_n_of_items\plusone
   \setbox\b_strc_itemgroups\hbox
     {\useitemgroupstyleandcolor\c!style\c!color
      \strc_itemgroups_used_symbol}%
   \strc_itemgroups_check_for_repeated
   \ignorepars} % \ignorespaces

\defcsname\??itemgroupdistance\v!none\endcsname
  {\let\m_strc_itemgroups_text_distance\zeropoint}

\defcsname\??itemgroupdistance\v!space\endcsname
  {\def\m_strc_itemgroups_text_distance{\interwordspace\s!plus\interwordstretch\s!minus\interwordshrink}}

\defcsname\??itemgroupdistance\endcsname % catches empty value
  {\let\m_strc_itemgroups_text_distance\zeropoint}

\protected\def\strc_itemgroups_set_text_item_distance
  {\edef\m_strc_itemgroups_text_distance{\itemgroupparameter\c!textdistance}%
   \ifempty\m_strc_itemgroups_text_distance
   % \let\m_strc_itemgroups_text_distance\zeropoint % safeguard elsewhere
   \orelse\ifcsname\??itemgroupdistance\m_strc_itemgroups_text_distance\endcsname
     \lastnamedcs
   \else
     \strc_itemgroups_set_text_item_distance_indeed
   \fi}

\def\strc_itemgroups_set_text_item_distance_indeed
  {\assignvalue
     \m_strc_itemgroups_text_distance
     \m_strc_itemgroups_text_distance
     {.5\interwordspace\s!plus.5\emwidth}%
     {\interwordspace  \s!plus  \emwidth}%
     {\emwidth         \s!plus  \interwordstretch\s!minus\interwordshrink}}

% \protected\def\strc_itemgroups_default_command
%   {\EveryPar{\ignorespaces}% needed ?
%    \ignorespaces}

\protected\def\strc_itemgroups_default_command
  {\ignorepars} % \ignorespaces

%D Special case:

\protected\def\strc_itemgroups_head#text\par
  {\startitemgrouphead{#text}}

%D The local commands:

\ifdefined\item             \else         \let\item            \relax \fi % defined later
\ifdefined\sub              \else \aliased\let\sub             \relax \fi
\ifdefined\sym              \else \aliased\let\sym             \relax \fi
\ifdefined\ran              \else \aliased\let\ran             \relax \fi
\ifdefined\its              \else \aliased\let\its             \relax \fi
\ifdefined\mar              \else \aliased\let\mar             \relax \fi
\ifdefined\noitem           \else \aliased\let\noitem          \relax \fi
\ifdefined\itm              \else \aliased\let\itm             \relax \fi
\ifdefined\but              \else \aliased\let\but             \relax \fi
%ifdefined\nop              \else         \let\nop             \relax \fi % used often by myself
\ifdefined\txt              \else \aliased\let\txt             \relax \fi
\ifdefined\head             \else         \let\head            \relax \fi % defined later
\ifdefined\headsym          \else \aliased\let\headsym         \relax \fi
\ifdefined\startitem        \else         \let\startitem       \relax \fi % defined later
\ifdefined\stopitem         \else \aliased\let\stopitem        \relax \fi
\ifdefined\starthead        \else \aliased\let\starthead       \relax \fi
\ifdefined\stophead         \else \aliased\let\stophead        \relax \fi
\ifdefined\startspecialitem \else \aliased\let\startspecialitem\relax \fi
\ifdefined\stopspecialitem  \else \aliased\let\stopspecialitem \relax \fi

\appendtoks
    \enforced\let\item            \strc_itemgroups_start_do_item
    \enforced\let\sub             \strc_itemgroups_start_subitem
    \enforced\let\sym             \strc_itemgroups_start_symbol
    \enforced\let\ran             \strc_itemgroups_start_edge
    \enforced\let\its             \strc_itemgroups_start_items
    \enforced\let\mar             \strc_itemgroups_start_margin
    \enforced\let\noitem          \strc_itemgroups_start_no_item
    \enforced\let\itm             \strc_itemgroups_start_do_item
    \enforced\let\but             \strc_itemgroups_start_button
    \enforced\let\nop             \strc_itemgroups_start_dummy
    \enforced\let\txt             \strc_itemgroups_start_text
    \enforced\let\head            \strc_itemgroups_head
    \enforced\let\headsym         \strc_itemgroups_start_head_sym
    \enforced\let\startitem       \startitemgroupitem
    \enforced\let\stopitem        \stopitemgroupitem
    \enforced\let\starthead       \startitemgrouphead
    \enforced\let\stophead        \stopitemgrouphead
    \enforced\let\startspecialitem\startspecialitemgroupitem
    \enforced\let\stopspecialitem \stopspecialitemgroupitem
\to \itemgroupcommands

\ifx\currentinterface \s!english \else

    \def\next#1#2{\ifcsname#1\endcsname\else\enforced\aliased\letcsname#1\endcsname#2\fi}

    \etoksapp\itemgroupcommands{%
        \next{\v!item        }\strc_itemgroups_start_do_item
        \next{\v!sub         }\strc_itemgroups_start_subitem
        \next{\v!sym         }\strc_itemgroups_start_symbol
        \next{\v!ran         }\strc_itemgroups_start_edge
        \next{\v!head        }\strc_itemgroups_head
        \next{\v!its         }\strc_itemgroups_start_items
        \next{\v!mar         }\strc_itemgroups_start_margin
        \next{\v!txt         }\strc_itemgroups_start_text
        \next{\e!start\v!item}\startitemgroupitem
        \next{\e!stop \v!item}\stopitemgroupitem
        \next{\e!start\v!head}\startitemgrouphead
        \next{\e!stop \v!head}\stopitemgrouphead
    }

  % \let\next\relax

\fi

\relaxvalueifundefined \v!item
\relaxvalueifundefined \v!sub
\relaxvalueifundefined \v!sym
\relaxvalueifundefined \v!ran
\relaxvalueifundefined \v!head
\relaxvalueifundefined \v!its
\relaxvalueifundefined \v!mar
\relaxvalueifundefined \v!txt
\relaxvalueifundefined {\e!start\v!item}
\relaxvalueifundefined {\e!stop \v!item}
\relaxvalueifundefined {\e!start\v!head}
\relaxvalueifundefined {\e!stop \v!head}

%D A nice example of a plugin:
%D
%D \startbuffer
%D \startitemize[a,random,packed]
%D \startitem first  \stopitem \startitem second \stopitem
%D \startitem third  \stopitem \startitem fourth \stopitem
%D \stopitemize
%D
%D \startitemize[a,random,packed]
%D \startitem first  \stopitem \startitem second \stopitem
%D \startitem third  \stopitem \startitem fourth \stopitem
%D \stopitemize
%D
%D \startitemize[a,packed]
%D \startitem first  \stopitem \startitem second \stopitem
%D \startitem third  \stopitem \startitem fourth \stopitem
%D \stopitemize
%D \stopbuffer
%D
%D \typebuffer \getbuffer

% better collectitems als conditional and a real plugin mechanism (some day)

\newinteger\c_strc_itemgroups_collected_stored
\newinteger\c_strc_itemgroups_collected_done
\newinteger\c_strc_itemgroups_collected_current

\let\strc_itemgroups_collected_store\relax

\lettonothing\m_strc_itemgroups_after
\lettonothing\m_strc_itemgroups_collected
\lettonothing\m_strc_itemgroups_destination
\lettonothing\m_strc_itemgroups_inbetween
\lettonothing\m_strc_itemgroups_indenting
\lettonothing\m_strc_itemgroups_repeat_start
\lettonothing\m_strc_itemgroups_saved
\lettonothing\m_strc_itemgroups_spacing
\lettonothing\m_strc_itemgroups_text_distance

\expanded{\def\strc_itemgroups_collected_store#1\csname\e!stop\v!item\endcsname}%
  {\advanceby\c_strc_itemgroups_collected_stored\plusone
   \defcsname\??itemgroupstack\the\c_strc_itemgroups_collected_stored\endcsname
     {\startitemgroupitem#1\stopitemgroupitem}}

\def\strc_itemgroups_collected_flush_randomize
  {\m_strc_itemgroups_collected}

\def\strc_itemgroups_collected_flush_horizontal
  {\begingroup
   \scratchcounter\itemgroupparameter\c!n\relax
   \ifnum\c_strc_itemgroups_collected_done>\plusone
     \ifcase\modulonumber\scratchcounter\c_strc_itemgroups_collected_done\relax
       % compensate for rounding errors
       \hfill % \hskip\zeropoint plus \scaledpoint minus \scaledpoint
       \allowbreak
     \fi
   \fi
   \noindent % no \dontleavehmode
   \hbox to {\availablehsize/\scratchcounter}{\m_strc_itemgroups_collected\hss}%
   \endgroup}

\def\strc_itemgroups_collected_flush_indeed
  {\m_strc_itemgroups_collected
   \letcsname\??itemgroupstack\the\c_strc_itemgroups_collected_current\endcsname\undefined}

\def\strc_itemgroups_collected_flush
  {\ifconditional\c_strc_itemgroups_randomize
     \getrandomcount\c_strc_itemgroups_collected_current\plusone\c_strc_itemgroups_collected_stored
   \else
     \advanceby\c_strc_itemgroups_collected_current\plusone
   \fi
   \ifcsname\??itemgroupstack\the\c_strc_itemgroups_collected_current\endcsname
     \edef\m_strc_itemgroups_collected{\lastnamedcs}%
     \ifconditional\c_strc_itemgroups_horizontal
       \strc_itemgroups_collected_flush_horizontal
     \else
       \strc_itemgroups_collected_flush_indeed
     \fi
     \advanceby\c_strc_itemgroups_collected_done\plusone
   \fi
   \ifnum\c_strc_itemgroups_collected_done<\c_strc_itemgroups_collected_stored
     \expandafter\strc_itemgroups_collected_flush
   \fi}

\protected\permanent\def\stopcollectitems % todo: frozen
  {\ifconditional\c_strc_itemgroups_collecting
     \c_strc_itemgroups_collected_done   \zerocount
     \c_strc_itemgroups_collected_current\zerocount
     \ifnum\c_strc_itemgroups_collected_stored>\zerocount
       \ifconditional\c_strc_itemgroups_horizontal
         \strc_itemgroups_before_command
         \c_strc_itemgroups_first\conditionalfalse
         \strc_itemgroups_collected_flush
        %\strc_itemgroups_after_command % triggered elsewhere
       \else
         \strc_itemgroups_collected_flush
       \fi
     \fi
   \fi}

\protected\permanent\def\startcollectitems % todo: frozen
  {\ifconditional\c_strc_itemgroups_collecting
     \c_strc_itemgroups_collected_stored\zerocount
     \enforced\letcsname\e!start\v!item\endcsname\strc_itemgroups_collected_store
   \fi}

%D Left-overs:

\permanent\protected\def\item % todo: frozen
  {\strc_itemgroups_item_alone}

\tolerant\def\strc_itemgroups_item_alone[#category]#:#text\par
  {\ifempty{#category}%
     \startitemgroup[\v!itemize]%
   \else
     \startitemgroup[#category]%
   \fi
   \startitem#text\stopitem
   \stopitemgroup}

\permanent\protected\def\head % todo: frozen
  {\strc_itemgroups_head_alone}

\def\strc_itemgroups_head_alone[#category]#head\par#body\par
  {\ifempty{#category}%
     \startitemgroup[\v!itemize]%
   \else
     \startitemgroup[#category]%
   \fi
   \starthead{#head}#body\stophead
   \stopitemgroup}

\pushoverloadmode

\permanent\protected\defcsname\e!start\v!item\endcsname
  {\startitemgroup[\v!itemize]%
   \startitemgroupitem
   \enforced\letcsname\e!stop\v!item\endcsname\strc_itemgroups_stop_item}

\aliased\letcsname\e!stop\v!item\endcsname\relax

\permanent\protected\def\strc_itemgroups_stop_item
  {\stopitemgroupitem
   \stopitemgroup}

\popoverloadmode

% \def\sym#text%
%   {\noindent
%    \begingroup
%    \setbox\scratchbox\hbox{\settrialtypesetting#text}%
%    \setbox\scratchbox\hbox\ifdim\wd\scratchbox<1em to 1.5\else spread 1\fi em{#text\hfil}%
%    \expanded{\box\scratchbox\endgroup\hangindent\the\wd\scratchbox}%
%    \ignorepars} % \ignorespaces

%D End of plugin.

%D Something for tables:

\permanent\tolerant\protected\def\itemtag[#reference]% we can reuse more
  {% what if empty
   \def\currentitemreference{#reference}%
   \iftrialtypesetting
     \strc_counters_save\v_strc_itemgroups_counter
     \strc_itemgroups_increment_item_counter
     \strc_itemgroups_insert_item_tag_indeed
     \strc_counters_restore\v_strc_itemgroups_counter
   \else
     \strc_itemgroups_increment_item_counter
     \strc_itemgroups_insert_item_tag_indeed
   \fi}

\def\strc_itemgroups_insert_item_tag_indeed
  {\letitemgroupparameter\c!distance\zeropoint
   %letitemgroupparameter\c!width\zeropoint
   \strc_itemgroups_make_symbol_box
   \strc_itemgroups_make_destination_box
   \lettonothing\m_strc_itemgroups_destination
   \ht\b_strc_itemgroups\strutheight
   \dp\b_strc_itemgroups\strutdepth
   \box\b_strc_itemgroups
   \ignorepars} % \ignorespaces

%D New per 2023-08-01

\newdimension\d_strc_itemgroups_inbetween_table
\newdimension\d_strc_itemgroups_column_distance
\newdimension\d_strc_itemgroups_column_width

\def\strc_itemgroups_table_begin
  {\NC}

\def\strc_itemgroups_table_end_row
  {\NR
   \ifzerodim\d_strc_itemgroups_inbetween_table\orelse\ifnum % todo
     \numexpr\c_strc_itemgroups_n_of_items/\c_strc_itemgroups_columns\relax
    <\numexpr\c_strc_itemgroups_max_items /\c_strc_itemgroups_columns\relax
        \noalign{\m_strc_itemgroups_inbetween}%
      % \TB[\the\d_strc_itemgroups_inbetween_table]%
   \fi}

\noaligned\def\strc_itemgroups_table_end
  {\ifcase{\c_strc_itemgroups_n_of_items mod \c_strc_itemgroups_columns}%
     \expandafter\strc_itemgroups_table_end_row
   \fi}

\protected\def\strc_itemgroups_table_wrapup
  {\iftrialtypesetting\orelse\ifcase\c_tabl_tabulate_column\else
     \beginlocalcontrol % horrible hack to prevens crcr issues
     \expandafter\endlocalcontrol\expandedloop
       {\c_tabl_tabulate_column+\plusone}%
       \c_tabl_tabulate_nofcolumns
       \plusone
       {\startignoreditem\strut\stopignoreditem}%
   \fi}

\let\strc_itemgroups_table_pickup\relax

\setupitemgroup[\c!columndistance=\emwidth]

\tolerant\permanent\protected\def\strc_itemgroups_start_table[#1]#*[#S#2]#*[#S#3]%
  {\ifcase\currentitemlevel\relax
     \startitemgroup[#1][#2][#3]%
     \itemgroupparameter\c!before
   \orelse\ifhmode
     \strut
     \startitemgroup[#1][#2][#3]%
     \ifconditional\c_strc_itemgroups_overlay
       \blank[\v!overlay]%
     \else
       \itemgroupparameter\c!before
     \fi
   \else
     \startitemgroup[#1][#2][#3]%
     \itemgroupparameter\c!before
   \fi
   \edef\m_strc_itemgroups_after    {\itemgroupparameter\c!after}%
   \edef\m_strc_itemgroups_inbetween{\itemgroupparameter\c!inbetween}%
   \setbox\scratchbox\vbox{\m_strc_itemgroups_inbetween}%
   \d_strc_itemgroups_inbetween_table\htdp\scratchbox
   \letitemgroupparameter\c!before\relax
   \letitemgroupparameter\c!after\relax
   \letitemgroupparameter\c!inbetween\relax
   \c_strc_itemgroups_columns\itemgroupparameter\c!n
   \let\strc_itemgroups_begin\strc_itemgroups_table_begin
   \let\strc_itemgroups_end  \strc_itemgroups_table_end
   %
   % horrible ... we have \dividebydsize\textwidth{1em}{3}
   %
   \scratchdistance{\itemgroupparameter\c!columndistance}%
   \d_strc_itemgroups_column_distance{\leftskip+\rightskip}%
   \d_strc_itemgroups_column_width\hsize
   \c_strc_itemgroups_no_par\conditionaltrue % blocks a par that interferes with tagging
   \advanceby\d_strc_itemgroups_column_width   -\c_strc_itemgroups_columns\d_strc_itemgroups_column_distance
   \divideby \d_strc_itemgroups_column_width    \c_strc_itemgroups_columns
   \advanceby\d_strc_itemgroups_column_distance \scratchdistance
   \advanceby\d_strc_itemgroups_column_width   -\scratchdistance
   \advanceby\d_strc_itemgroups_column_width    {\scratchdistance/\c_strc_itemgroups_columns}%
   %
   \c_strc_itemgroups_optimize\zerocount % otherwise we inject vertical breaks between struts
   % inlining confusses the verbose name parser
   \expanded{\strc_itemgroups_table_bootstrap
     \csname\e!start#1\v!table\endcsname
     \csname\e!stop #1\v!table\endcsname % watch the 'l' specification below, maybe a format key
     {\expandedrepeat \c_strc_itemgroups_columns {|p(\the\d_strc_itemgroups_column_width)l}|}}}

\protected\def\strc_itemgroups_table_bootstrap#1#2#3%
  {\protected\def\strc_itemgroups_table_pickup##L#1##R#2##1%
     {\tabl_tabulate_disable_tagging
      \starttabulate[#3][\c!before=,\c!after=,\c!split=\v!no,\c!unit=\the\d_strc_itemgroups_column_distance]%
        ##1\relax\strc_itemgroups_table_wrapup
      \stoptabulate
      \expanded{\stopitemgroup\m_strc_itemgroups_after}}%
   \strc_itemgroups_table_pickup}

\appendtoks
    \protected\frozen\instance\edefcsname\e!stop \currentitemgroup\v!table\endcsname
      {}% {\strc_itemgroups_stop_table}
    \protected\frozen\instance\edefcsname\e!start\currentitemgroup\v!table\endcsname
      {\strc_itemgroups_start_table[\currentitemgroup]}%
\to \everydefineitemgroup

%D Done again.

\setupitemgroup
  [\c!margin=\zeropoint,
   \c!leftmargin=\zeropoint,
   \c!rightmargin=\zeropoint,
   \c!leftmargindistance=\zeropoint,
   \c!rightmargindistance=\zeropoint,
   \c!indentnext=\v!yes,
   \c!width=1.5\emwidth,
   \c!factor=0,
  %\c!distance=.5em, % is now:
   \c!step=.5\emwidth, % deals with broad
   \c!distance=\zeropoint,
  %\c!align=\v!normal, % definitely not \v!normal !
  %\c!symalign=,
  %\c!color=,
  %\c!indenting=, % untouched if empty
  %\c!style=,
   \c!marstyle=\v!type,
  %\c!symstyle=,
  %\c!headstyle=,
  %\c!marcolor=,
  %\c!symcolor=,
  %\c!headcolor=,
  %\c!beforehead=,
   \c!symcolor=\itemgroupparameter\c!color, % new per 2012.01.17
   \c!symstyle=\itemgroupparameter\c!style, % new per 2012.01.17
   \c!afterhead=\blank,
   \c!before=\blank,
   \c!inbetween=\blank,
   \c!after=\blank,
  %\c!stopper=.,
   \c!placestopper=\v!yes,
   \c!stopper=.,
  %\c!inner=,
   \c!n=2,
   \c!items=4,
   \c!levels=10,
   \c!lefttext=(,
   \c!righttext=),
   \c!start=1,
   \c!packcriterium=\zerocount,
   \c!criterium=\v!all, % permits 0 and negative numbers
  %\c!option=,
   \c!textdistance=\v!space, % none big medium small <dimension>
   \c!lasttextseparator=\itemgroupparameter\c!textseparator,
  %\c!lasttextseparator=,
   \c!command=\strc_itemgroups_default_command,
   \c!indenting=\v!next,
  %\c!alignsymbol=v!no,
   \c!symbol=\currentitemlevel,
   \c!prefix=\v!no,
  %\c!prefixstopper=.,
  %\c!prefixseparatorset=,
  %\c!prefixconversion=,
  %\c!prefixconversionset=,
  %\c!prefixset=,
  %\c!prefixsegments=1:100,
   \c!prefixconnector=.,
   \c!numberseparatorset=,
   \c!numberconversionset=,
   \c!numberstopper=.,
   \c!numbersegments=1]

\defineitemgroup
  [\v!itemize]

%D This is really ugly I should get rid of the global mess, whuch is a side
%D effect of the simple \type {\item} interface that we're stuck with for
%D compatibility reasons. See footnotes for usage. It's probablynot robust
%D for mixed itemgroups so in the end I need to get rid of the globals. One
%D problem is that counters are set.

\defineitemgroup
  [\v!itemize:\v!note]

\def\strc_itemgroups_push
  {\edef\strc_itemgroups_pop
     {\xdef\noexpand\currentitemlevel{\currentitemlevel}%
      \global\c_strc_itemgroups_nesting     \the\c_strc_itemgroups_nesting     \relax
      \global\c_strc_itemgroups_column_depth\the\c_strc_itemgroups_column_depth\relax}%
   \global\c_strc_itemgroups_column_depth\zerocount
   \global\c_strc_itemgroups_nesting     \zerocount
   \glet\currentitemlevel\!!zerocount
   \enforced\permanent\protected\def\startitemize{\startitemgroup[\v!itemize:\v!note]}%
   \enforced\permanent\protected\def\stopitemize {\stopitemgroup}}

\let\strc_itemgroups_pop\relax

\protect \endinput
