% -----------------------------------------------------------------------
%   webquiz.cls | webquiz latex class file
% -----------------------------------------------------------------------
%
%   Copyright (C) Andrew Mathas, University of Sydney
%
%   Distributed under the terms of the GNU General Public License (GPL)
%               http://www.gnu.org/licenses/
%
%   This file is part of the WebQuiz system.
%
%   <Andrew.Mathas@sydney.edu.au>
% ----------------------------------------------------------------------

\NeedsTeXFormat{LaTeX2e}[1996/12/01]

% load webquiz-ini style
\input{webquiz-ini.code}

% ----------------------------------------------------------------------
\ProvidesClass{webquiz}[\webquiz{release date} Version \webquiz{version}]

% initialise and then process document class options usng pgfopts
\RequirePackage{etoolbox}
\RequirePackage{pgfopts}
\def\unknown@options{}%          unknown options are passed to article.cls
\def\WQ@HideSideMenu{DeFaUlT}%   side menu visible by default
\newif\ifWQ@Tikz\WQ@Tikzfalse%   true if tikz a document class option

\newif\ifWQ@Debugging  % for the debugging class option
% Process the documentclass options using pgfkeys and \ProcessPgfOptions
\pgfkeys{/WQ@ClassOptions/.is family,
  /WQ@ClassOptions,
    % turn debugging on
    debugging/.code           = {\WQ@Debuggingtrue},
    % pst2pdf
    pst2pdf/.style            = {pst2pdf value=true},
    pst2pdf value/.initial    = false,
    % languaage
    language/.initial         = DeFaUlT,
    % one page
    onepage/.style            = {onepage value=true},
    separatepages/.style      = {onepage value=false},
    onepage value/.initial    = DeFaUlT,
    % side menu
    showsidemenu/.style       = {hidesidemenu value=false},
    hidesidemenu/.style       = {hidesidemenu value=true},
    hidesidemenu value/.initial= DeFaUlT,
    % random order of quiz questions
    randomorder/.style        = {randomorder value=true},
    fixedorder/.style         = {randomorder value=false},
    randomorder value/.initial = DeFaUlT,
    % theme
    theme/.initial             = DeFaUlT,
    % tikz
    tikz/.code                 = {\global\WQ@Tikztrue},
    % unknown options => passed to article class
    .unknown/.code={\edef\unknown@options{\unknown@options,\pgfkeyscurrentname}}
}
\newcommand\WQ@ClassOption[1]{\pgfkeysvalueof{/WQ@ClassOptions/#1}}

% Use pgfkeys to check for valid options for the choice environment and the
% answer comparisons. As \ERROR is not defined an error message is
% generated by the unknown handlers below
\pgfkeys{/webquiz checker/.is family, /webquiz checker,
  mode/.initial          = single,
  columns value/.initial = 1,
  columns/.style         = {columns value=#1},
  single/.style          = {mode=single},
  multiple/.style        = {mode=multiple},
  .unknown/.code         = {\ERROR: invalid choice type: use single or multiple}
  comparison/.is choice,
  comparison/complex/.code      = \relax,
  comparison/integer/.code      = \relax,
  comparison/lowercase/.code    = \relax,
  comparison/number/.code       = \relax,
  comparison/string/.code       = \relax,
  comparison/.unknown/.code     = {\ERROR: invalid input type: use integer, string or eval}
}

% now process the options
\ProcessPgfOptions{/WQ@ClassOptions}% process options
\LoadClass[\unknown@options]{article}% load article class with options

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{xparse}
\RequirePackage{pgffor}

% load Michal Hoftich's new tikz driver for tex4ht
\ifWQ@Tikz
   \ifdefined\HCode
      \def\pgfsysdriver{pgfsys-dvisvgm4ht.def}
   \fi
\fi

\def\WQ@Error{\PackageError{webquiz}}
\def\WQ@Debugging#1{\ifWQ@Debugging\typeout{Debugging: #1}\fi}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{amsfonts,amsmath}
\RequirePackage{bbding}
\setlength{\parindent}{0pt}
\setlength{\parskip}{10pt}

% Macro to define a picture variant of \<command>. The latex version does
% nothing but the cfg version converts \<command> into an image

\newcommand\DisplayAsImage[2][]{\relax}

% Need to declare possible graphics extensions: see https://tex.stackexchange.com/questions/213461
% This is just placeholder - the real definition is used in the cfg file
%\newcommand\DeclareGraphicsExtensions[1]{}

% Macros for defining the university and department
\newcommand*{\DepartmentURL}[1]{\def\WQ@departmentURL{#1}}
\newcommand*{\Department}[1]{\def\WQ@department{#1}}

% University/instution - university included for backwards compatibility
\newcommand*{\InstitutionURL}[1]{\def\WQ@institutionURL{#1}}
\newcommand*{\Institution}[1]{\def\WQ@institution{#1}}
\newcommand*{\UniversityURL}[1]{\def\WQ@institutionURL{#1}}
\newcommand*{\University}[1]{\def\WQ@institution{#1}}

% Macros for defining the quiz web breadcrumbs using the unit code, name and
% URL. The names of these macros are chosen so as to be compatible with the
% in-house SMS package sms-uos.sty that specifies these for all units.
\newcommand*\UnitCode[1]{\def\uos@code{#1}}
\newcommand*\UnitName[1]{\def\uos@name{#1}}
\newcommand*\UnitURL[1]{\def\uos@url{#1}}
\newcommand*\QuizzesURL[1]{\def\WQ@quizzesUrl{#1}}
\newcommand*\BreadCrumb[1]{\def\WQ@breadcrumb{#1}}
\newcommand*\BreadCrumbs[1]{\def\WQ@breadcrumbs{#1}}

% Default values - the university and department defaults can also be
% set in the webquizrc file. The main purpose of these defaults is
% to remind the user to set them.
\UnitCode{Unit code?}
\UnitName{Unit name?}
\UnitURL{}
\QuizzesURL{DeFaUlT}
\BreadCrumb{}
\BreadCrumbs{DeFaUlT}
\Department{DeFaUlT}
\DepartmentURL{DeFaUlT}
\University{DeFaUlT}
\UniversityURL{DeFaUlT}

% Define page header and footer for the printable version of the quiz
% to show the unit code information.
\def\ps@quiz{\ps@empty
  \def\@oddhead{\hbox to\textwidth{%
      \uos@code\hss\textsc{\@title}\hss Page \thepage}}%
  \let\@evenhead=\@oddhead
}
\def\ps@firstpage{\ps@empty}
\pagestyle{quiz}


\def\@title{}
\def\maketitle{\vspace*{10mm}
  \begin{center}
    {\large\textsc{\@title}}%
  \end{center}
}
\AtBeginDocument{
  \maketitle%
  \def\title{\WQ@Error{\noexpand\title can only be used in the preamble}\@ehc}
  \thispagestyle{firstpage}%
  \ifdefined\HCode\else
     \textsc{WebQuiz} will process this quiz using \textbf{pst2pdf}.
  \fi
  \RequirePackage{tikz}
}

% -----------------------------------------------------------------------
% WebQuiz macros
% Define \WQ@XXXStart and \WQ@XXXEnd macros to avoid code duplication
% in webquiz.cfg. The following switches are used for syntax checking
% -----------------------------------------------------------------------

% These are all for error checking...
\newif\ifWQ@InFeedback
\newif\ifWQ@InAnswer
\newif\ifWQ@InChoice
\newif\ifWQ@InDiscussion
\newif\ifWQ@InItem
\newif\ifWQ@InQuestion
\newif\ifWQ@InQuizIndex
\newif\ifWQ@InWhenright
\newif\ifWQ@InWhenwrong

% -----------------------------------------------------------------------
% the quizindex environment and \quiz macro
% -----------------------------------------------------------------------

% the quiz counter keeps track of the question numbers in a quizindex environement
\newcounter{quiz}
\renewcommand\thequiz{\arabic{quiz}}
\def\WQ@QuizStart{%
  \WQ@Debugging{Starting \noexpand\quiz...}%
  \ifWQ@InQuizIndex\else\WQ@Error{\noexpand\quiz must appear inside a quizindex environment}\fi%
  \refstepcounter{quiz}% increment the quiz counter for the URLs
}
\NewDocumentCommand\quiz{som}{%
  \WQ@QuizStart%
  \IfBooleanTF{#1}{\def\WQ@Quiz{}}{\def\WQ@Quiz{Quiz~\thequiz.\space}}%
  \IfNoValueTF{#2}{\def\WQ@url{quiz\thequiz.html}}{\def\WQ@url{#2}}%
  \leavevmode\medskip\newline%
  \WQ@Quiz #3\newline%
  \phantom{Quiz 10}\textit{URL}:\quad \WQ@url%
}

\def\WQ@QuizIndexStart{%
  \WQ@Debugging{Starting quizindex...}%
  \ifWQ@InQuestion\WQ@Error{quizindex cannot appear in a question environment}\fi%
  \ifWQ@InDiscussion\WQ@Error{quizindex environments cannot be inside a discussion environment}\fi
  \ifWQ@InQuizIndex\WQ@Error{quizindex environments cannot be nested}\fi%
  \global\WQ@InQuizIndextrue% here, and below, using \global is probably overkill...
}
\def\WQ@QuizIndexEnd{\global\WQ@InQuizIndexfalse\WQ@Debugging{Ending quizindex...}}
\newenvironment{quizindex}{\WQ@QuizIndexStart\bigskip}{\WQ@QuizIndexEnd}

% -----------------------------------------------------------------------
% discussion environment
% -----------------------------------------------------------------------

\newcounter{discussion}

% \begin{dicussion}[short title][title -default-> Discussion]
\def\WQ@DiscussionStart{%
  \WQ@Debugging{Starting discussion...}%
  \ifWQ@InDiscussion\WQ@Error{discussion environments cannot be nested}\fi%
  \ifWQ@InQuestion\WQ@Error{discussion environments cannot be inside a question environment}\fi%
  \ifWQ@InQuizIndex\WQ@Error{discussion environments cannot be inside a quizindex environment}\fi%
  \global\WQ@InDiscussiontrue%
  \refstepcounter{discussion}%
}
\def\WQ@DiscussionEnd{\global\WQ@InDiscussionfalse\WQ@Debugging{Ending discussion...}}
\NewDocumentEnvironment{discussion}{O{Discussion}O{#1}}
    {\WQ@DiscussionStart\textbf{#1} (#2)}{\WQ@DiscussionEnd\par\bigskip}

% ---------------------------------------------------------------------------
% Cross referencing question and discussion environments
% ---------------------------------------------------------------------------

% \WQ@Ref{+ or -}[optional *][optional text]{mandatory label}
\NewDocumentCommand\WQ@ref{ m s o m }{%
\fbox{\IfBooleanTF{#2}{link}{button} to \IfNoValueTF{#3}{to #1 \ref{#4}}{ to ``#3'' (#1 \ref{#4})}}%
}
\newcommand\dref{\WQ@ref{discussion}}
\newcommand\qref{\WQ@ref{question}}
\newcommand\Qref{\WQ@ref{question number}}

% -----------------------------------------------------------------------
% question environment
% -----------------------------------------------------------------------

% the question counter keeps track of the quiz question numbers
\newcounter{question}

\def\WQ@QuestionStart{%
  \WQ@Debugging{Starting question...}%
  \ifWQ@InDiscussion\WQ@Error{question environments cannot be inside a discussion environment}\fi%
  \ifWQ@InQuizIndex\WQ@Error{question environments cannot be inside a quizindex environment}\fi%
  \ifWQ@InQuestion\WQ@Error{question environments cannot be nested!}\fi%
  \global\WQ@InAnswerfalse%
  \global\WQ@InChoicefalse%
  \global\WQ@InChoicefalse%
  \global\WQ@InItemfalse%
  \global\WQ@InQuestiontrue%
  \global\WQ@InFeedbackfalse%
  \global\WQ@InWhenrightfalse%
  \global\WQ@InWhenwrongfalse%
  \refstepcounter{question}%
}

\def\WQ@QuestionEnd{
  \ifWQ@InChoice\else\ifWQ@InAnswer\else%
    \WQ@Error{Each question must contain a choice environment or an \noexpand\answer!}%
  \fi\fi%
  \global\WQ@InQuestionfalse%
  \WQ@Debugging{Ending question...}%
}

\newenvironment{question}{\WQ@QuestionStart\bigskip\textbf{Question \arabic{question}.\newline}}
                         {\par\bigskip\WQ@QuestionEnd}

% -----------------------------------------------------------------------
% choice environment, \correct and \incorrect choices and \feedback
% -----------------------------------------------------------------------

% the choice counter keeps track of the choices in a choice environment
\newcounter{choice}
\renewcommand\thechoice{(\alph{choice})}

\def\WQ@ChoiceStart#1{%
  \WQ@Debugging{Starting choice...}%
  \ifWQ@InQuestion\relax% Give a warning if we are not inside a question
  \else\WQ@Error{Choice environments must be contained in a question}%
  \fi%
  \ifWQ@InAnswer\WQ@Error{choice environments cannot contain an \noexpand\answer!}\fi%
  \ifWQ@InChoice\WQ@Error{choice environments cannot be nested}\fi%
  \global\WQ@InChoicetrue%
  \global\WQ@InItemfalse%
  \pgfkeys{/webquiz checker, #1}%
  \setcounter{choice}{0}% reset choice counter
}

\def\WQ@ChoiceEnd{%
  \ifWQ@InItem\else\WQ@Error{Choice environment with no choices!}\fi%
  \WQ@InChoicefalse%
  \WQ@Debugging{Ending choice...}%
}

% \begin{choice}[choice type, number of columns] ... \end{choice} The
% allowed choice types are "single" or "multiple". The type and number
% of columns is allowed to appear in either order, so most of the fun
% and games below is sanity checking of the argunments.
\NewDocumentEnvironment{choice}{O{single}}{%
  \WQ@ChoiceStart{#1}%
  \leavevmode\newline%
% (\textit{The choices will be printed in \pgfkeys{/webquiz checker/columns value} columns in the HTML version of the quiz})%
  \par%
  \setcounter{choice}{0}%
}{\WQ@ChoiceEnd}

\def\WQ@ItemStart{%
  \WQ@Debugging{Starting item...}%
  \ifWQ@InChoice\relax%
  \else\WQ@Error{\noexpand\correct and \noexpand\incorrect must be inside a choice environment}%
  \fi%
  \global\WQ@InItemtrue\global%
  \WQ@InFeedbackfalse%
  \refstepcounter{choice}%
}

\def\WQ@Item#1{\WQ@ItemStart\par\bigskip #1\quad\textit{Option} \thequestion\thechoice:\qquad}
\def\correct{\WQ@Item\CheckmarkBold}
\def\incorrect{\WQ@Item\XSolidBrush}

\def\WQ@FeedbackStart{%
  \WQ@Debugging{Starting feedback...}%
  \ifWQ@InItem\relax%
  \else\WQ@Error{Missing \noexpand\correct or \noexpand\incorrect}%
  \fi%
  \ifWQ@InFeedback\WQ@Error{Only one feedback per option is allowed!}\fi%
  \WQ@InFeedbacktrue%
}

\def\feedback{\WQ@FeedbackStart\leavevmode\medskip\newline\textit{Feedback:}\space}

% -----------------------------------------------------------------------
% The \answer macro and the feedback macros \whenRight, \whenWrong
% -----------------------------------------------------------------------

% supported answer comparisons
\def\WQ@AnswerStart#1{%
  \WQ@Debugging{Starting answer...}%
  \ifWQ@InQuestion\relax%
  \else\WQ@Error{\noexpand\answer\ must be contained in a question}%
  \fi%
  \ifWQ@InChoice\WQ@Error{You cannot have \noexpand\answer inside a choice environment}\fi%
  \ifWQ@InAnswer\WQ@Error{Each question can contain only one \noexpand\answer command}\fi%
  \pgfkeys{/webquiz checker/comparison/#1}%
  \global\WQ@InAnswertrue%
  \global\WQ@InWhenrightfalse%
  \global\WQ@InWhenwrongfalse%
}

\NewDocumentCommand\answer{s O{string} m}{%
  \WQ@AnswerStart{#2}%
  \leavevmode\bigskip\newline%
  \IfBooleanTF{#1}{\fbox{\textit{(#2 comparison):}\quad#3}}%
                  {\fbox{\textit{Answer (#2 comparison):}\quad#3}}%
}

\def\WQ@WhenStart#1{%
  \WQ@Debugging{Starting when#1...}%
  \ifWQ@InAnswer\relax\else\WQ@Error{missing \noexpand\answer}\fi%
  \ifbool{WQ@InWhen#1}{%
    \WQ@Error{Only one \noexpand\when#1 per question is allowed!}%
  }{}%
  \global\booltrue{WQ@InWhen#1}%
}

\def\WQ@When#1{\WQ@WhenStart{#1}\leavevmode\medskip\newline\textit{Feedback when #1:}\space}
\def\whenRight{\WQ@When{right}}
\def\whenWrong{\WQ@When{wrong}}

\endinput
%% End of file `webquiz.cls'.
