%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% vim:tw=0 nowrap:
%
% icpc_problem.sty
%
% Author: Greg Hamerly (hamerly@cs.baylor.edu)
%
% Date: 2008/10/15
%
% Description: This is a LaTeX package for making ICPC-style problems. There is
% a very regular format to these problems, which this package assumes.
% Therefore, it's not that flexible, but it makes the simple task of writing a
% problem much easier.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Basic usage:
%        \documentclass{article}
% 
%        \usepackage{../../latex/icpc_problem} % or wherever this package is stored
% 
%        \title{title of the problem here}
%        \author{your name here}
%        \keywords{list of lower-case keywords separated by spaces}
%        \comments{Any comments can go in here, so long as they can be fed as
%        an argument to a LaTeX command.
%        }
%        \difficulty{2} % the difficulty should be a non-negative integer
% 
%        \begin{document}
% 
%        \begin{problemDescription}
%        The basic problem description goes here.
%        \end{problemDescription}
% 
%        \begin{inputDescription}
%        A description of the input format goes here.
%        \end{inputDescription}
% 
%        \begin{outputDescription}
%        A description of the output format goes here.
%        \end{outputDescription}
% 
%        \begin{sampleInput}
%        The sample input can be anything (except \end{SaveVerbatim}, which
%        would cause a LaTeX parsing error). Treat this like the standard
%        verbatim environment.
%        \end{sampleInput}
%        \begin{sampleOutput}
%        The sample output environment is similar to sample input; treat it
%        like a verbatim environment.
%        \end{sampleOutput}
% 
%        \end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
% Note that the sampleInput and sampleOutput environments should not have a
% paragraph break between them; they should float to the right positions to
% minimize space. It's okay to have a break between them if you want to force
% them to be in separate paragraphs, but otherwise keeping them in the same
% paragraph should do the "right" thing.
%
% There are several options available for this package:
%   - displaymeta: Put into the layout a table describing the meta tags.
%
%   - showspaces: Display spaces in the Verbatim environments (note: this only
%     works with FancyVerbatim environments, not regular verbatim).
%
%   - warnonly: Normally, this package will validate the presence of all meta
%     tags, and produce an error (which prevents compilation) if validation
%     fails. If this option is present, the errors will be reduced to warnings.
%
% Tips:
%   - If you use \begin{Verbatim} instead of \begin{verbatim} in a problem
%     description, your description will inherit the property of the showspaces
%     option.
%   - The sampleInput and sampleOutput environments are kinda touchy. They're
%     certainly complicated enough.
%   - Without changing the LaTeX source, you can enable options for a package
%     from the command line like this:
%       $ latex '\PassOptionsToPackage{displaymeta}{icpc_problem}\input{statement.tex}'
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{icpc_problem}[2008/10/15 hamerly@cs.baylor.edu]

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ifthen is required to set up the package options, so require it here
\RequirePackage{ifthen}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% PACKAGE OPTIONS -- can be passed when \usepackage is called, or by
% \PassOptionsToPackage prior to \usepackage
%

% this option will make the document display the meta tags in a table
\newboolean{displayMetaTags}
\setboolean{displayMetaTags}{false}
\DeclareOption{displaymeta}{
    \PackageInfo{icpc_problem}{Displaying meta tags in the document}
    \setboolean{displayMetaTags}{true}
}

% this option turns on spaces in the FancyVerbatim environments (e.g. sample
% input/output)
\newboolean{showSampleSpaces}
\setboolean{showSampleSpaces}{false}
\DeclareOption{showspaces}{
    \PackageInfo{icpc_problem}{Showing spaces in sample input/output}
    \setboolean{showSampleSpaces}{true}
}

% this option turns errors from this package into warnings only
\newboolean{warnOnly}
\setboolean{warnOnly}{false}
\DeclareOption{warnonly}{
    \PackageInfo{icpc_problem}{Turning off package errors; using package warnings only}
    \setboolean{warnOnly}{true}
}

% process the options...
\ProcessOptions\relax
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% OTHER COMMONLY NEEDED PACKAGES
\RequirePackage{epsf}
\RequirePackage{plain}
\RequirePackage{fullpage}
\RequirePackage{graphicx}
\RequirePackage{fancyvrb}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% when the document begins, check the meta tags
\AtBeginDocument{\doMetaTagCheck}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% formatting
\setlength{\parindent}{0in} % don't indent paragraphs
\setlength{\parskip}{0.1in} % skip a bit between paragraphs
\pagestyle{empty}           % don't number pages
% FIXME -- is there a way to avoid numbering if there is only one page, and otherwise use page numbers?
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \header is used generally to highlight the beginning of each part of the
% document. We avoid using \section because we have more control over the
% spacing.
\newcommand{\header}[1]{\medskip{\Large\bf#1}\par}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% META TAG STUFF
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These are the values of the meta-tags used to document the problems.
\newcommand{\@comments}{}
\newcommand{\@difficulty}{}
\newcommand{\@keywords}{}
% \@author is standard LaTeX stuff, so it's already defined. However, its
% default definition seems strange -- I can't use it (or test its value)
% without getting errors about \@gobble. Therefore, we redefine it to be empty.
\renewcommand{\@author}{}

% These commands, with \author, are used to set up the meta tag values. They
% should all be called before \begin{document}
\newcommand{\comments}[1]{\renewcommand{\@comments}{#1}}
\newcommand{\difficulty}[1]{\renewcommand{\@difficulty}{#1}}
\newcommand{\keywords}[1]{\renewcommand{\@keywords}{#1}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Change \maketitle so that it shows only the title, not the author/date.
\renewcommand{\maketitle}{\begin{center}\header{\@title}\end{center}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Register an error or a warning for the package, depending on the value of the
% warnOnly boolean.

\newcommand{\PackageProblem}[2]{
    \ifthenelse{\boolean{warnOnly}}{
        \PackageWarning{icpc_problem}{#1}
    }{
        \PackageError{icpc_problem}{#1}{#2}
    }
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These commands check to see if author, comments, difficulty, and keywords have
% been defined, and display errors if they are not defined. They can be turned
% off by using \def\dontCheckMetaTags{true} within the document.

\newcommand{\checkMetaTag}[1]{
    % enclose the check in a new local environment so that the \metaTagMacro is
    % not globalized and can be defined each time this command is called
    {
        % Assume that \@#1 is the value to check. Construct a macro that has
        % that same value, for ease of multiple tests:
        \newcommand{\metaTagMacro}{\csname @#1\endcsname}

        \ifthenelse{\isundefined{\metaTagMacro}}
        {
            % this shouldn't happen, since we initialized the meta tags above
            \PackageProblem{META TAG UNDEFINED: #1}{Please define `#1' before begin{document}}
        }
        {
            \ifthenelse{\equal{\metaTagMacro}{}}{
                \PackageProblem{META TAG EMPTY: #1}{Please define `#1' before begin{document}}
            }
            {
                % do nothing; the meta tag is defined and not empty
            }
        }
    }
}

% shortcut for performing a check on all the meta tags we care about
\newcommand{\doMetaTagCheck}{
    \checkMetaTag{author}
    % TODO: would be nice to validate keywords on the fly
    \checkMetaTag{keywords}
    \checkMetaTag{comments}
    \checkMetaTag{difficulty}
    \ifthenelse{\(\equal{\@difficulty}{}\) \OR \( \(\@difficulty < 1\) \AND \(\NOT \equal{\@difficulty}{0}\)\)}{
        \PackageProblem{INVALID DIFFICULTY: `\@difficulty'}{Please use integer difficulties >= 0}
    }{}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These commands control whether the document will show the meta tags.  Passing
% the option [displaymeta] will cause this to be enabled.
\newcommand{\doMetaTagDisplay}{
    % if \displayMetaTags is not defined, do nothing...
    \ifthenelse{\boolean{displayMetaTags}}{
        \begin{center}
            % put a fancy side-lined marker indicating meta tags
            \raisebox{-0.3in}{ \rotatebox{90}{\Large \bf \textsf{META}} }
            \newlength{\metaTagRightColumnWidth}
            \setlength{\metaTagRightColumnWidth}{0.7\textwidth}
            \begin{tabular}{|r|p{\metaTagRightColumnWidth}|}
                \hline Author:     & \@author \\
                \hline Keywords:   & \@keywords \\
                \hline Difficulty: & \@difficulty \\
                \hline Comments:   & \begin{minipage}[t]{\metaTagRightColumnWidth}
                                     {
                                        \small
                                        \setlength{\parskip}{0.1in}
                                        \@comments
                                     }
                                     \end{minipage}\par
                                     \\
                \hline
            \end{tabular}
        \end{center}
    }{}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% problemDescription is the environment for describing the problem; nothing
% special.
\newenvironment{problemDescription}{
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % put in the title, automatically...
    \maketitle
    % display problem meta tags, if enabled
    \doMetaTagDisplay
}{}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% inputDescription is for describing the format of the input
\newenvironment{inputDescription}{\header{Input}}{\par}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% outputDescription is for describing the format of the output
\newenvironment{outputDescription}{\header{Output}}{\par}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% these are the FancyVerbatim environment settings used

\ifthenelse{\boolean{showSampleSpaces}}{\fvset{fontsize=\small,showspaces=true}}
                                       {\fvset{fontsize=\small}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% the sampleInput environment allows us to wrap any text and have it be
%% represented just like in a verbatim environment, but with a title... and
%% automatically-sized width.
%%
%% For more information about embedding Verbatim inside another environment, see
%% http://newsgroups.derkeiler.com/Archive/Comp/comp.text.tex/2006-06/msg01041.html
%% The key seems to be calling \VerbatimEnvironment within the environment.
%% However, I don't really know what that does.

\newenvironment{sampleInput}{\VerbatimEnvironment\begin{SaveVerbatim}{sampleInputSavedVerbatim}}
{\end{SaveVerbatim}
% create some boxes, but don't display them
\newsavebox{\sampleInputVerbatimBox}
\newsavebox{\sampleInputHeaderBox}
\sbox{\sampleInputVerbatimBox}{\BUseVerbatim{sampleInputSavedVerbatim}}
\sbox{\sampleInputHeaderBox}{\header{Sample Input}}
% find the widths of the boxes
\newlength{\sampleInputVerbatimWidth}
\newlength{\sampleInputHeaderWidth}
\settowidth{\sampleInputVerbatimWidth}{\usebox{\sampleInputVerbatimBox}}
\settowidth{\sampleInputHeaderWidth}{\usebox{\sampleInputHeaderBox}}
% find the maximum width between the two boxes
\newlength{\sampleInputWidth}
\ifthenelse{\lengthtest{\sampleInputVerbatimWidth < \sampleInputHeaderWidth}}
    {\setlength{\sampleInputWidth}{\sampleInputHeaderWidth}}
    {\setlength{\sampleInputWidth}{\sampleInputVerbatimWidth}}
% create the output, with appropriate boxes and widths
\begin{minipage}[t]{\sampleInputWidth}
    \vspace{\parskip}
    \usebox{\sampleInputHeaderBox}\\
    \rule[2pt]{\sampleInputWidth}{0.3pt}
    \usebox{\sampleInputVerbatimBox}
    \rule[5pt]{\sampleInputWidth}{0.3pt}
    \vspace{\parskip} % create a little vertical space in case the output is below the input
\end{minipage}
\hfill % if sample input/output are side-by-side, push the output to the right as far as possible
\hspace{0.1in} % put a little space between the sample input and output if they are side-by-side
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% the sampleOutput environment is similar to the sampleInput environment, but
%% with a different title, and no \hfill at the end

% we use a minipage environment with width 0 to wrap around the SaveVerbatim.
% Otherwise, if we don't wrap it like this, the SaveVerbatim creates a new
% paragraph, which we don't want. This is very hackish. Also, even though the
% minipage has 0 width, it still introduces some space (about 0.5in) which we
% must later remove.
\newenvironment{sampleOutput}{\VerbatimEnvironment\begin{minipage}{0in}\begin{SaveVerbatim}{sampleOutputSavedVerbatim}}
{\end{SaveVerbatim}\end{minipage}
% create some boxes, but don't display them
\newsavebox{\sampleOutputVerbatimBox}
\newsavebox{\sampleOutputHeaderBox}
\sbox{\sampleOutputVerbatimBox}{\BUseVerbatim{sampleOutputSavedVerbatim}}
\sbox{\sampleOutputHeaderBox}{\header{Sample Output}}
% find the widths of the boxes
\newlength{\sampleOutputVerbatimWidth}
\newlength{\sampleOutputHeaderWidth}
\newlength{\sampleOutputWidth}
\settowidth{\sampleOutputVerbatimWidth}{\usebox{\sampleOutputVerbatimBox}}
\settowidth{\sampleOutputHeaderWidth}{\usebox{\sampleOutputHeaderBox}}
% find the maximum width between the two boxes
\ifthenelse{\lengthtest{\sampleOutputVerbatimWidth < \sampleOutputHeaderWidth}}
    {\setlength{\sampleOutputWidth}{\sampleOutputHeaderWidth}}
    {\setlength{\sampleOutputWidth}{\sampleOutputVerbatimWidth}}
% create the output, with appropriate boxes and widths
\hspace{-0.5in} % the minipage kludge above introduces about 0.5in space, so we remove it here
\begin{minipage}[t]{\sampleOutputWidth}
    \vspace{\parskip}
    \usebox{\sampleOutputHeaderBox}\\
    \rule[2pt]{\sampleOutputWidth}{0.3pt}
    \usebox{\sampleOutputVerbatimBox}
    \rule[5pt]{\sampleOutputWidth}{0.3pt}
\end{minipage}
% paragraph ends here; don't continue this line
\par
}

