\ProvidesPackage{cards}

% Written by Ken Clary around Jeremy Brown's card TeX hacks
% Much modified by Jamie Morris

%% Place as many cards on the page as possible while keeping the
%% given margins; first build columns of cards, then build pages
%% out of the columns, since height is more likely to vary than width.

%% Invoke this with
%% (\RequirePackage or \usepackage)[options]{cards}
%% where ``options'' MUST include exactly one of
%% ``single'' (single-sided cards), 
%% ``double'' (double-sided cards),
%% ``mirror'' (mirror-sided cards, same thing on each side)
%% and can optionally include a dimension (specifying the margin
%% to leave around each side of each card) or two dimensions
%% (to specify the horizontal and vertical margins separately).
%%
%% If invoked without dimensions, double- or mirror-sided cards will
%% use the \card@default@margin specified below, while single-sided
%% cards will default to zero margin.  (Because printer alignment
%% isn't a concern with single-sided cards, so you usually want to
%% save scissors work via merger of neighboring cards' borders.)
%%
%% E.g. in a .sty file
%% \RequirePackage[double]{cards}           % double-sided, default margins
%% \RequirePackage[single]{cards}           % single-sided, no margins
%% \RequirePackage[mirror,0.5cm]{cards}     % mirrors, .5cm all around
%% \RequirePackage[single,1ex,1em]{cards}   % single-sided, 1ex horiz, 1em vert
%%
%% In a .tex file you'd use \usepackage instead of \RequirePackage, of course.

%% Commands provided:
%%
%%   \makecard{front}{back}  if you used [double]; make an arbitrary card
%%   \makecard{front}        if you used [single] or [mirror]
%%
%%   \putcard     % repeat last card once
%%   \pageof{some \makecard-based code}  % full page of cards

%% As usual, this file is arranged so that the things the Czar is
%% most likely to possibly want to frob tend towards the start
%% and the more magical parts tends towards the end.



\RequirePackage{times}
\RequirePackage{graphicx}

\geometry{margin=.3in}  % *page* margin, not card margin
\topskip=0pt

\unitlength=1in   % provide default for those using the picture environment

% default margins around each card if not set as a package option;
% this value is for double- and mirror-sided cards, if single-sidedness
% is selected it will be reset to zero!
%
\newcommand\card@default@margin{.2cm}

% since the sides might be different sizes, we frame the united area
% with a border of this width
%
\newdimen\card@border \card@border=.4pt

\newcommand\card@whitespace{%
  \fboxsep=0pt \fboxrule=\card@border
  \lineskip=0pt
  \baselineskip=0pt
  \parskip=0pt
  \parindent=0pt
  \leftskip=0pt
  \rightskip=0pt
}


%%%%%
%% Process the usage options to determine what kind of cards
%% to make and what margins to give them, as described up top.
%%
%
% Exactly one of single, double, mirror should appear.
\DeclareOption{single}{
  \special{header=simplex}  % force single-sided printing
  \newcommand\makecard[1]{\make@card{#1}{}}
  \newcommand\card@skip@back{}
  % no printer-alignment worries here, so save scissors work
  \renewcommand\card@default@margin{0pt}
}
\DeclareOption{double}{
  \special{header=duplex}  % force double-sided printing
  \newcommand\makecard[2]{\make@card{#1}{#2}}
}
\DeclareOption{mirror}{
  \special{header=mirror}  % force mirror-sided printing (respects unmirror)
  \newcommand\makecard[1]{\make@card{#1}{#1}}
}
%
% Since the margins should never be negative, we use that to mean ``not set''
\newdimen\horiz@margin  \horiz@margin -1in
\newdimen\vert@margin   \vert@margin  -1in
% All other options should be margin dimensions; if one is given, use
% it for both horiz and vert, if two are given, use each.  nonnegative.
\DeclareOption*{
  \ifdim\horiz@margin<0pt\relax
    \horiz@margin=\CurrentOption
    \vert@margin=\CurrentOption
  \else
    \vert@margin=\CurrentOption
  \fi
}
%
\ProcessOptions*
\ifx\makecard\ThisMacroShouldNotBeDefined
  \@die{cards.sty used without specifying single, double, or mirror siding}
\fi
% If either/both margins haven't been set, give them the default.
\ifdim\horiz@margin<0pt\relax \horiz@margin=\card@default@margin \fi
\ifdim\vert@margin<0pt\relax  \vert@margin=\card@default@margin  \fi
% Want extra margin at top in case there's headers; it can go away
% if they're single-sided, but *not* for zero-vert-margins on
% asymmetric double-sided since headers can interfere on *either* side.
\geometry{headsep=\card@default@margin}



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Card-making preliminary setup.
%

% the single/double/mirror options define \makecard in terms of this
\newcommand\make@card[2]{%
  \def\card@frontside{#1}%
  \def\card@backside{#2}%
  \putcard
}

% current card's front and back
\newbox\front@card
\newbox\back@card

% current column of cards; use \vtop 'cause it looks a bit nicer
% if they line up at the tops, with any empty spaces at the bottoms
\newbox\front@column	\global\setbox\front@column=\vtop{}
\newbox\back@column	\global\setbox\back@column=\vtop{}

% current page of cards
\newbox\front@page	\global\setbox\front@page=\hbox{}
\newbox\back@page	\global\setbox\back@page=\hbox{}

% for misc calculations
\newdimen\card@ht
\newdimen\card@wd
\newdimen\inner@ht
\newdimen\inner@wd
\newdimen\card@tmp

% this should be left at true almost all the time; \pageof sets
% it to false to see if the current card would spark a new page,
% in which case it wants to punt it
\newif\if@keepcard
\@keepcardtrue


%%%%%
%% \putcard, the macro which places the current card on the page.
%% If used without resetting the current \card@frontside and
%% \card@backside, it will keep placing copies of the same card.
%%
\newdef\putcard{%
  \setbox\front@card=\hbox{\card@frontside}%
  \setbox\back@card=\hbox{\card@backside}%

  \card@ht=\ht\front@card
  \advance\card@ht by \dp\front@card
  \card@tmp=\ht\back@card
  \advance\card@tmp by \dp\back@card
  \ifdim\card@tmp>\card@ht \card@ht=\card@tmp \fi
  \inner@ht=\card@ht
  \advance\card@ht by 2\vert@margin

  \card@wd=\wd\front@card
  \card@tmp=\wd\back@card
  \ifdim\card@tmp>\card@wd \card@wd=\card@tmp \fi
  \inner@wd=\card@wd
  \advance\card@wd by 2\horiz@margin

  % now put the margins in and frame it
  \rebox@card\front@card
  \rebox@card\back@card
  % framing may have altered the dimens (at least via the border)
  \card@wd=\wd\front@card
  \card@ht=\ht\front@card
  \advance\card@ht by \dp\front@card

  % can we fit this in the current column?
  \card@tmp=\ht\front@column
  \advance\card@tmp by \dp\front@column
  \advance\card@tmp by \card@ht
  \advance\card@tmp by \headsep  % lost this space at the top
  \advance\card@tmp by -\vert@margin  % don't count bottommost glue
  \ifdim\card@tmp>\textheight \put@column \else \@keepcardtrue \fi

  \if@keepcard  % \pageof will punt the card that would make the next page
    \card@tmp=\wd\front@column
    \ifdim\card@tmp<\card@wd \card@tmp=\card@wd \fi
    \global\setbox\front@column=\vtop{\hsize=\card@tmp
      \card@whitespace                         % no uncontrolled whitespace;
      \unvbox\front@column                     % previous contents,
      \hbox to \hsize{\box\front@card\hfill}%  % plus front of new card
    }%
    \global\setbox\back@column=\vtop{\hsize=\card@tmp
      \card@whitespace                         % no uncontrolled whitespace;
      \unvbox\back@column                      % previous contents,
      \hbox to \hsize{\hfill\box\back@card}%   % plus back of new card
    }%
  \fi
}


% put a frame around the card with the proper margins around that
\newcommand\rebox@card[1]{%
  \setbox#1=\hbox{\card@whitespace % no uncontrolled whitespace
    \hspace\horiz@margin        % left margin
    \vbox{\hsize=\inner@wd
      \vspace\vert@margin       % top margin
      \framebox[\hsize]{%       % center it in here, both ways
        \hfill
        \vbox to \inner@ht{\vfill\box#1\vfill}%
        \hfill
      }%
      \vspace\vert@margin       % bottom margin
    }%
    \hspace\horiz@margin        % right margin
  }%
}

%  put the current columns onto the page if possible, or start new page
\newcommand\put@column{%
  \ifdim\wd\front@column>0pt
    \card@tmp=\wd\front@page
    \advance\card@tmp by \wd\front@column
    \ifdim\card@tmp>\textwidth \put@page \else \@keepcardtrue \fi
    \if@keepcard
      \global\setbox\front@page=\hbox{\card@whitespace % no uncontrolled space;
        \unhbox\front@page    % previous contents,
        \box\front@column}%   % plus front of newly finished column
      \global\setbox\back@page=\hbox{\card@whitespace  % no uncontrolled space;
        \box\back@column      % add back of newly finished column
        \unhbox\back@page}%   % to previous contents
    \fi
    \global\setbox\front@column=\vtop{}%
    \global\setbox\back@column=\vtop{}%
  \fi
}

% send out the current page
\newcommand\put@page{%
  \ifdim\wd\front@page>0pt
    \hbox to \textwidth{\unhbox\front@page\hfill}%
    \vfil\pagebreak
    \ifx\card@skip@back\ThisMacroHadBetterNotBeDefined
      \hbox to \textwidth{\hfill\unhbox\back@page}%
      \vfil\pagebreak
    \fi
    \global\setbox\front@page=\hbox{}%
    \global\setbox\back@page=\hbox{}%
  \fi
}


% \newpage is a standard latex macro that flushes the current page;
% cause it to flush pending cards, since we haven't put them on page yet.
% Can be called by hand, and is automatically called by \end{document}.
%
\renewcommand\newpage{\put@column\put@page}


% flush pending cards, then fill up the page with the given card
\newdef\pageof[1]{%
  \newpage
  #1\relax
  \loop
    \@keepcardfalse
    \putcard
  \if@keepcard
  \repeat
}  


\vfuzz=10in      % shut up about overfull \vbox's!
\vbadness=10000	 % and underfull ones
\hfuzz=10in      % and overfull \hbox's
\hbadness=10000  % and underfull ones
