% \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}{2023/03/19}{3.3.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
}
\RequirePackage{stex}
%    \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 {\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}
\stex_keys_define:nnnn{ problem }{
  \tl_set:Nn \l_stex_key_pts_tl 0
  \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
}{
  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,
  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}
\newcounter{pts}
\newcounter{min}
\stex_new_stylable_env:nnnnnnn {problem} {O{}}{
  \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}
  \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:No \stex_module_setup:n \l_stex_key_name_str

  \stex_if_do_html:T {
    \exp_args:Nne \begin{stex_annotate_env} {
      shtml:problem={\l_stex_current_module_str},
      shtml:language={ \l_stex_current_language_str},
      shtml:signature={\l_stex_key_sig_str}
      \tl_if_empty:NF \l_stex_metatheory_uri {,
        shtml:metatheory={\stex_uri_use:N \l_stex_metatheory_uri}
      }
    }
    \stex_annotate_invisible:n{}
    \tl_if_empty:NF \l_stex_key_title_tl {
      \exp_args:No \stexdoctitle \l_stex_key_title_tl
    }
  }
  \stex_if_smsmode:F {
    \str_set_eq:NN \thismoduleuri \l_stex_current_module_str
    \tl_set_eq:NN \thismodulename \l_stex_key_name_str
    \tl_set_eq:NN \thistitle \l_stex_key_title_tl
    \stex_style_apply:
    \addtocounter{pts}{\l_stex_key_pts_tl}
    \addtocounter{min}{\l_stex_key_min_tl}
    \_stex_do_id:
    \_@@_record_problem:
  }
  \stex_reactivate_macro:N \solution
  \stex_reactivate_macro:N \mcb
  \stex_reactivate_macro:N \fillinsol
  \stex_smsmode_do:
}{
  \stex_close_module:
  \stex_if_smsmode:F \stex_style_apply:
  \stex_if_do_html:T{ \end{stex_annotate_env} }
}{
  \par\noindent\problemheader
  \bool_if:NT \c_@@_pts_bool {
    \marginpar{\l_stex_key_pts_tl{}~\problem@kw@points\smallskip}
  }
  \bool_if:NT \c_@@_min_bool {
    \marginpar{\l_stex_key_min_tl{}~\problem@kw@minutes\smallskip}
  }
  \\
  \stex_ignore_spaces_and_pars:
}{
  \par\bigskip
%  \bool_if:NT \c_@@_test_bool \pagebreak
}{s}
\stex_sms_allow_env:n{sproblem}

\tl_set:Nn \problemheader {
  \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_stex_key_pts_tl}{\l_stex_key_min_tl}
  }
}

\cs_new_protected:Npn \problem@restore #1 #2 #3 {} 
%    \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

\cs_new_protected:Nn \_@@_solution_start:n {
  \str_set:Nn \l_stex_key_title_tl {#1}
  \str_set:Nn \l_stex_key_id_str {#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}{
      shtml:solution=\l_stex_key_id_str
    }
  }
  \stex_style_apply:
}

\stex_new_stylable_env:nnnnnnn { solution }{ O{} }{
  \stex_if_do_html:TF{
    \_@@_solution_start:n{#1}
  }{
    \ifsolutions
      \_@@_solution_start:n{#1}
    \else
      \setbox\l_tmpa_box\vbox\bgroup
    \fi
  }
}{
  \stex_if_do_html:TF{
    \stex_style_apply:
    \end{stex_annotate_env}
  }{
    \ifsolutions
      \stex_style_apply:
      \stex_if_do_html:T{
        \end{stex_annotate_env}
      }
    \else
      \egroup
    \fi
  }
}{
  \par\smallskip\hrule\smallskip
  \noindent\emph{Solution\str_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl
  } :~}
}{
  \par\smallskip\hrule
}{}

\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}
\cs_new_protected:Nn \_@@_hint_start:n {
  \str_set:Nn \l_stex_key_title_tl {#1}
  \str_set:Nn \l_stex_key_id_str {#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}{
      shtml:problemhint=\l_stex_key_id_str
    }
  }
  \stex_style_apply:
}

\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}
    }{
      \setbox\l_tmpa_box\vbox\bgroup
    }
  }
}{
  \stex_if_do_html:TF{
    \stex_style_apply:
    \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\hrule\smallskip
  \noindent\emph{Hint\str_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl
  } :~}
}{
  \par\smallskip\hrule
}{}
%    \end{macrocode}
% \end{environment}
%
% \begin{environment}{exnote}
%    \begin{macrocode}
\cs_new_protected:Nn \_@@_exnote_start:n {
  \str_set:Nn \l_stex_key_title_tl {#1}
  \str_set:Nn \l_stex_key_id_str {#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}{
      shtml:problemnote=\l_stex_key_id_str
    }
  }
  \stex_style_apply:
}

\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}
    }{
      \setbox\l_tmpa_box\vbox\bgroup
    }
  }
}{
  \stex_if_do_html:TF{
    \stex_style_apply:
    \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\hrule\smallskip
  \noindent\emph{Note\str_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl
  } :~}
}{
  \par\smallskip\hrule
}{}
%    \end{macrocode}
% \end{environment}
%% \begin{environment}{gnote}
%    \begin{macrocode}
\cs_new_protected:Nn \_@@_gnote_start:n {
  \str_set:Nn \l_stex_key_title_tl {#1}
  \str_set:Nn \l_stex_key_id_str {#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:T{
    \begin{stex_annotate_env}{
      shtml: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_if_do_html:TF{
    \stex_style_apply:
    \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\hrule\smallskip
  \noindent\emph{Grading\str_if_empty:NF \l_stex_key_title_tl{
    {~}\l_stex_key_title_tl
  } :~}
}{
  \par\smallskip\hrule
}{}
%    \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 {
    \marginpar{#1~\problem@kw@points}
  }
}
\def\min#1{
  \bool_if:NT \c_@@_min_bool {
    \marginpar{#1~\problem@kw@minutes}
  }
}
%    \end{macrocode}
%
% \begin{environment}{mcb}
%
%    \begin{macrocode}
\newenvironment{mcb}{\par
  \stex_if_do_html:T{
    \begin{stex_annotate_env}{shtml:multiple-choice-block={}}
  }
  \stex_deactivate_macro:Nn \mcb {sproblem~environments}
  \stex_deactivate_macro:Nn \solution {sproblem~environments}
  \stex_reactivate_macro:N \mcc
  \begin{enumerate}
}{
  \end{enumerate}
  \stex_if_do_html:T{
    \end{stex_annotate_env}
  }
}
\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         .default:n    = { false } ,
  T         .bool_set:N   = \l_stex_key_T_bool ,
  F         .default:n    = { false } ,
  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}
\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}\par
  \tl_set:Nn \l_tmpb_tl {~--~
    \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 {
      \\\emph{\l_stex_key_feedback_tl}
    }
  }
  \tl_set:Nn \l_tmpa_tl {
     #2
    \stex_if_do_html:TF{ 
      \stex_annotate:nn{shtml:mcc-solution={}}{\l_tmpb_tl} 
    }{
      \ifsolutions\l_tmpb_tl\fi
    }
  }
  \item[\problem_mcc_box_tl]{}~
  \stex_if_do_html:TF{
    \stex_annotate:nn{shtml:mcc={
      \bool_if:NTF \l_stex_key_T_bool {true}{false}
    }}{\l_tmpa_tl}
  }{\l_tmpa_tl}
} 
\stex_deactivate_macro:Nn \mcc {mcb~environments}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\fillinsol}
%    \begin{macrocode}
\newcommand\fillinsol[2][]{
  \quad
  \stex_if_do_html:TF{
    \stex_annotate:nn{shtml:fillinsol={}}{ \_stex_annotate_force_break:n{#2} }
  }{
    \ifsolutions
      \textcolor{red}{\fbox{#2}}
    \else
      \fbox{
        \tl_if_empty:nTF{#1}{
          \phantom{\huge{#2}}
        }{
          \hspace{#1}
        }
      }
    \fi
  }
  \quad
}
\stex_deactivate_macro:Nn \fillinsol {sproblem~environments}
%    \end{macrocode}
% \end{macro}
%
% \end{environment}
%
%
%    \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

