% \iffalse meta-comment
%
%% File: fancytm.dtx
%
% Copyright (C) 2022 Maximilian Keßler
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% -----------------------------------------------------------------------
%<package>\ProvidesExplPackage{fancythm}{2022/01/17}{0.0.1}{Grouped theorems.}
%
%<*driver>
\documentclass[full,kernel]{l3doc}
\usepackage{mkessler-todo}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{fancythm} package^^A
% }
%
% \author{^^A
%      Maximilian Keßler
% }
%
% \date{Released 2022-01-12}
%
% \maketitle
%
% \begin{documentation}
% \end{documentation}
% 
% 
% \begin{implementation}
% 
% \section{\pkg{fancythm} implementation}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=fancythm>
%    \end{macrocode}
%
%
%  \subsection{Dependencies}
%    \begin{macrocode}
\RequirePackage{l3keys2e}
\RequirePackage{groupthm}
\RequirePackage[default styles]{mkessler-thmstyle}
%    \end{macrocode}
%
%  \subsection{Counter management}
%
%
% Wrappers for \LaTeX2e counter manipulation
%
%
% \begin{macro}{\arabic:n, \counter_new:n, \counter_within:nn,\counter_new:nn}
%		 
%   Obvious meanings.     
%
%    \begin{macrocode}
\cs_set_eq:NN \arabic:n \arabic
\cs_set_eq:NN \counter_new:n \newcounter
\cs_set_eq:NN \counter_within:nn \counterwithin
\cs_new:Npn \counter_new:nn #1 #2
  {
    \counter_new:n { #1 }
    \counter_within:nn { #1 } { #2 }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% \begin{macro}
%   {
%     \counter_if_exist_p:n,
%     \counter_if_exist:nT,
%     \counter_if_exist:F,
%     \counter_if_exist:nTF,
%   }
%		 
%     
%
%    \begin{macrocode}
\cs_new:Npn \counter_if_exist_p:n #1 
  {
    \cs_if_exist_p:c { c@ #1 }
  }
\cs_new:Npn \counter_if_exist:nT #1
  {
    \cs_if_exist:cT { c@ #1 }
  }
\cs_new:Npn \counter_if_exist:nF #1
  {
    \cs_if_exist:cF { c@ #1 }
  }
\cs_new:Npn \counter_if_exist:nTF #1
  {
    \cs_if_exist:cTF { c@ #1 }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\counter_undefined_error:n}
%		 
%     Standard counter error message.     
%
%    \begin{macrocode}
\cs_set_eq:Nc \counter_undefined_error:n { @nocounterr }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% \begin{macro}{\counter_ensure_exist:n}
%		 
%     
%
%    \begin{macrocode}
\cs_new:Npn \counter_ensure_exist:n #1 
  {
    \counter_if_exist:nF { #1 }
      {
        \counter_undefined_error:n { #1 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
%
% \begin{macro}{\counter_the:n, \counter_set_the:nn}
%     
%
%    \begin{macrocode}
\cs_new:Npn \counter_the:n #1
  {
    \use:c { the #1 }
  }
\cs_new:Npn \counter_set_the:nn #1 #2
  {
    \counter_ensure_exist:n { #1 }
    \exp_args:Nc \renewcommand { the #1 } { #2 }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% \begin{macro}{\counter_sub:nn}
%    \begin{syntax}
%       \cs{counter_sub:nn}\marg{counter_1}\marg{counter_2}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\cs_new:Npn \counter_sub:nn #1 #2
  {
    \counter_within:nn { #1 } { #2 }
    \counter_set_the:nn { #1 } 
    {
      \counter_the:n { #2 } . \arabic:n { #1 }
    }
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\counter_new_sub:nn #1 #2}
%		 
%     
%
%    \begin{macrocode}
\cs_new:Npn \counter_new_sub:nn #1 #2
  {
    \counter_new:n { #1 }
    \counter_sub:nn { #1 } { #2 }
  }

%    \end{macrocode}
% \end{macro}
%
% \subsection{Counter management}
% 
% 
%
% \begin{macro}{\@@_counter_sub_if_exist:n}
%		 
%     
%
%    \begin{macrocode}
\cs_new:Npn \@@_counter_sub_if_exist:n #1
  {
    \counter_if_exist:nT { #1 }
      {
        \counter_new_sub:nn { in #1 } { #1 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% 
%
% \begin{macro}{\counter_alias:nn, \counter_alias:nx}
%    \begin{syntax}
%       \cs{counter_alias:nn}\marg{counter_1}\marg{counter_2}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\cs_set_eq:Nc \counter_alias:nn { @counteralias }
\cs_generate_variant:Nn \counter_alias:nn { n x }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% 
% 
%   \subsection{Initialization}
% 
% 
%
% \begin{variable}{indocument, insection, insubsection, inchapter, inpart}
%		 
%     
%
%    \begin{macrocode}
\counter_new:n { indocument }
\@@_counter_sub_if_exist:n { section }
\@@_counter_sub_if_exist:n { subsection }
\@@_counter_sub_if_exist:n { chapter }
\@@_counter_sub_if_exist:n { part }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{toplevel, sublevel, subsublevel, subsubsublevel}
%		 
%     Note that the \texttt{toplevel} counter will be potentially redefined
%     by the given package options.
%
%    \begin{macrocode}
\counter_alias:nn   { toplevel       } { indocument  }
\counter_new_sub:nn { sublevel       } { toplevel    }
\counter_new_sub:nn { subsublevel    } { sublevel    }
\counter_new_sub:nn { subsubsublevel } { subsublevel }
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{variable}{\g_@@_style_str}
%		 
%     This will hold the style information of the package.
%
%    \begin{macrocode}
\str_new:N \g_@@_style_str
%    \end{macrocode}
% \end{variable}
% 
% \begin{variable}{\g_@@_translator_bool}
%		 
%     
%
%    \begin{macrocode}
\bool_new:N \g_@@_translator_bool
%    \end{macrocode}
% \end{variable}
% 
% 
% \begin{variable}{\g_@@_generate_defaults_bool}
%		 
%     
%
%    \begin{macrocode}
\bool_new:N \g_@@_generate_defaults_bool
%    \end{macrocode}
% \end{variable}
% 
% 
% 
% 
% \begin{variable}
%   {
%     \l_@@_key_name_tl,
%     \l_@@_key_mdframed_tl,
%     \l_@@_key_style_tl,
%     \l_@@_key_group_clist,
%     \l_@@_key_thmtools_clist,
%   }
%     
%
%    \begin{macrocode}
\tl_new:N    \l_@@_key_name_tl
\tl_new:N    \l_@@_key_mdframed_tl
\tl_new:N    \l_@@_key_style_tl
\clist_new:N \l_@@_key_group_clist
\clist_new:N \l_@@_key_thmtools_clist
%    \end{macrocode}
% \end{variable}
% 
% 
%
% \begin{variable}
%   {
%     \l_@@_name_tl,
%     \l_@@_thmtools_clist,
%     \l_@@_group_clist,
%   }
%     
%
%    \begin{macrocode}
\tl_new:N    \l_@@_name_tl
\clist_new:N \l_@@_thmtools_clist
\clist_new:N \l_@@_group_clist
%    \end{macrocode}
% \end{variable}
% 
%    \subsection{Key interface}
% 
% \begin{texnote}
%  Note that unfortunately, none of the keynames really containes a space.
%  \LaTeX2e strips spaces before loading a package, so introducing them here
%  would make them inaccessible.
%  Here they are ignored by \LaTeX3 and are present for readability.
% \end{texnote}
%
%
%    \begin{macrocode}
\keys_define:nn { fancythm }
  {
    translator        .bool_set:N   = \g_@@_translator_bool        ,
    translator        .default:n    = { true }                            ,
    generate defaults .bool_set:N   = \g_@@_generate_defaults_bool ,
    generate defaults .default:n    = { true }                            ,
    number in         .choices:nn   =
      { document, section, subsection, chapter, part }
      {
        \counter_alias:nx { toplevel } { in \tl_use:N \l_keys_choice_tl }
      }                                                                   ,
    number in         .default:n    = { document }                        ,
    style             .choices:nn   =
      { fancy, plain, classic }
      { 
        \str_set:Nn \g_@@_style_str { \tl_use:N \l_keys_choice_tl }
      }                                                                   ,
    style             .default:n    = { fancy }                           ,
  }
%    \end{macrocode}
% 
% 
%
%
% 
%
%    \begin{macrocode}
\keys_define:nn { fancythm / fancytheorem } 
  {
    name            .tl_set:N      = \l_@@_key_name_tl           ,
    name            .default:n     = \c_novalue_tl               ,
    mdframed        .tl_set:N      = \l_@@_key_mdframed_tl       ,
    mdframed        .default:n     = \c_novalue_tl               ,
    style           .tl_set:N      = \l_@@_key_style_tl          ,
    style           .default:n     = \c_novalue_tl               ,
    group           .clist_set:N   = \l_@@_key_group_clist       ,
    group           .default:n     = {}                          ,
    thmtools        .clist_set:N   = \l_@@_key_thmtools_clist    ,
    thmtools        .default:n     = {}                          ,
  }
%    \end{macrocode}
% 
% 
%    Process the given keys:
%
%    \begin{macrocode}
\ProcessKeysOptions{ fancythm }
%    \end{macrocode}
% 
% 
% 
% 
%    This sets up translation if requested.
%    Throughout implementation, we can just use \cs{@@_translate:n}
%    and will (or not) have translation according to the specified options.
%  
%    \begin{macrocode}
\bool_if:NTF \g_@@_translator_bool
  {
    \RequirePackage{translator}
    \usedictionary{translator-environment-names}
    \cs_set_eq:NN \@@_translate:n \translate
  }
  {
    \cs_set_eq:NN \@@_translate:n \use:n
  }
%    \end{macrocode}
%
% 
% 
%
% \begin{macro}{\@@_set_normalized_keys:nn}
%   
%   \begin{syntax}
%     \cs{@@_set_normalized_keys:nn}\marg{keys}\marg{fallback name}
%   \end{syntax}
%     
%
%    \begin{macrocode}
\cs_new:Npn \@@_set_normalized_keys:nn #1 #2
  {
    \keys_set:nn { fancythm / fancytheorem } { name, mdframed, style, group, thmtools }
    \keys_set:nn { fancythm / fancytheorem } { #1 }
    \clist_set_eq:NN \l_@@_group_clist \l_@@_key_group_clist
    \clist_set_eq:NN \l_@@_thmtools_clist \l_@@_key_thmtools_clist
    \tl_if_eq:NnF \l_@@_key_mdframed_tl { \c_novalue_tl }
      {
        \clist_put_right:Nx \l_@@_thmtools_clist
          {
            mdframed = { style = \tl_use:N \l_@@_key_mdframed_tl }
          }
      }
    \tl_if_eq:NnF \l_@@_key_style_tl { \c_novalue_tl }
      {
        \clist_put_right:Nx \l_@@_thmtools_clist
          {
            style = \tl_use:N \l_@@_key_style_tl
          }
      }
    \tl_if_eq:NnTF \l_@@_key_name_tl { \c_novalue_tl }
      {
        \tl_set:Nx \l_@@_name_tl
        {
          \text_titlecase_first:n { \tl_trim_spaces:n { #2 } }
        }
      }
      {
        \tl_set_eq:NN \l_@@_name_tl \l_@@_key_name_tl
      }
    \tl_set:Nx \l_@@_name_tl
      {
        \exp_not:N \@@_translate:n { \tl_use:N \l_@@_name_tl }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_wrap_multiple:nnn}
%    \begin{syntax}
%       \cs{@@_wrap_multiple:nnn}\marg{declarator list}\marg{function name}\marg{code}
%    \end{syntax}
%		 
%    Defines \meta{function name}, which is assumed to contain \cs{declarator}
%    by \meta{code} for each declarator in \meta{declarator list}.
%
%    \begin{macrocode}
\cs_new:Npn \@@_wrap_multiple:nnn #1 #2 #3
  {
    \cs_set:Npn \@@_map_aux:n ##1
      {
        \cs_new:cn { #2 }
          {
            #3
          }
      }
    \clist_map_function:nN { #1 } \@@_map_aux:n
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\fancythm_new_theorem:nnnn, \fancythm_provide_theorem:nnnn}
%    \begin{syntax}
%       \cs{fancythm_new_theorem:nnnn}\marg{fancy theorem}\marg{groups}
%       \marg{name}\marg{thmtools keys}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\@@_wrap_multiple:nnn
{ new, provide }
{ fancythm_#1_theorem:nnnn }
  {
    \use:c { groupthm_#1_family:nnnnn } { ##1 } { dagger, star } { ##3 } { ##4 } { ##2 }
    \use:c { groupthm_#1_family_options:nnnn }
      { ##1 }
      { !s !t+ }
      {
        \IfBooleanT { ####1 } 
          {
            \groupthm_add_theorem_to_group:n { star }
          }
        \IfBooleanT { ####2 }
          {
            \groupthm_add_theorem_to_group:n { dagger }
          }
      }
      { ##2 }
  }
\cs_generate_variant:Nn \fancythm_new_theorem:nnnn { n V V V }
\cs_generate_variant:Nn \fancythm_provide_theorem:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
%
% 
%
% \begin{macro}{\fancythm_new_theorem:nn}
%    \begin{syntax}
%       \cs{fanythm_new_theorem:nn}\marg{key=value list}\marg{fancy theorem}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\@@_wrap_multiple:nnn
{ new, provide }
{ fancythm_#1_theorem:nn }
  {
    \@@_set_normalized_keys:nn { ##1 } { ##2 }
    \use:c { fancythm_#1_theorem:nVVV }
      { ##2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\@@_new_document_command:Nnn, \@@_new_document_command:cnn}
%		 
%   Private wrappers around \cs{NewDocumentCommand}.
%
%    \begin{macrocode}
\cs_new:Npn \@@_new_document_command:Nnn #1 #2 #3
  {
    \NewDocumentCommand { #1 } { #2 } { #3 }
  }
\cs_generate_variant:Nn \@@_new_document_command:Nnn { c n n }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\@@_wrap_multiple_document:nnnn}
%    \begin{syntax}
%       \cs{@@_wrap_multiple_document:nnnn}\marg{declarator list}\marg{function name}\marg{arg spec}\marg{code}
%    \end{syntax}
%		 
%     This is very similar to \cs{@@_wrap_multiple:nnn}, except that it produces document commands.
%     For this reason, \cs{declarator} and \cs{Declarator} are available to refer to the lower
%     and upper-case versions of the current declarator.
%
%    \begin{macrocode}
\cs_new:Npn \@@_wrap_multiple_document:nnnn #1 #2 #3 #4
  {
    \cs_set:Npn \@@_map_aux:n ##1
      {
        \cs_set:Nn \@@_Declarator: { \text_titlecase_first:n { ##1 } }
        \@@_new_document_command:cnn { #2 } { #3 } { #4 }
      }
    \clist_map_function:nN { #1 } \@@_map_aux:n
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% 
%
% \begin{macro}{\NewFancyTheorem, \ProvideFancyTheorem}
%    \begin{syntax}
%       \cs{NewFancyTheorem}\marg{key=value list}\marg{fancy theorem}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\@@_wrap_multiple_document:nnnn
  { new, provide }
  { \@@_Declarator: FancyTheorem }
  { O{} m }
  {
    \use:c { fancythm_#1_theorem:nn } { ##1 } { ##2 }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
%  \subsection{Provided resources} 
%
% 
%  We introduce various new theorem groups that help us to organize the document
%  in a flexible way.
%
% \begin{variable}{star, dagger, big, small, tiny, custom}
%     
%
%    \begin{macrocode}
\groupthm_new_group:nnnnn { star   } { } { *      } { } { }
\groupthm_new_group:nnnnn { dagger } { } { $^{\dagger}$ } { } { }
\groupthm_new_group:nnnnn { big    } { } {        } { } { sibling = toplevel }
\groupthm_new_group:nnnnn { small  } { } {        } { } { sibling = sublevel }
\groupthm_new_group:nnnnn { tiny   } { } {        } { } { numbered = no      }
\groupthm_new_group:nnnnn { custom } { } {        } { } { sibling = sublevel }
%    \end{macrocode}
% \end{variable}
% 
%
%    \begin{macrocode}
\groupthm_add_parent:nn { star   } { custom }
\groupthm_add_parent:nn { dagger } { custom }
%    \end{macrocode}
%    \begin{macrocode}
\DeclareTheoremGroupRule [ suffix ] { dagger  } { higher } { star     }
\DeclareTheoremGroupRule            { tiny    } { higher } { small    }
\DeclareTheoremGroupRule            { tiny    } { higher } { big      }
\DeclareTheoremGroupRule            { tiny    } { higher } { custom   }
\DeclareTheoremGroupRule            { small   } { higher } { big      }
\DeclareTheoremGroupRule            { custom  } { higher } { big      }
%    \end{macrocode}
% 
% 
%   It remains to provide a list of theorems at the beginning of the document.
% 
% 
% 
% 
%    \begin{macrocode}
\AddToHook { begindocument / before } [ fancythm ]
  {
    \ProvideFancyTheorem [ group = big, style = thmgreenmargin ] { example }
  }
%    \end{macrocode}
% 
% 
% 
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
%   \end{implementation}
% 
% 
% 
% \newpage
