#!/usr/bin/perl -w
# prtasmdfacts.pl - Generate printable addition/subtraction or
#	multiplication/divison fact boxes or sentences

use CGI qw(escapeHTML);

my $cgi = new CGI();
my $def_output = 'Sentences';
my $def_min = 0;
my $def_max = 9;
my $em_scale = 0.75;	# Font-size (CSS em)-to-width scaling factor

#======================================================================
# Subroutines

#----------------------------------------------------------------------
sub show_header
{
	my $oper = $cgi->param('oper') || '+';
	my $output = $cgi->param('output') || $def_output;

	$oper = ($oper eq '+')? 'Addition/Subtraction': 'Multiplcation/Division';
	$output = ($output =~ /boxes/i)? 'Boxes': 'Sentences';

	my $loper = lc($oper);
	my $loutput = lc($output);
	my @oper = split('/', $loper);

	print <<HTML;
Content-type: text/html

<html>
<head>
<title>$oper Fact $output</title>
<meta name="description" value="Printable $loper fact $loutput" />
<meta name="keywords" value="$oper[0] facts,printable $oper[0] facts,$oper[1] facts,printable $oper[1] facts,math tools,teaching tools" />
<style type='text/css'>
body { font-family: sans-serif; }
h1 { font-size: 20pt; }
.problem { font-family: monospace; }
input.num { text-align: right; }
\@media print {
.noprint { display: none; }
}
</style>
</head>
<body>
HTML
}

#----------------------------------------------------------------------
sub show_form
{
	my $minopf = $cgi->textfield('-name' => 'min_op', '-size' => 3, '-class' => 'num', '-default' => $def_min, '-title' => 'Minimum operand (usually 0, 1, or 2)');
	my $maxopf = $cgi->textfield('-name' => 'max_op', '-size' => 3, '-class' => 'num', '-default' => $def_max, '-title' => 'Maximum operand (usually between 9 and 12)');
	my $operf = $cgi->popup_menu('-name' => 'oper', '-values' => [ '+', '*' ], '-default' => '+', '-title' => 'Operation (+ for addition/subtraction, * for multiplication/division)');
	my $outputf = $cgi->popup_menu('-name' => 'output', '-values' => [ 'Boxes', 'Sentence', 'Sentences' ], '-default' => $def_output, '-title' => 'Output format (summary boxes or math sentence(s))');
	my $breakf = $cgi->textfield('-name' => 'break', '-size' => 3, '-class' => 'num', '-title' => 'Number per page (0 or blank = no forced breaks; check Print Preview)');

	print <<HTML;
<form class='noprint' method='POST'>
<div>Minimum: $minopf &nbsp; Maximum: $maxopf &nbsp;
Operation: $operf &nbsp; Output: $outputf &nbsp;
Per page: $breakf &nbsp;
<input type='submit' value='Generate' /></div>
</form>
HTML
}

#----------------------------------------------------------------------
sub show_footer
{
	print <<HTML;
</body>
</html>
HTML
}

#----------------------------------------------------------------------
sub generate_problems
{
	my @problems;
	my $min_op = $cgi->param('min_op') || $def_min;
	my $max_op = $cgi->param('max_op');
	my $oper = $cgi->param('oper') || '+';

	$min_op = 0 if ($min_op < 0);
	$max_op = $def_max unless (defined($max_op));
	$max_op = $min_op if ($max_op < $min_op);

	foreach my $op1 ($min_op .. $max_op)
	{
		foreach my $op2 ($op1 .. $max_op)
		{
			if ($oper eq '+')
			{
				push(@problems, "$op1+$op2=" . ($op1 + $op2));
			}
			else
			{
				push(@problems, "$op1*$op2=" . ($op1 * $op2));
			}
		}
	}

	return \@problems;
}

#----------------------------------------------------------------------
sub show_box_problems
{
	my ($problems) = @_;
	my $max_op = $cgi->param('max_op');
	my $em_wid = sprintf("%.2f", (length($max_op) + 1) * $em_scale);

		print <<HTML;
<style type='text/css'>
div.problem { float: left; padding: 1em; page-break-inside: avoid; }
div.and { float: left; padding-left: 0.3em; position: absolute; }
table.problem { border-collapse: collapse; }
.problem td { text-align: center; vertical-align: middle; border: solid 1px black; }
.problem .op td { width: ${em_wid}em; }
</style>
HTML

	my $breakpt = $cgi->param('break');
	my $n = 0;

	foreach my $problem (@$problems)
	{
		my ($op1, $oper, $op2, $res) = ($problem =~ /(\d+)(.)(\d+)=(\d+)/);
		my $oper1 = ($oper eq '+')? '+': '&times';

		print "<div style='clear: both; page-break-after: always;'></div>\n"
		  if ($n && $breakpt && $n % $breakpt == 0);
		print <<HTML;
<div class='problem'><table class='problem'>
<tr class='result'><td colspan='2'><div class='and'>$oper1</div>$res</td></tr>
<tr class='op'><td>$op1</td><td>$op2</td></tr>
</table></div>
HTML
		++$n;
	}
}


#----------------------------------------------------------------------
sub show_sentence_problems
{
	my ($problems, $permute) = @_;
	my $longest = $problems->[$#{$problems}];
	my $em_wid = sprintf("%.2f", (length($longest) + 5) * $em_scale);

	print <<HTML;
<style type='text/css'>
div.problem { float: left; padding: 1em; page-break-inside: avoid; }
table.problem { border: solid 1px #CCC; border-collapse: collapse; }
.problem td { text-align: center; width: ${em_wid}em; }
</style>
HTML

	my $breakpt = $cgi->param('break');
	my $n = 0;

	foreach my $problem (@$problems)
	{
		my ($op1, $oper, $op2, $res) = ($problem =~ /(\d+)(.)(\d+)=(\d+)/);
		my ($oper1, $oper2) = ($oper eq '+')?
		  ('+', '&minus;'): ('&times;', '&divide;');

		print "<div style='clear: both; page-break-after: always;'></div>\n"
		  if ($n && $breakpt && $n % $breakpt == 0);
		print "<div class='problem'><table class='problem'>\n";
		print "<tr><td>$op1 $oper1 $op2 = $res</td></tr>\n";
		if ($permute)
		{
			if ($op1 != $op2)
			{
				print "<tr><td>$op2 $oper1 $op1 = $res</td></tr>\n";
			}
			else
			{
				print "<tr><td>&nbsp;</td></tr>\n";
			}
			if ($oper ne '*' || $op1)
			{
				print "<tr><td>$res $oper2 $op1 = $op2</td></tr>\n";
			}
			else
			{
				print "<tr><td>&nbsp;</td></tr>\n";
			}
			if ($op1 != $op2 && ($oper ne '*' || $op2))
			{
				print "<tr><td>$res $oper2 $op2 = $op1</td></tr>\n";
			}
			else
			{
				print "<tr><td>&nbsp;</td></tr>\n";
			}
		}
		print "</table></div>\n";
		++$n;
	}
}

#======================================================================
# Main program

show_header();
show_form();
my $output = $cgi->param('output') || '';
if ($output)
{
	my $problems = generate_problems();
	if ($output =~ /boxes/i)
	{
		show_box_problems($problems);
	}
	elsif ($output =~ /sentence(s?)/i)
	{
		show_sentence_problems($problems, $1);
	}
}
show_footer();

# END
