% \iffalse meta-comment
% An Infrastructure for Problems 
% Copyright (c) 2019 Michael Kohlhase, all rights reserved
%               this file is released under the
%               LaTeX Project Public License (LPPL)
% The original of this file is in the public repository at 
% http://github.com/sLaTeX/sTeX/
% \fi
% 
% \iffalse
%
%<*driver>
\def\stexdocpath{../doc}
\input{\stexdocpath/stex-docheader}
\stextoptitle{The \texttt{problem} Package}{problem}
\docmodule
%</driver>
% \fi
% 
% \begin{stexmanual}
%    \begin{sfragment}{Problem Manual}
%      \input{\stexdocpath/packages/stex-problem}
%    \end{sfragment}
% \end{stexmanual}
%
% \begin{documentation}
%    \begin{sfragment}{Problem Documentation}
%       TODO
%    \end{sfragment}
% \end{documentation}
%
% \begin{implementation}
%
% \section{Implementation: The problem Package} 
% 
% \subsection{Package Options}\label{sec:impl:options}
% 
% The first step is to declare (a few) package options that handle whether certain
% information is printed or not. They all come with their own conditionals that are set by
% the options.
%
%    \begin{macrocode}
%<*package>
%<@@=problems>
\ProvidesExplPackage{problem}{2025/11/11}{4.0.0}{Semantic Markup for Problems}
\RequirePackage{l3keys2e}

\keys_define:nn { problem / pkg }{
  notes     .default:n    = { true },
  notes     .bool_set:N   = \c_@@_notes_bool,
  gnotes    .default:n    = { true },
  gnotes    .bool_set:N   = \c_@@_gnotes_bool,
  hints     .default:n    = { true },
  hints     .bool_set:N   = \c_@@_hints_bool,
  solutions .default:n    = { true },
  solutions .bool_set:N   = \c_@@_solutions_bool,
  pts       .default:n    = { true },
  pts       .bool_set:N   = \c_@@_pts_bool,
  min       .default:n    = { true },
  min       .bool_set:N   = \c_@@_min_bool,
  %boxed     .default:n    = { true },
  %boxed     .bool_set:N   = \c_@@_boxed_bool,
  test     .default:n    = { true },
  test     .bool_set:N   = \c_@@_test_bool,
  unknown     .code:n       = {
    \PassOptionsToPackage{\CurrentOption}{stex}
  }
}
\newif\ifsolutions

\ProcessKeysOptions{ problem / pkg }
\bool_if:NTF \c_@@_solutions_bool {
  \solutionstrue
}{
  \solutionsfalse
}
\newif\ifintest
\bool_if:NTF \c_@@_test_bool {
  \intesttrue
}{
  \intestfalse
}

\RequirePackage{stex}

\newcommand\precondition[2]{
  \stex_get_symbol:n{#2}
  \tl_if_empty:NF \l_stex_get_symbol_uri {
    \str_case:nnTF {#1}{
      {remember}{}
      {understand}{}
      {analyze}{}
      {evaluate}{}
      {apply}{}
      {create}{}
    }{
      \ifstexhtml\else\bool_if:NT\c_stex_metadata_bool {
        \marginpar{\tiny \textbf{Precondition:}~#1~
          \exp_args:Ne\symrefemph@uri{\stex_symbol_uri_name:N \l_stex_get_symbol_uri}{\l_stex_get_symbol_uri}
        }
      }\fi
      \stex_annotate_invisible:nn{
        data-ftml-preconditionsymbol={\stex_use_symbol_uri:N \l_stex_get_symbol_uri},
        data-ftml-preconditiondimension={#1}
      }{}
    }{\errmessage{Unknown~cognitive~dimension~#1}}
  }
}
\newcommand\objective[2]{
  \stex_get_symbol:n{#2}
  \tl_if_empty:NF \l_stex_get_symbol_uri {
    \str_case:nnTF {#1}{
      {remember}{}
      {understand}{}
      {analyze}{}
      {evaluate}{}
      {apply}{}
      {create}{}
    }{
      \ifstexhtml\else\bool_if:NT\c_stex_metadata_bool {
        \marginpar{\tiny \textbf{Objective:}~#1~
        \exp_args:Ne\symrefemph@uri{\stex_symbol_uri_name:N \l_stex_get_symbol_uri}{\l_stex_get_symbol_uri}
        }
      }\fi
      \stex_annotate_invisible:nn{
        data-ftml-objectivesymbol={\stex_use_symbol_uri:N \l_stex_get_symbol_uri},
        data-ftml-objectivedimension={#1}
      }{}
    }{\errmessage{Unknown~cognitive~dimension~#1}}
  }
}
%    \end{macrocode}
%
% \begin{macro}{\problem@kw@*}
%   For multilinguality, we define internal macros for keywords that can be specialized in
%   |*.ldf| files.
%    \begin{macrocode}
\AddToHook{begindocument}{
  \ExplSyntaxOn\makeatletter
  \input{problem-english.ldf}
  \ltx@ifpackageloaded{babel}{
			\clist_set:Nx \l_tmpa_clist {\exp_args:No \tl_to_str:n \bbl@loaded}
      \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{ngerman}}{
        \input{problem-ngerman.ldf}
      }
      \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{finnish}}{
        \input{problem-finnish.ldf}
      }
      \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{french}}{
        \input{problem-french.ldf}
      }
      \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{russian}}{
        \input{problem-russian.ldf}
      }
  }{}
  \makeatother\ExplSyntaxOff
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Problems and Solutions}\label{sec:impl:probsols}
% 
% We now prepare the KeyVal support for problems. The key macros just set appropriate
% internal macros.
%
%    \begin{macrocode}
\bool_new:N \l_stex_key_autogradable_bool
\stex_keys_define:nnnn{ problem }{
  \tl_clear:N \l_stex_key_pts_tl
  \tl_set:Nn \l_stex_key_min_tl 0
  \str_clear:N \l_stex_key_name_str
  \str_clear:N \l_stex_key_mhrepos_str
  \bool_set_false:N \l_stex_key_autogradable_bool
}{
  pts     .tl_set:N     = \l_stex_key_pts_tl,
  min     .tl_set:N     = \l_stex_key_min_tl,
  name    .str_set:N    = \l_stex_key_name_str,
  autogradable .bool_set:N = \l_stex_key_autogradable_bool,
  archive  .code:n = {},
  %archive .str_set:N    = \l_stex_key_mhrepos_str,
  %creators .code:n = {}
  %imports .tl_set:N     = \l_@@_prob_imports_tl,
  %refnum  .int_set:N    = \l_@@_prob_refnum_int,
}{id,title,style,uses}
%    \end{macrocode}
%
% Then we set up a counter for problems.
% \begin{macro}{\numberproblemsin}
%    \begin{macrocode}
\newcounter{sproblem}[section]
\newcommand\numberproblemsin[1]{
  \@addtoreset{sproblem}{#1}
  \def\thesproblem{\arabic{#1}.\arabic{sproblem}}
}
\numberproblemsin{section}
%\def\theplainsproblem{\arabic{sproblem}}
%\def\thesproblem{\thesection.\theplainsproblem}
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{sproblem}
%    \begin{macrocode}
\cs_new:Nn \_@@_activate_macros: {
  \stex_reactivate_macro:N \solution
  \stex_reactivate_macro:N \mcb
  \stex_reactivate_macro:N \scb
  \stex_reactivate_macro:N \fillinsol
  \stex_reactivate_macro:N \hint
  \stex_reactivate_macro:N \exnote
  \stex_reactivate_macro:N \gnote
}

\fp_new:N \g_problem_total_pts_fp
\fp_new:N \g_problem_total_min_fp

\bool_new:N \l_@@_in_problem_bool
\bool_new:N \l_@@_has_pts_bool
\bool_new:N \l_@@_has_min_bool
\bool_set_false:N \l_@@_in_problem_bool
\stex_new_stylable_env:nnnnnnn {problem} {O{}}{
  \bool_if:NT \l_@@_in_problem_bool {
    \msg_error:nn{stex}{error/nestedproblem}
  }
  \cs_if_exist:NTF \l_problem_inputproblem_keys_tl {
    \tl_put_left:Nn \l_problem_inputproblem_keys_tl {#1,}
    \exp_args:Nno \stex_keys_set:nn{problem}{
      \l_problem_inputproblem_keys_tl
    }
  }{
    \stex_keys_set:nn{problem}{#1}
  }
  \refstepcounter{sproblem}

  \stex_if_do_html:T {
    \str_if_empty:NT \l_stex_key_name_str {
      \stex_file_split_off_lang:NN \l_@@_path_seq \g_stex_current_file
      \seq_get_right:NN \l_@@_path_seq \l_stex_key_name_str
    }
    \exp_args:Nne \begin{stex_annotate_env} {
      data-ftml-problem={\l_stex_key_name_str},
      %data-ftml-language={ \l_stex_current_language_str},
      data-ftml-autogradable={\bool_if:NTF \l_stex_key_autogradable_bool {true}{false}}
      \tl_if_empty:NF \l_stex_key_pts_tl{,data-ftml-problempoints={\l_stex_key_pts_tl}}
    }
    \noindent \stex_annotate:nn{data-ftml-title={}}{\_stex_annotate_force_break:n{\l_stex_key_title_tl}}
    \tl_if_empty:NF \l_stex_key_title_tl {
      \exp_args:No \stexdoctitle \l_stex_key_title_tl
    }
    \_stex_annotate_force_break:n{}
  }
  \tl_set_eq:NN \thistitle \l_stex_key_title_tl
  \tl_if_empty:NT \l_stex_key_pts_tl { \tl_set:Nn \l_stex_key_pts_tl{0} }
  

  \bool_set_true:N \l_@@_in_problem_bool
  \tl_set_eq:NN \l_@@_pts_tl \l_stex_key_pts_tl
  \tl_set_eq:NN \l_@@_min_tl \l_stex_key_min_tl
  \tl_if_eq:NnTF \l_@@_pts_tl {0}
    {\bool_set_false:N \l_@@_has_pts_bool}
    {\bool_set_true:N \l_@@_has_pts_bool}
  \tl_if_eq:NnTF \l_@@_min_tl {0}
    {\bool_set_false:N \l_@@_has_min_bool}
    {\bool_set_true:N \l_@@_has_min_bool}
  \int_gzero:N \g_@@_subproblem_int

  \stex_if_do_html:F\stex_style_apply:
  \_stex_do_id:
  \_@@_activate_macros:
}{
  \fp_gadd:Nn \g_problem_total_pts_fp { \l_@@_pts_tl}
  \fp_gadd:Nn \g_problem_total_min_fp { \l_@@_min_tl}
  \_@@_record_problem:
  \stex_if_do_html:F\stex_style_apply:
  \stex_if_do_html:T{ \end{stex_annotate_env} }
}{
  \par\noindent\problemheader
  \stex_if_do_html:F{
    \bool_if:NT \c_@@_pts_bool {
      \tl_if_eq:NnF \l_@@_pts_tl {0}{
        \marginpar{\l_@@_pts_tl{}~\problem@kw@pts\smallskip}
      }
    }
    \bool_if:NT \c_@@_min_bool {
      \tl_if_eq:NnF \l_@@_min_tl {0} {
        \marginpar{\l_@@_min_tl{}~\problem@kw@minutes\smallskip}
      }
    }
  }
  \par
  \stex_ignore_spaces_and_pars:
}{
  \par\bigskip
%  \bool_if:NT \c_@@_test_bool \pagebreak
}{s}

\tl_set:Nn \problemheader {
  \stex_if_do_html:TF{
    \tl_if_empty:NF \thistitle {
      \stex_annotate:nn{data-ftml-title={}}{\textbf{\thistitle}}
    }
  }{
    \textbf{\sproblemautorefname{~}\thesproblem
      \tl_if_empty:NF \thistitle {
        {~}(\thistitle)
      }
    }
  }
}

\cs_new_protected:Nn \_@@_record_problem: {
  \exp_args:NNe \iow_now:Nn \@auxout {
    \problem@restore {\thesproblem}{\l_@@_pts_tl}{\l_@@_min_tl}
  }
}

\cs_new_protected:Npn \problem@restore #1 #2 #3 {} 
%    \end{macrocode}
% \end{environment}
%
% \begin{environment}{subproblem}
%    \begin{macrocode}
\int_new:N \g_@@_subproblem_int

\stex_new_stylable_env:nnnnnnn {subproblem} {O{}}{
  \stex_keys_set:nn{problem}{#1}
  \bool_if:NF \l_@@_in_problem_bool{
    \ifstexhtml\else
      \par{\bfseries WARNING~subproblem~to~be~used~in~some~problem}\par
    \fi
    \_@@_activate_macros:
    \bool_set_true:N \l_@@_in_problem_bool
    \tl_set:Nn \l_@@_pts_tl{0}
    \tl_set:Nn \l_@@_min_tl{0}
  }
  \str_if_empty:NT \l_stex_key_name_str {
    \stex_file_split_off_lang:NN \l_@@_path_seq \g_stex_current_file
    \seq_get_right:NN \l_@@_path_seq \l_stex_key_name_str
  }
  \stex_if_do_html:T {
    \str_if_empty:NT \l_stex_key_name_str {
      \stex_file_split_off_lang:NN \l_@@_path_seq \g_stex_current_file
      \seq_get_right:NN \l_@@_path_seq \l_stex_key_name_str
    }
    \exp_args:Nne \begin{stex_annotate_env} {
      data-ftml-subproblem={\l_stex_key_name_str},
      %data-ftml-language={ \l_stex_current_language_str},
      data-ftml-autogradable={\bool_if:NTF \l_stex_key_autogradable_bool {true}{false}}
      \tl_if_empty:NF \l_stex_key_pts_tl{,data-ftml-problempoints={\l_stex_key_pts_tl}}
    }
    \noindent \stex_annotate:nn{data-ftml-title={}}{\_stex_annotate_force_break:n{\l_stex_key_title_tl}}
    \tl_if_empty:NF \l_stex_key_title_tl {
      \exp_args:No \stexdoctitle \l_stex_key_title_tl
    }
    \tl_if_empty:NF \l_stex_key_title_tl {
      \exp_args:No \stexdoctitle \l_stex_key_title_tl
    }
    \_stex_annotate_force_break:n{}
  }
  \tl_if_empty:NT \l_stex_key_pts_tl { \tl_set:Nn \l_stex_key_pts_tl{0} }
  \int_gincr:N \g_@@_subproblem_int
  \bool_if:NF \l_@@_has_pts_bool {
    \tl_gset:Ne \l_@@_pts_tl {\fp_to_decimal:n {\l_@@_pts_tl + \l_stex_key_pts_tl}}
  }
  \bool_if:NF \l_@@_has_min_bool {
    \tl_gset:Ne \l_@@_min_tl {\fp_to_decimal:n {\l_@@_min_tl + \l_stex_key_min_tl}}
  }
  \stex_if_smsmode:F {\stex_if_do_html:F \stex_style_apply: }
}{
  \stex_if_do_html:TF{ \end{stex_annotate_env} }{\stex_if_smsmode:F\stex_style_apply:}
}{
  \begin{list}{}{
    \setlength\topsep{0pt}
    \setlength\parsep{0pt}
    \setlength\rightmargin{0pt}
  }\item[\int_use:N \g_@@_subproblem_int .]
  \bool_if:NT \c_@@_pts_bool {
    \bool_if:NF \l_@@_has_pts_bool {
      \marginpar{\smallskip\l_stex_key_pts_tl{}~\problem@kw@pts}
    }
  }
  \bool_if:NT \c_@@_min_bool {
    \bool_if:NF \l_@@_has_min_bool{
      \marginpar{\smallskip\l_stex_key_min_tl{}~\problem@kw@minutes}
    }
  }
  \ignorespaces
}{
  \end{list}
}{}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\includeproblem}
%    \begin{macrocode}
\stex_keys_define:nnnn{ includeproblem }{
  \str_clear:N \l_stex_key_mhrepos_str
}{
  archive .str_set:N    = \l_stex_key_mhrepos_str,
  unknown .code:n = {}
}{}

\NewDocumentCommand\includeproblem{O{} m}{
  \group_begin:
  \tl_set:Nn \l_problem_inputproblem_keys_tl {#1}
  \stex_keys_set:nn{includeproblem}{#1}
  \exp_args:Nno \use:nn{\inputref[}\l_stex_key_mhrepos_str]{#2}
  \group_end:
}

%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{solution}
%    \begin{macrocode}
\int_new:N \g_problem_id_counter
\dim_new:N \l_stex_key_testspace_dim
\stex_keys_define:nnnn{ solution }{
  \str_clear:N \l_stex_key_answerclass_str
  \dim_zero:N \l_stex_key_testspace_dim
}{
  testspace   .dim_set:N = \l_stex_key_testspace_dim,
  answerclass .str_set:N = \l_stex_key_answerclass_str
}{id,title,style}

\cs_new_protected:Nn \_@@_solution_start:n {
  \stex_keys_set:nn{ solution }{#1}
  \str_if_empty:NT \l_stex_key_id_str {
    \int_gincr:N \g_problem_id_counter
    \str_set:Nx \l_stex_key_id_str {
      SOLUTION_\int_use:N \g_problem_id_counter
    }
  }
  \stex_if_do_html:T{
    \begin{stex_annotate_env}{
      data-ftml-solution=\l_stex_key_id_str,
      data-ftml-answerclass={\l_stex_key_answerclass_str}
    }
  }
}

\stex_new_stylable_env:nnnnnnn { solution }{ O{} }{
  \stex_if_do_html:TF{
    \_@@_solution_start:n{#1}
  }{
    \ifsolutions
      \_@@_solution_start:n{#1}
      \stex_style_apply:
    \else
      \stex_keys_set:nn{ solution }{#1}
      \testspace{\l_stex_key_testspace_dim}
      \setbox\l_tmpa_box\vbox\bgroup
    \fi
  }
}{
  \stex_if_do_html:TF{
    \end{stex_annotate_env}
  }{
    \ifsolutions
      \stex_style_apply:
      \stex_if_do_html:T{
        \end{stex_annotate_env}
      }
    \else
      \egroup
    \fi
  }
}{
  \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip
  \noindent\emph{\problem@kw@solution\tl_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl \str_if_empty:NF \l_stex_key_answerclass_str {
      (Answer Class: \l_stex_key_answerclass_str)
    }
  } :~}
}{
  \par\rule[.3em]{\linewidth}{0.4pt}\newline
}{}

\stex_deactivate_macro:Nn \solution {sproblem~environments}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\startsolutions,\stopsolutions}
%    \begin{macrocode}
\cs_new_protected:Npn \startsolutions{
  \global\solutionstrue
}
\cs_new_protected:Npn \stopsolutions{
  \global\solutionsfalse
}
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{hint}
%    \begin{macrocode}

\stex_keys_define:nnnn{ problemenv }{}{}{id,title,style}

\cs_new_protected:Nn \_@@_hint_start:n {
  \stex_keys_set:nn{ problemenv }{#1}
  \str_if_empty:NT \l_stex_key_id_str {
    \int_gincr:N \g_problem_id_counter
    \str_set:Nx \l_stex_key_id_str {
      HINT_\int_use:N \g_problem_id_counter
    }
  }
  \stex_if_do_html:T{
    \begin{stex_annotate_env}{
      data-ftml-problemhint=\l_stex_key_id_str
    }
  }
}

\stex_new_stylable_env:nnnnnnn { hint }{ O{} }{
  \stex_if_do_html:TF{
    \_@@_hint_start:n{#1}
  }{
    \bool_if:NTF \c_@@_hints_bool {
      \_@@_hint_start:n{#1}
      \stex_style_apply:
    }{
      \setbox\l_tmpa_box\vbox\bgroup
    }
  }
}{
  \stex_if_do_html:TF{
    \end{stex_annotate_env}
  }{
    \bool_if:NTF \c_@@_hints_bool {
      \stex_style_apply:
      \stex_if_do_html:T{
        \end{stex_annotate_env}
      }
    }{
      \egroup
    }
  }
}{
  \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip
  \noindent\emph{\problem@kw@hint\tl_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl
  } :~}
}{
  \par\rule[.3em]{\linewidth}{0.4pt}\newline
}{}
\stex_deactivate_macro:Nn \hint {sproblem~environments}
%    \end{macrocode}
% \end{environment}
%
% \begin{environment}{exnote}
%    \begin{macrocode}
\cs_new_protected:Nn \_@@_exnote_start:n {
  \stex_keys_set:nn{ problemenv }{#1}
  \str_if_empty:NT \l_stex_key_id_str {
    \int_gincr:N \g_problem_id_counter
    \str_set:Nx \l_stex_key_id_str {
      EXNOTE_\int_use:N \g_problem_id_counter
    }
  }
  \stex_if_do_html:T{
    \begin{stex_annotate_env}{
      data-ftml-problemnote=\l_stex_key_id_str
    }
  }
}

\stex_new_stylable_env:nnnnnnn { exnote }{ O{} }{
  \stex_if_do_html:TF{
    \_@@_exnote_start:n{#1}
  }{
    \bool_if:NTF \c_@@_notes_bool {
      \_@@_exnote_start:n{#1}
      \stex_style_apply:
    }{
      \setbox\l_tmpa_box\vbox\bgroup
    }
  }
}{
  \stex_if_do_html:TF{
    \end{stex_annotate_env}
  }{
    \bool_if:NTF \c_@@_notes_bool {
      \stex_style_apply:
      \stex_if_do_html:T{
        \end{stex_annotate_env}
      }
    }{
      \egroup
    }
  }
}{
  \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip
  \noindent\emph{\problem@kw@note\tl_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl
  } :~}
}{
  \par\rule[.3em]{\linewidth}{0.4pt}\newline
}{}
\stex_deactivate_macro:Nn \exnote {sproblem~environments}
%    \end{macrocode}
% \end{environment}
%% \begin{environment}{gnote}
%    \begin{macrocode}
\int_new:N \l_@@_anscls_int

\cs_new_protected:Nn \_@@_gnote_start:n {
  \stex_keys_set:nn{ problemenv }{#1}
  \str_if_empty:NT \l_stex_key_id_str {
    \int_gincr:N \g_problem_id_counter
    \str_set:Nx \l_stex_key_id_str {
      GNOTE_\int_use:N \g_problem_id_counter
    }
  }

  \stex_if_do_html:TF{
    \begin{stex_annotate_env}{
      data-ftml-problemgnote=\l_stex_key_id_str
    }
  }
  \stex_style_apply:
}

\stex_new_stylable_env:nnnnnnn { gnote }{ O{} }{
  \stex_if_do_html:TF{
    \_@@_gnote_start:n{#1}
  }{
    \bool_if:NTF \c_@@_gnotes_bool {
      \_@@_gnote_start:n{#1}
    }{
      \setbox\l_tmpa_box\vbox\bgroup
    }
  }
  \stex_reactivate_macro:N \anscls
}{
  \stex_if_do_html:TF{
    \end{stex_annotate_env}
  }{
    \bool_if:NTF \c_@@_gnotes_bool {
      \stex_style_apply:
      \stex_if_do_html:T{
        \end{stex_annotate_env}
      }
    }{
      \egroup
    }
  }
}{
  \par\smallskip\rule[.3em]{\linewidth}{0.4pt}\newline\smallskip
  \noindent\emph{\problem@kw@grading\str_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl
  } :~}
}{
  \par\rule[.3em]{\linewidth}{0.4pt}\newline
}{}
\stex_deactivate_macro:Nn \gnote {sproblem~environments}


\stex_keys_define:nnnn{ anscls }{
  \str_clear:N \l_stex_key_pts_str
  \tl_clear:N \l_stex_key_feedback_tl
}{
  pts     .str_set:N = \l_stex_key_pts_str,
  feedback .tl_set:N = \l_stex_key_feedback_tl,
  update  .code:n    = {}
}{id}
\newcommand \anscls [2][] {
  \stex_keys_set:nn{ anscls }{#1}
  \str_if_empty:NT \l_stex_key_id_str {
    \int_incr:N \l_@@_anscls_int
    \str_set:Nx \l_stex_key_id_str {
      AC\int_use:N \l_@@_anscls_int
    }
  }
  \stex_if_do_html:TF{
    \begin{list}{}{
      \setlength\topsep{0pt}
      \setlength\parsep{0pt}
      \setlength\rightmargin{0pt}
    }\item[] \exp_args:Ne \stex_annotate:nn{
      data-ftml-answerclass={\l_stex_key_id_str}
      \str_if_empty:NF \l_stex_key_pts_str{
        ,data-ftml-answerclass-pts={\l_stex_key_pts_str}
      }
    }{
      #2~
      \tl_if_empty:NF \l_stex_key_feedback_tl{
        \stex_annotate:nn{
          data-ftml-answerclass-feedback={}
        }{\l_stex_key_feedback_tl}
      }
    }
    \end{list}
  }{
    \begin{list}{}{
      \setlength\topsep{0pt}
      \setlength\parsep{0pt}
      \setlength\rightmargin{0pt}
    }\item[\l_stex_key_id_str] #2
      \str_if_empty:NF \l_stex_key_pts_str {\par
        ~ \problem@kw@points :~\l_stex_key_pts_str
      }
      \tl_if_empty:NF \l_stex_key_feedback_tl {\par
        ~ \problem@kw@feedback :~\l_stex_key_feedback_tl
      }
    \end{list}
  }
}
\stex_deactivate_macro:Nn \anscls {gnote~environments}
%    \end{macrocode}
% \end{environment}
%
% The margin pars are reader-visible, so we need to translate
% 
%    \begin{macrocode}
\def\pts#1{
  \bool_if:NT \c_@@_pts_bool {
    \stex_annotate:nn{data-ftml-problempoints={#1}}{\marginpar{#1~\problem@kw@pts}}
  }\hbox_unpack:N\c_empty_box
}
\def\min#1{
  \bool_if:NT \c_@@_min_bool {
    \stex_annotate:nn{data-ftml-problemminutes={}}{\marginpar{#1~\problem@kw@minutes}}
  }\hbox_unpack:N\c_empty_box
}
%    \end{macrocode}
%
% \begin{environment}{mcb}
%
%    \begin{macrocode}
\stex_new_stylable_env:nnnnnnn{mcb}{O{}}{
  \stex_keys_set:nn{style}{#1}
  \cs_set:Nn \_@@_mccline:n{
    \begin{list}{}{
      \setlength\topsep{0pt}
      \setlength\parsep{0pt}
      \setlength\rightmargin{0pt}
    }\item[\problem_mcc_box_tl] ##1 \end{list}
  }

  \stex_if_do_html:T{
    \tl_set:Nn\problem_mcc_box_tl{}
    \_@@_maybe_inline:n{
      \exp_args:Nne \begin{stex_annotate_env}{
        data-ftml-multiple-choice-block={}
        \clist_if_empty:NF \l_stex_key_style_clist {,
          data-ftml-styles={\l_stex_key_style_clist}
        }
      }
    }
    \clist_if_in:NnTF \l_stex_key_style_clist {inline} {
      \cs_set:Nn \_@@_mccline:n {##1}
    }{
      \clist_if_in:NnT \l_stex_key_style_clist {dropdown} {
      \cs_set:Nn \_@@_mccline:n {##1}
    }
    }
  }
  \stex_deactivate_macro:Nn \mcb {sproblem~environments}
  \stex_deactivate_macro:Nn \scb {sproblem~environments}
  \stex_deactivate_macro:Nn \solution {sproblem~environments}
  \stex_deactivate_macro:Nn \hint {sproblem~environments}
  \stex_deactivate_macro:Nn \exnote {sproblem~environments}
  \stex_deactivate_macro:Nn \gnote {sproblem~environments}
  \stex_reactivate_macro:N \mcc
  \stex_if_do_html:F \stex_style_apply:
}{
  \stex_if_do_html:TF{
    \_@@_maybe_inline:n{\end{stex_annotate_env}}
  }\stex_style_apply:
}{\par}{}{}

\stexstylemcb[inline]{
  {\Large[}\cs_set:Nn \_@@_mccline:n{\problem_mcc_box_tl{~} #1}
}{{\Large]}}

\stexstylemcb[dropdown]{
  {\Large[}\cs_set:Nn \_@@_mccline:n{\problem_mcc_box_tl{~} #1}
}{{\Large]}}

\stex_deactivate_macro:Nn \mcb {sproblem~environments}
%    \end{macrocode}
%
% we define the keys for the |mcc| macro
%
%    \begin{macrocode} 
\cs_new_protected:Nn \_@@_do_yes_param:Nn {
  \exp_args:Nx \str_if_eq:nnTF { \str_lowercase:n{ #2 } }{ yes }{
    \bool_set_true:N #1
  }{
    \bool_set_false:N #1
  }
}
\stex_keys_define:nnnn{mcc}{
  \tl_clear:N \l_stex_key_feedback_tl
  \bool_set_false:N \l_stex_key_T_bool
  \tl_clear:N \l_stex_key_Ttext_tl
  \tl_clear:N \l_stex_key_Ftext_tl
}{
  feedback  .tl_set:N     = \l_stex_key_feedback_tl ,
  T         .code:n       = {\bool_set_true:N \l_stex_key_T_bool} ,
  F         .code:n       = {\bool_set_false:N \l_stex_key_T_bool} ,
  Ttext     .tl_set:N     = \l_stex_key_Ttext_tl ,
  Ftext     .tl_set:N     = \l_stex_key_Ftext_tl ,
}{id}

%    \end{macrocode}
%
% \begin{macro}{\mcc}
%    \begin{macrocode}

\cs_set:Nn \_@@_maybe_newline: { \\ }

\stex_if_html_backend:TF{
  \tl_set:Nn \problem_mcc_box_tl {
    \ltx@ifpackageloaded{amssymb}{$\square$}{
      \hbox{\vrule\vbox{\hrule width 6 pt\vskip 6pt\hrule}\vrule}
    }
  }

  \newcommand\mcc[2][]{
    \stex_keys_set:nn{mcc}{#1}
    \_@@_mccline:n{
      \stex_if_do_html:T{
        \stex_annotate:nn{data-ftml-problem-choice={
          \bool_if:NTF \l_stex_key_T_bool {true}{false}
        }}{
          #2~
          \stex_annotate:nn{data-ftml-problem-choice-verdict={}}{
            \bool_if:NTF \l_stex_key_T_bool {
              \tl_if_empty:NTF \l_stex_key_Ttext_tl \problem@kw@correct \l_stex_key_Ttext_tl
            }{
              \tl_if_empty:NTF \l_stex_key_Ftext_tl \problem@kw@wrong \l_stex_key_Ftext_tl
            }
          }
          \tl_if_empty:NF \l_stex_key_feedback_tl {
            \stex_annotate:nn{data-ftml-problem-choice-feedback={}}{
              \l_stex_key_feedback_tl
            }
          }
        }
      }
    }
  } 
}{
  \tl_set:Nn \problem_mcc_box_default_tl {
    \ltx@ifpackageloaded{amssymb}{$\square$}{
      \hbox{\vrule\vbox{\hrule width 6 pt\vskip 6pt\hrule}\vrule}
    }
  }
  \tl_set:Nn \problem_mcc_box_tl {
    \ifsolutions
      \bool_if:NTF \l_stex_key_T_bool {
        \makebox[0pt][l]{\problem_mcc_box_default_tl}
          \hspace{0.1em}$\cs_if_exist:NTF\checkmark{
            \raisebox{.15ex}{\checkmark}
          } X$
      }{\problem_mcc_box_default_tl}
    \else
      \problem_mcc_box_default_tl
    \fi
  }
  \newcommand\mcc[2][]{
    \stex_keys_set:nn{mcc}{#1}
    \ifsolutions
      \tl_set:Nx \l_tmpa_tl{
        \bool_if:NTF \l_stex_key_T_bool {
          \tl_if_empty:NF \l_stex_key_Ttext_tl {\exp_not:N \l_stex_key_Ttext_tl}
        }{
          \tl_if_empty:NF \l_stex_key_Ftext_tl {\exp_not:N \l_stex_key_Ftext_tl}
        }
        \tl_if_empty:NF \l_stex_key_feedback_tl {
          \exp_not:n{\\\emph{\l_stex_key_feedback_tl}}
        }
      }
    \fi

    \_@@_mccline:n{ #2
      \ifsolutions
        \tl_if_empty:NF \l_tmpa_tl { \footnote{\l_tmpa_tl} }
      \fi 
    }
  } 
}
\stex_deactivate_macro:Nn \mcc {mcb~environments}
%    \end{macrocode}
% \end{macro}
% \end{environment}
%
% \begin{environment}{scb}
%
%    \begin{macrocode}

\cs_new_protected:Nn \_@@_maybe_inline:n {
  \clist_if_in:NnTF \l_stex_key_style_clist {inline} {
    \let\_@@_oldpar:\stex_par:
    \cs_set:Nn\stex_par:{~}
    \cs_set:Nn\_@@_maybe_newline:{}
    #1
    \let\stex_par:\_@@_oldpar:
  }{
    \clist_if_in:NnTF \l_stex_key_style_clist {dropdown} {
      \let\_@@_oldpar:\stex_par:
      \cs_set:Nn\stex_par:{~}
      \cs_set:Nn\_@@_maybe_newline:{}
      #1
      \let\stex_par:\_@@_oldpar:
    }{\par #1}
  }
}

\stex_new_stylable_env:nnnnnnn{scb}{O{}}{
  \stex_keys_set:nn{style}{#1}
  \cs_set:Nn \_@@_sccline:n{
    \begin{list}{}{
      \setlength\topsep{0pt}
      \setlength\parsep{0pt}
      \setlength\rightmargin{0pt}
    }\item[\problem_scc_box_tl] ##1 \end{list}
  }

  \stex_if_do_html:T{
    \_@@_maybe_inline:n{
      \exp_args:Ne\stex_annotate_env{
        data-ftml-single-choice-block={}
        \clist_if_empty:NF \l_stex_key_style_clist {,
          data-ftml-styles={\l_stex_key_style_clist}
        }
      }
    }
    \tl_set:Nn\problem_scc_box_tl{}
    \clist_if_in:NnTF \l_stex_key_style_clist {inline} {
      \cs_set:Nn \_@@_sccline:n {##1}
    }{
      \clist_if_in:NnT \l_stex_key_style_clist {dropdown} {
        \cs_set:Nn \_@@_sccline:n {##1}
      }
    }
  }
  \stex_deactivate_macro:Nn \mcb {sproblem~environments}
  \stex_deactivate_macro:Nn \scb {sproblem~environments}
  \stex_deactivate_macro:Nn \solution {sproblem~environments}
  \stex_deactivate_macro:Nn \hint {sproblem~environments}
  \stex_deactivate_macro:Nn \exnote {sproblem~environments}
  \stex_deactivate_macro:Nn \gnote {sproblem~environments}
  \stex_reactivate_macro:N \scc
  \stex_if_do_html:F \stex_style_apply:
}{
  \stex_if_do_html:TF{
    \_@@_maybe_inline:n { \endstex_annotate_env }
  }\stex_style_apply:
}{\par}{}{}

\stexstylescb[inline]{
  {\Large[}\cs_set:Nn \_@@_sccline:n{\problem_scc_box_tl{~} #1}
}{{\Large]}}

\stexstylescb[dropdown]{
  {\Large[}\cs_set:Nn \_@@_sccline:n{\problem_scc_box_tl{~} #1}
}{{\Large]}}

\stex_deactivate_macro:Nn \scb {sproblem~environments}
%    \end{macrocode}
%
% \begin{macro}{\scc}
%    \begin{macrocode}

\stex_if_html_backend:TF{
  \tl_set:Nn\problem_scc_box_tl{$\bigcirc$}
  \newcommand\scc[2][]{
    \stex_keys_set:nn{mcc}{#1}
    \_@@_sccline:n{
      \stex_if_do_html:T{
        \stex_annotate:nn{data-ftml-problem-choice={
          \bool_if:NTF \l_stex_key_T_bool {true}{false}
        }}{
          #2~
          \stex_annotate:nn{data-ftml-problem-choice-verdict={}}{
            \bool_if:NTF \l_stex_key_T_bool {
              \tl_if_empty:NTF \l_stex_key_Ttext_tl \problem@kw@correct \l_stex_key_Ttext_tl
            }{
              \tl_if_empty:NTF \l_stex_key_Ftext_tl \problem@kw@wrong \l_stex_key_Ftext_tl
            }
          }
          \tl_if_empty:NF \l_stex_key_feedback_tl {
            \stex_annotate:nn{data-ftml-problem-choice-feedback={}}{
              \l_stex_key_feedback_tl
            }
          }
        }
      }
    }
  }
}{
  \tl_set:Nn\problem_scc_box_default_tl{$\bigcirc$}
  \tl_set:Nn\problem_scc_box_tl{
    \ifsolutions
      \bool_if:NTF \l_stex_key_T_bool {
        \makebox[0pt][l]{\problem_scc_box_default_tl}
          \hspace{0.1em}$\cs_if_exist:NTF\checkmark{
            \raisebox{.15ex}{\checkmark}
          } X$
      }{\problem_scc_box_default_tl}
    \else
      \problem_scc_box_default_tl
    \fi
  }
  \newcommand\scc[2][]{
    \stex_keys_set:nn{mcc}{#1}
    \ifsolutions
      \tl_set:Nx \l_tmpa_tl{
        \bool_if:NTF \l_stex_key_T_bool {
          \tl_if_empty:NF \l_stex_key_Ttext_tl {\exp_not:N \l_stex_key_Ttext_tl}
        }{
          \tl_if_empty:NF \l_stex_key_Ftext_tl {\exp_not:N \l_stex_key_Ftext_tl}
        }
        \tl_if_empty:NF \l_stex_key_feedback_tl {
          \exp_not:n{ \\\emph{\l_stex_key_feedback_tl} }
        }
      }
    \fi
  
    \_@@_sccline:n{ #2
      \ifsolutions
        \tl_if_empty:NF \l_tmpa_tl { \footnote{\l_tmpa_tl} }
      \fi
    }
  }
}
 
\stex_deactivate_macro:Nn \scc {scb~environments}


\newcommand\yesTnoF{
  \begin{scb}[style=inline]
    \scc[T]{yes}~\scc[F]{no}
  \end{scb}
}
\newcommand\yesFnoT{
  \begin{scb}[style=inline]
    \scc[F]{yes}~\scc[T]{no}
  \end{scb}
}
\newcommand\trueTfalseF{
  \begin{scb}[style=inline]
    \scc[T]{true}~\scc[F]{false}
  \end{scb}
}
\newcommand\trueFfalseT{
  \begin{scb}[style=inline]
    \scc[F]{true}~\scc[T]{false}
  \end{scb}
}
%    \end{macrocode}
% \end{macro}
% \end{environment}
%
% \begin{macro}{\fillinsol}
%    \begin{macrocode}
\stex_keys_define:nnnn{fillinsol}{
  \tl_clear:N \l_@@_fillin_solution_tl
  \dim_zero:N \l_stex_key_testspace_dim
}{
  testspace   .dim_set:N = \l_stex_key_testspace_dim,
  exact    .code:n = {\_@@_parse_fillin_arg:nnnn{exact}#1 },
  numrange .code:n = {\_@@_parse_fillin_arg:nnnn{numrange}#1 },
  regex    .code:n = {\_@@_parse_fillin_arg:nnnn{regex}#1 }
}{}

\tl_const:Nn \c_@@_true_tl{T}
\tl_const:Nn \c_@@_false_tl{F}

\msg_set:nnn{problem}{error/neither-true-nor-false}{
  Fillinsol~verdict~#1~is~neither~T~nor~F!
}

\stex_if_html_backend:TF{
  \cs_new:Nn \_@@_parse_fillin_arg:nnnn {
    \tl_set:Nn \l_tmpa_tl{#3}
    \tl_if_eq:NNF \l_tmpa_tl\c_@@_true_tl{
      \tl_if_eq:NNF \l_tmpa_tl\c_@@_false_tl {
        \msg_error:nnn{problem}{error/neither-true-nor-false}{#3}
      }
    }
    \tl_put_right:Ne \l_@@_fillin_solution_tl {
      \stex_annotate:nn{
        data-ftml-fillin-case={#1},
        data-ftml-fillin-case-value={\tl_to_str:n{#2}},
        data-ftml-fillin-case-verdict={
          \tl_if_eq:NNTF\l_tmpa_tl\c_@@_true_tl{true}{false}
        },
      }{\_stex_annotate_force_break:n{\exp_not:n{#4}}}
    }
  }
}{
  \cs_new:Nn \_@@_parse_fillin_arg:nnnn {
    \tl_put_right:Nn \l_@@_fillin_solution_tl {
      #1 & \tl_to_str:n{#2} & #3 & #4 \crcr
    }
  }
}


\newcommand\fillinsol[2][]{
  \stex_if_do_html:F \quad
  \mode_if_math:TF{
    \hbox{\_@@_fillinsol:nn{#1}{#2}}
  }{
    \_@@_fillinsol:nn{#1}{#2}
  }
  \stex_if_do_html:F \quad
}

\stex_if_html_backend:TF{
  \cs_new_protected:Nn \_@@_fillinsol:nn {
    \stex_keys_set:nn{fillinsol}{#1}
    \tl_if_empty:nF{#2}{
      \_@@_parse_fillin_arg:nnnn{exact}{#2}{T}{}
    }
    \hbox_set:Nn \l_tmpa_box{\fbox{\huge{\texttt{\tl_to_str:n{#2}}}\hskip\l_stex_key_testspace_dim}}
    \exp_args:Ne \stex_annotate:nn{
      data-ftml-fillinsol={},
      data-ftml-fillinsol-width={\dim_to_decimal:n{1.5 \box_wd:N \l_tmpa_box }}
    }{ 
      \_stex_annotate_force_break:n{
        \l_@@_fillin_solution_tl
        #2
      } 
    }
  }
}{
  \cs_new_protected:Nn \_@@_fillinsol:nn {
    \stex_keys_set:nn{fillinsol}{#1}  
    \ifsolutions

      \cs_if_exist:NT\textcolor{\textcolor{red}}{\fbox{\texttt{\tl_to_str:n{#2}}}}
      \tl_if_empty:NF \l_@@_fillin_solution_tl {
        \footnote{
          \halign{ ~##~\hfil & ~##~\hfil & ~##~\hfil & ~##~\hfil \cr
            \textbf{type}&\textbf{case}&\textbf{verdict}&\textbf{feedback}\cr
            \tl_if_empty:nF{#2}{
              exact & #2 & T & \cr
            }
            \l_@@_fillin_solution_tl
          }
        }
      }
    \else
      \fbox{\dim_compare:nNnTF\l_stex_key_testspace_dim={0pt}{
        \phantom{\huge{\tl_to_str:n{#2}}}
      }{
        \hspace{\l_stex_key_testspace_dim}\vphantom{\huge{A \tl_to_str:n{#2}}}
      }}
    \fi
  }
}

\stex_deactivate_macro:Nn \fillinsol {sproblem~environments}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\testemptypage}
%    \begin{macrocode}
\newcommand\testemptypage[1][]{%
	\bool_if:NT \c_@@_test_bool {\ \vfill\begin{center}\hwexam@kw@testemptypage\end{center}\eject}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\testspace}
%    \begin{macrocode}
\newcommand\testspace[1]{\bool_if:NT \c_@@_test_bool {\vspace*{#1}}}
\newcommand\testsmallspace{\testspace{1cm}}
\newcommand\testmedspace{\testspace{2cm}}
\newcommand\testbigspace{\testspace{3cm}}
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\testnewpage}
%    \begin{macrocode}
\newcommand\testnewpage{\bool_if:NT \c_@@_test_bool {\newpage}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\testnewpage}
%    \begin{macrocode}
\newcommand{\testnewpageInProblem}%
{\ifintest\vfill\begin{center}\emph{continued on next page}\end{center}\testnewpage\fi}%
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
% 
% \end{implementation}
% ^^A \ifinfulldoc\else\printbibliography\fi
\endinput
%%% Local Variables: 
%%% mode: doctex
%%% TeX-master: t
%%% End: 
% \fi
% LocalWords:  GPL structuresharing STR dtx pts keyval xcomment CPERL DefKeyVal iffalse 
% LocalWords:  RequirePackage Semiverbatim DefEnvironment OptionalKeyVals soln texttt baz
% LocalWords:  exnote DefConstructor inclprob NeedsTeXFormat omd.sty textbackslash exfig
%  LocalWords:  stopsolution fileversion filedate maketitle setcounter tocdepth newpage
%  LocalWords:  tableofcontents showmeta showmeta solutionstrue usepackage minipage hrule
%  LocalWords:  linewidth elefants.prob Elefants smallskip noindent textbf startsolutions
%  LocalWords:  startsolutions stopsolutions stopsolutions includeproblem includeproblem
%  LocalWords:  textsf HorIacJuc cscpnrr11 includemhproblem includemhproblem importmodule
%  LocalWords:  importmhmodule foobar ldots latexml mhcurrentrepos mh-variants mh-variant
%  LocalWords:  compactenum langle rangle langle rangle ltxml metakeys newif ifexnotes rm
%  LocalWords:  exnotesfalse exnotestrue ifhints hintsfalse hintstrue ifsolutions ifpts
%  LocalWords:  solutionsfalse ptsfalse ptstrue ifmin minfalse mintrue ifboxed boxedfalse
%  LocalWords:  boxedtrue sref mdframed marginpar prob srefaddidkey addmetakey refnum kv
%  LocalWords:  newcounter ifx thesection theproblem hfill newenvironment metasetkeys ltx
%  LocalWords:  stepcounter currentsectionlevel xspace ignorespaces surroundwithmdframed
%  LocalWords:  omdoc autoopen autoclose solvedinminutes kvi qw vals newcommand exhint
%  LocalWords:  specialcomment excludecomment mhrepos xref marginpar addtocounter doctex
%  LocalWords:  mh@currentrepos endinput

