% \iffalse meta-comment
% An Infrastructure for marking up Assignments
% 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\libfolder#1{../../lib/#1}
\input{../../doc/stex-docheader}

\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \GetFileInfo{hwexam.sty}
% 
% \MakeShortVerb{\|}
% \def\scsys#1{{{\sc #1}}\index{#1@{\sc #1}}}
% \def\latexml{\scsys{LaTeXML}}
%
% \title{\texttt{hwexam.sty/cls}: An Infrastructure for formatting Assignments 
%        and Exams\thanks{Version {\fileversion} (last revised {\filedate})}}
%    \author{Michael Kohlhase\\
%    FAU Erlangen-N\"urnberg\\
%    \url{http://kwarc.info/kohlhase}}
% \maketitle
%
% \begin{documentation}
%\ifinfulldoc\else 
% 
%\begin{abstract}{}
%  The |hwexam| package and class allows individual course assignment sheets and compound
%  assignment documents using problem files marked up with the |problem| package.
% 
%  This is the documentation for the \pkg{hwexam} package.  For a more high-level
%  introduction, see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the
%  \href{\basedocurl/stex.pdf}{full \sTeX documentation}.
% \end{abstract}
%
% \tableofcontents
% \begin{sfragment}{The User Intterface}
% \input{../../doc/packages/stex-hwexam}
% \end{sfragment}
% \fi
%
% \end{documentation}
%
%\begin{implementation}
% 
% \section{Implementation: The hwexam Package} 
%
% \subsection{Package Options}
%
% The first step is to declare (a few) package options that handle whether certain
% information is printed or not. Some come with their own conditionals that are set by the
% options, the rest is just passed on to the |problems| package.
%
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage{hwexam}{2022/09/14}{3.2.0}{homework assignments and exams}
\RequirePackage{l3keys2e}

\newif\iftest\testfalse
\DeclareOption{test}{\testtrue\PassOptionsToPackage{\CurrentOption}{problem}}
\newif\ifmultiple\multiplefalse
\DeclareOption{multiple}{\multipletrue}
\DeclareOption{lang}{\PassOptionsToPackage{\CurrentOption}{problem}}
\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{problem}}
\ProcessOptions
%    \end{macrocode}
% Then we make sure that the necessary packages are loaded (in the right versions).
%    \begin{macrocode}
\RequirePackage{keyval}[1997/11/10]
\RequirePackage{problem}
%    \end{macrocode}
%
% \begin{macro}{\hwexam@*@kw}
%   For multilinguality, we define internal macros for keywords that can be specialized in
%   |*.ldf| files. 
%    \begin{macrocode}
\newcommand\hwexam@assignment@kw{Assignment}
\newcommand\hwexam@given@kw{Given}
\newcommand\hwexam@due@kw{Due}
\newcommand\hwexam@testemptypage@kw{This~page~was~intentionally~left~blank~for~extra~space}
\newcommand\hwexam@minutes@kw{minutes}
\newcommand\correction@probs@kw{prob.}
\newcommand\correction@pts@kw{total}
\newcommand\correction@reached@kw{reached}
\newcommand\correction@sum@kw{Sum}
\newcommand\correction@grade@kw{grade}
\newcommand\correction@forgrading@kw{To~be~used~for~grading,~do~not~write~here}
%    \end{macrocode}
% \end{macro}
% 
% For the other languages, we set up triggers
%    \begin{macrocode}
\AddToHook{begindocument}{
	\ltx@ifpackageloaded{babel}{
		\makeatletter
		\clist_set:Nx \l_tmpa_clist {\bbl@loaded}
		\exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{ngerman}}{
		  \input{hwexam-ngerman.ldf}
		}
		\exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{finnish}}{
		  \input{hwexam-finnish.ldf}
		}
		\exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{french}}{
		  \input{hwexam-french.ldf}
		}
		\exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{russian}}{
		  \input{hwexam-russian.ldf}
		}
		\makeatother
	}{}
}

%    \end{macrocode}
% \subsection{Assignments}
%
% Then we set up a counter for problems and make the problem counter inherited from
% |problem.sty| depend on it. Furthermore, we specialize the |\prob@label| macro to take
% the assignment counter into account.
%    \begin{macrocode}
\newcounter{assignment}
%\numberproblemsin{assignment}
%    \end{macrocode}
%
% We will prepare the keyval support for the |assignment| environment.
%
%    \begin{macrocode}
\keys_define:nn { hwexam / assignment } {
	id 				.str_set_x:N =	\l_@@_assign_id_str,
	number 			.int_set:N 	= \l_@@_assign_number_int,
	title 			.tl_set:N 	= \l_@@_assign_title_tl,
	type 			.tl_set:N 	= \l_@@_assign_type_tl,
	given			.tl_set:N 	= \l_@@_assign_given_tl,
	due				.tl_set:N 	= \l_@@_assign_due_tl,
	loadmodules		.code:n 	= {
		\bool_set_true:N \l_@@_assign_loadmodules_bool
	}
}
\cs_new_protected:Nn \_@@_assignment_args:n {
	\str_clear:N \l_@@_assign_id_str
	\int_set:Nn \l_@@_assign_number_int {-1}
	\tl_clear:N \l_@@_assign_title_tl
	\tl_clear:N \l_@@_assign_type_tl
	\tl_clear:N \l_@@_assign_given_tl
	\tl_clear:N \l_@@_assign_due_tl
	\bool_set_false:N \l_@@_assign_loadmodules_bool
	\keys_set:nn { hwexam / assignment }{ #1 }
}
%    \end{macrocode}
%
% The next three macros are intermediate functions that handle the case gracefully, where
% the respective token registers are undefined.
% 
% The |\given@due| macro prints information about the given and due status of the
% assignment. Its arguments specify the brackets. 
% 
%    \begin{macrocode}
\newcommand\given@due[2]{
	\bool_lazy_all:nF {
		{\tl_if_empty_p:V \l_@@_inclassign_given_tl}
		{\tl_if_empty_p:V \l_@@_assign_given_tl}
		{\tl_if_empty_p:V \l_@@_inclassign_due_tl}
		{\tl_if_empty_p:V \l_@@_assign_due_tl}
	}{ #1 }

	\tl_if_empty:NTF \l_@@_inclassign_given_tl {
		\tl_if_empty:NF \l_@@_assign_given_tl {
			\hwexam@given@kw\xspace\l_@@_assign_given_tl
		}
	}{
		\hwexam@given@kw\xspace\l_@@_inclassign_given_tl
	}

	\bool_lazy_or:nnF {
		\bool_lazy_and_p:nn {
			\tl_if_empty_p:V \l_@@_inclassign_due_tl
		}{
			\tl_if_empty_p:V \l_@@_assign_due_tl
		}
	}{
		\bool_lazy_and_p:nn {
			\tl_if_empty_p:V \l_@@_inclassign_due_tl
		}{
			\tl_if_empty_p:V \l_@@_assign_due_tl
		}
	}{ ,~ }

	\tl_if_empty:NTF \l_@@_inclassign_due_tl {
		\tl_if_empty:NF \l_@@_assign_due_tl {
			\hwexam@due@kw\xspace \l_@@_assign_due_tl
		}
	}{
		\hwexam@due@kw\xspace \l_@@_inclassign_due_tl
	}
	
	\bool_lazy_all:nF {
		{ \tl_if_empty_p:V \l_@@_inclassign_given_tl }
		{ \tl_if_empty_p:V \l_@@_assign_given_tl }
		{ \tl_if_empty_p:V \l_@@_inclassign_due_tl }
		{ \tl_if_empty_p:V \l_@@_assign_due_tl }
	}{ #2 }
}
%    \end{macrocode}
% 
% \begin{macro}{\assignment@title}
%   This macro prints the title of an assignment, the local title is overwritten, if there
%   is one from the |\inputassignment|. |\assignment@title| takes three arguments the
%   first is the fallback when no title is given at all, the second and third go around
%   the title, if one is given. 
%    \begin{macrocode}
\newcommand\assignment@title[3]{
	\tl_if_empty:NTF \l_@@_inclassign_title_tl {
		\tl_if_empty:NTF \l_@@_assign_title_tl {
			#1
		}{
			#2\l_@@_assign_title_tl#3
		}
	}{
		#2\l_@@_inclassign_title_tl#3
	}
}
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\assignment@number}
%   Like |\assignment@title| only for the number, and no around part.
%    \begin{macrocode}
\newcommand\assignment@number{
	\int_compare:nNnTF \l_@@_inclassign_number_int = {-1} {
		\int_compare:nNnTF \l_@@_assign_number_int = {-1} {
			\arabic{assignment}
		} {
			\int_use:N \l_@@_assign_number_int
		}
	}{
		\int_use:N \l_@@_inclassign_number_int
	}
}
%    \end{macrocode}
% \end{macro}
% 
% With them, we can define the central |assignment| environment. This has two forms
% (separated by |\ifmultiple|) in one we make a title block for an assignment sheet, and
% in the other we make a section heading and add it to the table of contents. We first
% define an assignment counter
% 
% \begin{environment}{assignment}
%   For the |assignment| environment we delegate the work to the |@assignment| environment
%   that depends on whether |multiple| option is given. 
%    \begin{macrocode}
\newenvironment{assignment}[1][]{
	\_@@_assignment_args:n { #1 }	
	%\sref@target
	\int_compare:nNnTF \l_@@_assign_number_int = {-1} {
		\global\stepcounter{assignment}
	}{
		\global\setcounter{assignment}{\int_use:N\l_@@_assign_number_int}
	}
	\setcounter{sproblem}{0}
	\renewcommand\prob@label[1]{\assignment@number.##1}
	\def\current@section@level{\document@hwexamtype}
	%\sref@label@id{\document@hwexamtype \thesection}
	\begin{@assignment}
}{
	\end{@assignment}
}
%    \end{macrocode}
% In the multi-assignment case we just use the |omdoc| environment for suitable
% sectioning. 
%    \begin{macrocode}
\def\ass@title{
	{\protect\document@hwexamtype}~\arabic{assignment}
	\assignment@title{}{\;(}{)\;} -- \given@due{}{}
}
\ifmultiple 
	\newenvironment{@assignment}{
		\bool_if:NTF \l_@@_assign_loadmodules_bool {
			\begin{sfragment}[loadmodules]{\ass@title}
		}{
			\begin{sfragment}{\ass@title}
		}
	}{
		\end{sfragment}
	}
%    \end{macrocode}
% for the single-page case we make a title block from the same components. 
%    \begin{macrocode}
\else
	\newenvironment{@assignment}{
		\begin{center}\bf
			\Large\@title\strut\\
			\document@hwexamtype~\arabic{assignment}\assignment@title{\;}{:\;}{\\}
			\large\given@due{--\;}{\;--}
		\end{center}
	}{}
\fi% multiple
%    \end{macrocode}
% \end{environment}
% 
% \subsection{Including Assignments}
%
% \begin{macro}{\in*assignment}
%   This macro is essentially a glorified |\include| statement, it just sets some internal
%   macros first that overwrite the local points Importantly, it resets the |inclassig|
%   keys after the input.
%    \begin{macrocode}
\keys_define:nn { hwexam / inclassignment } {
	%id 				.str_set_x:N =	\l_@@_assign_id_str,
	number 			.int_set:N 	= \l_@@_inclassign_number_int,
	title 			.tl_set:N 	= \l_@@_inclassign_title_tl,
	type 			.tl_set:N 	= \l_@@_inclassign_type_tl,
	given			.tl_set:N 	= \l_@@_inclassign_given_tl,
	due				.tl_set:N 	= \l_@@_inclassign_due_tl,
	mhrepos 		.str_set_x:N = \l_@@_inclassign_mhrepos_str
}
\cs_new_protected:Nn \_@@_inclassignment_args:n {
	\int_set:Nn \l_@@_inclassign_number_int {-1}
	\tl_clear:N \l_@@_inclassign_title_tl
	\tl_clear:N \l_@@_inclassign_type_tl
	\tl_clear:N \l_@@_inclassign_given_tl
	\tl_clear:N \l_@@_inclassign_due_tl
	\str_clear:N \l_@@_inclassign_mhrepos_str
	\keys_set:nn { hwexam / inclassignment }{ #1 }
}
\_@@_inclassignment_args:n {}

\newcommand\inputassignment[2][]{
	\_@@_inclassignment_args:n { #1 }
	\str_if_empty:NTF \l_@@_inclassign_mhrepos_str {
		\input{#2}
	}{
		\stex_in_repository:nn{\l_@@_inclassign_mhrepos_str}{
			\input{\mhpath{\l_@@_inclassign_mhrepos_str}{#2}}
		}
	}
	\_@@_inclassignment_args:n {}
}
\newcommand\includeassignment[2][]{
	\newpage
	\inputassignment[#1]{#2}
}
%    \end{macrocode}
% \end{macro}
% 
% \subsection{Typesetting Exams}
%
% \begin{macro}{\quizheading}
%    \begin{macrocode}
\ExplSyntaxOff
\newcommand\quizheading[1]{%
	\def\@tas{#1}%
	\large\noindent NAME: \hspace{8cm}  MAILBOX:\\[2ex]%
	\ifx\@tas\@empty\else%
		\noindent TA:~\@for\@I:=\@tas\do{{\Large$\Box$}\@I\hspace*{1em}}\\[2ex]%
	\fi%
}
\ExplSyntaxOn
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\testheading}
%    \begin{macrocode}

\def\hwexamheader{\input{hwexam-default.header}}

\def\hwexamminutes{
	\tl_if_empty:NTF \testheading@duration {
		{\testheading@min}~\hwexam@minutes@kw
	}{
		\testheading@duration
	}
}

\keys_define:nn { hwexam / testheading } {
	min 		.tl_set:N 	= \testheading@min,
	duration	.tl_set:N 	= \testheading@duration,
	reqpts		.tl_set:N 	= \testheading@reqpts,
	tools		.tl_set:N 	= \testheading@tools 
}
\cs_new_protected:Nn \_@@_testheading_args:n {
	\tl_clear:N \testheading@min
	\tl_clear:N \testheading@duration
	\tl_clear:N \testheading@reqpts
	\tl_clear:N \testheading@tools
	\keys_set:nn { hwexam / testheading }{ #1 }
}
\newenvironment{testheading}[1][]{
	\_@@_testheading_args:n{ #1 }
	\newcount\check@time\check@time=\testheading@min
	\advance\check@time by -\theassignment@totalmin
	\newif\if@bonuspoints
	\tl_if_empty:NTF \testheading@reqpts {
		\@bonuspointsfalse
	}{
		\newcount\bonus@pts
		\bonus@pts=\theassignment@totalpts
		\advance\bonus@pts by -\testheading@reqpts
		\edef\bonus@pts{\the\bonus@pts}
		\@bonuspointstrue
	}
	\edef\check@time{\the\check@time}

	\makeatletter\hwexamheader\makeatother
}{
	\newpage
}
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@problem}
%   This macro acts on a problem's record in the |*.aux| file. Here we redefine it (it was
%   defined to do nothing in |problem.sty|) to  generate the correction table. 
%    \begin{macrocode}
%<@@=problems>
\renewcommand\@problem[3]{
	\stepcounter{assignment@probs}
	\def\@@pts{#2}
	\ifx\@@pts\@empty\else
		\addtocounter{assignment@totalpts}{#2}
	\fi
	\def\@@min{#3}\ifx\@@min\@empty\else\addtocounter{assignment@totalmin}{#3}\fi
	\xdef\correction@probs{\correction@probs & #1}%
	\xdef\correction@pts{\correction@pts & #2}
	\xdef\correction@reached{\correction@reached &}
}
%<@@=hwexam>
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\correction@table}
%   This macro generates the correction table
%    \begin{macrocode}
\newcounter{assignment@probs}
\newcounter{assignment@totalpts}
\newcounter{assignment@totalmin}
\def\correction@probs{\correction@probs@kw}
\def\correction@pts{\correction@pts@kw}
\def\correction@reached{\correction@reached@kw}
\stepcounter{assignment@probs}
\newcommand\correction@table{
	\resizebox{\textwidth}{!}{%
\begin{tabular}{|l|*{\theassignment@probs}{c|}|l|}\hline%
&\multicolumn{\theassignment@probs}{c||}%|
{\footnotesize\correction@forgrading@kw} &\\\hline
\correction@probs & \correction@sum@kw & \correction@grade@kw\\\hline
\correction@pts &\theassignment@totalpts & \\\hline
\correction@reached & & \\[.7cm]\hline
\end{tabular}}}
%</package>
%    \end{macrocode}
% \end{macro}
% 
% \subsection{Leftovers}
%
% at some point, we may want to reactivate the logos font, then we use
% \begin{verbatim}
% here we define the logos that characterize the assignment
% \font\bierfont=../assignments/bierglas
% \font\denkerfont=../assignments/denker
% \font\uhrfont=../assignments/uhr
% \font\warnschildfont=../assignments/achtung
%
% \newcommand\bierglas{{\bierfont\char65}}
% \newcommand\denker{{\denkerfont\char65}}
% \newcommand\uhr{{\uhrfont\char65}}
% \newcommand\warnschild{{\warnschildfont\char 65}}
% \newcommand\hardA{\warnschild}
% \newcommand\longA{\uhr}
% \newcommand\thinkA{\denker}
% \newcommand\discussA{\bierglas}
% \end{verbatim}
% \end{implementation}
% \ifinfulldoc\else\printbibliography\fi
\endinput
% \iffalse

%%% Local Variables: 
%%% mode: doctex
%%% TeX-master: t
%%% End: 
% \fi
%  LocalWords:  texttt scsys sc latexml fileversion filedate maketitle setcounter newpage
%  LocalWords:  tocdepth tableofcontents pts showmeta showmeta showignores omdoc extrefs
%  LocalWords:  testspace testnewpage testemptypage testheading testheading reqpts reqpts
%  LocalWords:  exfig makeatletter makeatother vspace hrule vspace vspace noindent textsf
%  LocalWords:  includeassignment includeassignment HorIacJuc cscpnrr11 importmodule baz
%  LocalWords:  includemhassignment includemhassignment importmhmodule foobar ldots sref
%  LocalWords:  mhcurrentrepos mh-variants mh-variant compactenum printbibliography Cwd
%  LocalWords:  langle rangle langle rangle ltxml.cls ltxml.sty respetively metakeys qw
%  LocalWords:  cwd stex graphicx amssymb amstext amsmath newif iftest testfalse testtrue
%  LocalWords:  ifsolutions solutionsfalse ifmultiple multiplefalse multipletrue keyval
%  LocalWords:  ltxml assig srefaddidkey addmetakey ifx assignment@titleblock stepcounter
%  LocalWords:  document@hwexamtype importmodules metasetkeys inclassig@title inclassig
%  LocalWords:  inclassig@title inclassig@type inclassig@type inclassig@number xspace kv
%  LocalWords:  inclassig@number inclassig@due inclassig@due inclassig@given ignorespaces
%  LocalWords:  inclassig@given newenvironment currentsectionlevel OptionalKeyVals kvi
%  LocalWords:  omgroup vals hwexamtype ednote textbackslash newcommand inputassignment
%  LocalWords:  unlist quizheading tas hspace hfill textbf newcount vfill addtocounter
%  LocalWords:  theassignment@totalmin theassignment@totalpts assignment@probs xdef hline
%  LocalWords:  assignment@totalpts assignment@totalmin correction@probs correction@probs
%  LocalWords:  newcounter theassignment@probs footnotesize mh@currentrepos endinput
%  LocalWords:  inclassig@mhrepos inclassig@mhrepos doctex inputmhassignment
%  LocalWords:  GPL structuresharing STR iffalse cls NeedsTeXFormat hwexam hwexam.dtx sc 
