#!/usr/bin/env perl

## A script for creating MagicPoint files from a very simple input format
## that is similar to Shawn Ostermann's smaker format for making LaTeX 
## slides.
##
##
## Copyright (c) 2001 BBNT Solutions LLC
##
## Permission to use, copy, modify, and distribute this software
## and its documentation for any purpose is hereby granted without
## fee, provided that the above copyright notice and this permission
## appear in all copies and in supporting documentation, and that the
## name of BBN Technologies not be used in advertising or publicity
## pertaining to distribution of the software without specific,
## written prior permission.  BBN makes no representations about the
## suitability of this software for any purposes.  It is provided "AS
## IS" without express or implied warranties.
##
##
## Mark Allman
## NASA Glenn Research Center/BBN Technologies
## mallman@bbn.com
## January 2003

## Version.

$version = "1.24.2";

## Default values for various parameters.

$default_font_size = 4;
$current_font_size = $default_font_size;

$default_vgap = 15;
$t = "11";
$T = "7";
$I = "2";
$default_vgap_ps = 40;
$t_ps = "39";
$T_ps = "28";
$I_ps = "6";
$current_vgap = $default_vgap;

$font_size_bullet = 4;

$barwidth = 5;

$default_fore = "black";
$fore_color = $default_fore;

$default_back = "white";
$back_color = $default_back;

$bg_grad = "";

$default_bullet = $default_fore;
$bullet_color = $default_bullet;

$default_bar_color = $default_fore;
$bar_color = $default_bar_color;

$default_ccolor = "black";
$ccolor = $default_ccolor;

$default_prefix = " ";
$default_pre_spaces = 1;
$prefix = $default_prefix;

$bot_txt [1] = "";
$bot_txt [2] = "";
$bot_txt [3] = "";
$bot_pos [1] = 0;
$bot_pos [2] = 34;
$bot_pos [3] = 68;
$bot_align [1] = "left";
$bot_align [2] = "center";
$bot_align [3] = "right";
$bot_es [1] = "  ";
$bot_es [2] = "";
$bot_es [3] = "";

$foot_color = "";

$tab_spaces{1} = "  ";
$tab_spaces{2} = "    ";
$tab_spaces{3} = "      ";
$tab_spaces{4} = "        ";

$tab_icon{1} = "arc";
$tab_icon{2} = "delta3";
$tab_icon{3} = "box";
$tab_icon{4} = "dia";

$screen = 1;
$ps = 2;
$where = $screen;

## Table of commands and number of arguments expected.

$cmds{"P"} = "%pause";                            $args{"P"} = 0;
$cmds{"Ac"} = "%center";                          $args{"Ac"} = 0;
$cmds{"Al"} = "%leftfill";                        $args{"Al"} = 0;
$cmds{"Ar"} = "%right";                           $args{"Ar"} = 0;
$cmds{"Ftt"} = "%font \"typewriter\"";            $args{"Ftt"} = 0;
$cmds{"Fbf"} = "%font \"thick\"";                 $args{"Fbf"} = 0;
$cmds{"Fno"} = "%font \"standard\"";              $args{"Fno"} = 0;
$cmds{"Fit"} = "%font \"italics\"";               $args{"Fit"} = 0;
$cmds{"Fbi"} = "%font \"boldit\"";                $args{"Fbi"} = 0;
$cmds{"tight"} = "%vgap " . $t;                   $args{"tight"} = 0;
$cmds{"Tight"} = "%vgap " . $T;                   $args{"Tight"} = 0;
$cmds{"TIGHT"} = "%vgap " . $I;                   $args{"TIGHT"} = 0;
$cmds{"S"} = "%size";                             $args{"S"} = 1;
$cmds{"V"} = "%vgap";                             $args{"V"} = 1;
$cmds{"PS"} = "";                                 $args{"PS"} = 1;
$cmds{"Ilt"} = "";                                $args{"Ilt"} = 1;
$cmds{"C"} = "";                                  $args{"C"} = 1;
$cmds{"I"} = "";                                  $args{"I"} = 2;
$cmds{"Br"} = "";                                 $args{"Br"} = 99;
$cmds{"Bl"} = "";                                 $args{"Bl"} = 99;
$cmds{"Bc"} = "";                                 $args{"Bc"} = 99;

## Initialization.

$current_latex_file = 0;
$current_slide = 0;
$append_to_file = 0;
$bullet_spacer = 0;
$in_defines = 1;

## Process the command line arguments.

sub mmaker_usage
{
    printf ("mmaker [options] input_file [output_file]\n");
    printf ("options:\n");
    printf (" -a       append to output file\n");
    printf (" -n X     set first slide number to X + 1\n");
    printf (" -p       output suitable for mgp2ps\n");
    exit (0);
}

sub parseargs
{
    if ($#ARGV < 0)
    {
	mmaker_usage ();
    }
    for ($i = 0; $i <= $#ARGV; $i++)
    {
	$_ = $ARGV[$i];
	if (/^\-n$/ && ($i < $#ARGV))
	{
	    $current_slide = $ARGV[++$i];
	}
	elsif (/^\-a/)
	{
	    $append_to_file = 1;
	}
	elsif (/^\-p/)
	{
	    $where = $ps;
	}
	elsif (length ($infile) == 0)
	{
	    $infile = $ARGV[$i];
	}
	elsif (length ($outfile) == 0)
	{
	    $outfile = $ARGV[$i];
	}
	else
	{
	    mmaker_usage ();
	}
    }
    if (length ($infile) == 0)
    {
	mmaker_usage ();
    }
    open (IN,"< $infile") || die "can't open specified input file\n";
    $_ = $infile;
    if (length ($outfile) == 0)
    {
	if (/\.mm$/)
	{
	    s/.mm/.mgp/;
	}
	else
	{
	    $_ .= ".mgp";
	}
	$outfile = $_;
    }
    if ($append_to_file)
    {
	open (OUT,">> $outfile") || die "can't open specified output file\n";
    }
    else
    {
	open (OUT,"> $outfile") || die "can't open specified output file\n";
    }
    printf ("mmaker %s\n", $version);
    printf (" input file:  %s\n", $infile);
    printf (" output file: %s", $outfile);
    if ($append_to_file)
    {
	printf (" (appending)");
    }
    printf ("\n");
}

## Dump the defaults out to the MagicPoint file.

sub dump_header
{
    ##
    ## Default fonts.
    ##
    print OUT "%deffont \"standard\" xfont \"helvetica-medium-r\", ";
    print OUT "tfont \"standard.ttf\", tmfont \"hoso6.ttf\"\n";
    print OUT "%deffont \"thick\" xfont \"helvetica-bold-r\", tfont ";
    print OUT "\"thick.ttf\", tmfont \"hoso6.ttf\"\n";
    print OUT "%deffont \"typewriter\" xfont \"courier-medium-r\", ";
    print OUT "tfont \"typewriter.ttf\", tmfont \"hoso6.ttf\"\n";
    print OUT "%deffont \"italics\" xfont \"helvetica-medium-r\", ";
    print OUT "tfont \"standard.ttf\", tmfont \"hoso6.ttf\"\n";
    print OUT "%deffont \"boldit\" xfont \"helvetica-medium-r\", ";
    print OUT "tfont \"standard.ttf\", tmfont \"hoso6.ttf\"\n";
    ##
    ## Standard page heading.
    ##
    print OUT "%default 1 center, size 2, fore \"", $fore_color, "\", ";
    print OUT "back \"", $back_color, "\",";
    print OUT " font \"standard\", hgap 0\n";
    print OUT "%default 2 size 6, vgap 10, prefix \"", $prefix, "\", fore ";
    print OUT "\"", $fore_color, "\", font \"thick\"\n";
    print OUT "%default 3 size 1, bar \"", $bar_color, "\" ";
    print OUT $barwidth, ", vgap 0, leftfill, font \"standard\"\n";
    print OUT "%default 4 size 5, fore \"", $fore_color, "\", vgap 30, ";
    print OUT "prefix \" \", ";
    print OUT "font \"standard\"\n";
    ##
    ## Standard bulleting for lists.
    ##
    print OUT "%tab 1 ";
    print OUT "vgap ", $default_vgap, ", prefix \"", $tab_spaces{1}, 
	"\", icon ";
    print OUT $tab_icon{1}, " \"", $bullet_color, "\" 35, hgap 0\n";
    print OUT "%tab 2 size ", $font_size_bullet;
    print OUT ", vgap ", $default_vgap, ", prefix \"", $tab_spaces{2},"\", ";
    print OUT "icon ", $tab_icon{2}, " \"", $bullet_color, "\" 40, hgap 0\n";
    print OUT "%tab 3 size ", $font_size_bullet;
    print OUT ", vgap ", $default_vgap, ", prefix \"", $tab_spaces{3}, 
	"\", icon ";
    print OUT $tab_icon{3}, " \"", $bullet_color, "\" 35, hgap 0\n";
    print OUT "%tab 4 size ", $font_size_bullet;
    print OUT ", vgap ", $default_vgap, ", prefix ";
    print OUT "\"", $tab_spaces{4}, "\", icon ", $tab_icon{4}, " \"";
    print OUT $bullet_color, "\" 40, hgap 0\n";
}

## Finish a slide.

sub endslide
{
    print OUT "%ccolor \"", $ccolor, "\"\n";
    return if ($notitle == 1);
    if (length ($foot_color))
    {
	print OUT "%fore \"", $foot_color, "\"\n";
    }
    for ($i = 1; $i <= 3; $i++)
    {
	if (length ($bot_txt [$i]))
	{
	    if ($where == $screen)
	    {
		printf (OUT "%area 100 3 %d 96, size 90, ", $bot_pos [$i]);
		print OUT $bot_align [$i], "\n";
	    }
	    else
	    {
		printf (OUT "%area 100 10 %d 96, size 300, ", $bot_pos [$i]);
		print OUT $bot_align [$i], "\n";
		print OUT $bot_es [$i];
	    }
	    $_ = $bot_txt [$i];
	    if (/\%d/)
	    {
		s/\%d/$current_slide/;
		print OUT $_;
	    }
	    else
	    {
		print OUT $bot_txt [$i];
	    }
	    if ($i == 3)
	    {
		print OUT "  ";
	    }
	    print OUT "\n";
	}
    }
}

## Start a new slide.

sub startslide
{
    print OUT "%page, size ", $current_font_size, ", vgap ";
    print OUT $current_vgap, ", fore \"", $fore_color, "\"";
    if (length ($bg_grad))
    {
	print OUT "\n%bgrad ", $bg_grad, "\n";
    }
    else
    {
	print OUT ", back \"", $back_color, "\"\n";
    }
    $dumped_header = 0;
    $bullet_spacer = 0;
    $tight = 0;
    $notitle = 0;
    $current_slide++;
}

## Set the header for the current slide.

sub set_header
{
    if (/^$/)
    {
	print OUT "%nodefault\n";
	if (length ($bg_grad))
	{
	    print OUT "%font \"standard\", ";
	}
	else
	{
	    print OUT "%font \"standard\", back \"", $back_color, "\", ";
	}
	print OUT "fore \"", $fore_color, "\", size ";
	print OUT $current_font_size, ", vgap ", $current_vgap, "\n";
	print OUT "\n\n\n";
	print OUT "%area 100 100, leftfill\n";
	$notitle = 1;
    }
    else
    {
	if (/^\+$/)
	{
	    print OUT "\n", $last_title, " (cont.)\n\n";
	}
	else
	{
	    chop;
	    print OUT "\n", $_, "\n\n";
	    $last_title = $_;
	}
	print OUT "%size ", $current_font_size, "\n";
    }
    $dumped_header = 1;
}

## Insert a bullet.

sub insert_bullet
{
    if ($bullet_spacer)
    {
	print OUT "%size 1, vgap 0\n";
	if ($tight == 1)
	{
	    print OUT "\n";
	}
	elsif ($tight == 0)
	{
	    print OUT "\n\n";
	}
	print OUT "%size ", $current_font_size, ", vgap ", $current_vgap, "\n";
    }
    ($pre) = /^([ ]*\.)/;
    $rest = substr ($_,length ($pre));
#     ($rest) = /^[ ]*\.(.*)$/;
    for ($i = 0; $i < length ($pre); $i++)
    {
	print OUT "\t";
    }
    print OUT $rest;
    $bullet_spacer = 1;
}

## Insert an item into a numbered list.

sub insert_numbered_item
{
    if ($bullet_spacer)
    {
	print OUT "%size 1, vgap 0\n";
	if ($tight == 1)
	{
	    print OUT "\n";
	}
	elsif ($tight == 0)
	{
	    print OUT "\n\n";
	}
	print OUT "%size ", $current_font_size, ", vgap ", $current_vgap, "\n";
    }
    ($pre) = /^([ ]*\#)/;
    $level = length ($pre);
    if (/^[ ]*\#\d+/)
    {
	($seed,$rest) = /^[ ]*\#(\d+)(.*)$/;
	$level_n{$level} = $seed;
    }
    else
    {
	($rest) = /^[ ]*\#(.*)$/;
	if ($level_n{$level} == 0)
	{
	    $level_n{$level} = 1;
	}
    }
    $bullet_prefix = $prefix . $tab_spaces{$level};
    print OUT "%prefix \"", $bullet_prefix, "\"\n";
    print OUT $level_n{$level}, ". ", $rest, "\n";
    print OUT "%prefix \"", $prefix, "\"\n";
    $level_n{$level}++;
    $bullet_spacer = 1;
}

## Routines to deal with the short-hand commands included with mmaker.

sub unknown_cmd
{
    print "unknown key: ", $key, " in line:\n  ";
    print $orig_line;
    exit (0);
}

sub cmd_process
{
    $orig_line = $_;
    s/^\*//;
    @fields = split (' ');
    $key = $fields [0];
    if ($cmds{$key} && ($args{$key} == 0))
    {
	print OUT $cmds{$key}, "\n";
	if (/^tight/)
	{
	    $tight = 1;
	}
	elsif (/^Tight/ || /^TIGHT/)
	{
	    $tight = 2;
	}
    }
    elsif (($args{$key} == 1) && length ($fields [1]))
    {
	if (/^Ilt/)
	{
	    print OUT "%newimage -yscrzoom ", $fields [1], " \"";
	    print OUT $lfnps, "\"\n";;
	}
	elsif (/^PS/)
	{
	    if ($fields [1] =~ /^\-PS/)
	    {
		$fields [1] = $default_pre_spaces;
	    }
	    print OUT "%prefix \"";
	    for ($i = 0; $i < $fields [1]; $i++)
	    {
		print OUT " ";
	    }
	    print OUT "\"\n";
	}
	elsif (/^S/)
	{
	    if ($fields [1] =~ /^\-$/)
	    {
		$fields [1] = $default_font_size;
	    }
	    $current_font_size = $fields [1];
	    print OUT "%size ", $current_font_size, "\n";
	}
	elsif (/^V/)
	{
	    if ($fields [1] =~ /^\-$/)
	    {
		$fields [1] = $default_vgap;
	    }
	    $current_vgap = $fields [1];
	    print OUT "%vgap ", $current_vgap, "\n";
	}
	elsif (/^C/)
	{
	    $color = ($fields [1] =~ /^\-$/) ? $default_fore : $fields [1];
	    print OUT "%fore \"", $color, "\"\n";
	}
	else
	{
	    print OUT $cmds{$key}, " ", $arg, "\n";
	}
    }
    elsif (($args{$key} == 2) && length ($fields [1]) && 
	   length ($fields [2]))
    {
	if (/^I /)
	{
	    print OUT "%newimage -yscrzoom ", $fields [2], " \"";
	    print OUT $fields [1], "\"\n";;
	}
	else
	{
	    unknown_cmd ();
	}
    }
    elsif ($args{$key} == 99)
    {
	$tmp = $_;
	chop;
	if (length ($_) > 3)
	{
	    s/...//;
	}
	else
	{
	    $_ = "";
	}
	$remain = $_;
	$_ = $tmp;
	if (/Bl/)
	{
	    $bot_txt [1] = $remain;
	}
	elsif (/Bc/)
	{
	    $bot_txt [2] = $remain;
	}
	elsif (/Br/)
	{
	    $bot_txt [3] = $remain;
	}
	else
	{
	    unknown_cmd ();
	}
    }
    else
    {
	unknown_cmd ();
    }
}

## Generate a latex file on the fly and generate eps for inclusion in the
## presentation.

sub latex_first_line
{
    $current_latex_file++;
    $lfnbase = "MGP-LATEX-" . $infile . "-" . $current_latex_file . ".";
    $lfntex = $lfnbase . "tex";
    open (LOUT,"> $lfntex");
    print LOUT "\\documentclass{article}\n";
    print LOUT "\\pagestyle{empty}\n";
    print LOUT "\\thispagestyle{empty}\n";
    print LOUT "\\begin{document}\n";
    s/^.//;
    print LOUT;
}

sub latex_new_line
{
    s/^.//;
    print LOUT;
}

sub latex_end
{
    print LOUT "\\end{document}\n";
    close (LOUT);
    `latex -interaction=nonstopmode $lfntex`;
    $lfnps = $lfnbase . "ps";
    $lfndvi = $lfnbase . "dvi";
    `dvips -E -o $lfnps $lfndvi > /dev/null 2>&1`;
}

sub latex_process
{
	if (/^\)/)
	{
	    $latex_skip = 1;
	    if ($inlatex)
	    {
		latex_new_line ();
	    }
	    else
	    {
		latex_first_line ();
		$inlatex = 1;
	    }
	}
	else
	{
	    latex_end ();
	    $inlatex = 0;
	}
}

sub process_define ()
{
    ($arg) = /[Dd][Ee][Ff][Ii][Nn][Ee]\:\s+\w+\s+(.*)$/;
    if (/bgcolor/)
    {
	$back_color = $arg;
    }
    elsif (/bgrad/)
    {
	$bg_grad = $arg;
    }
    elsif (/fgcolor/)
    {
	$fore_color = $arg;
    }
    elsif (/ccolor/)
    {
	$ccolor = $arg;
    }
    elsif (/bulcolor/)
    {
	$bullet_color = $arg;
    }
    elsif (/barcolor/)
    {
	$bar_color = $arg;
    }
    elsif (/barwidth/)
    {
	$barwidth = $arg;
    }
    elsif (/lfooter/)
    {
	$bot_txt [1] = $arg;
    }
    elsif (/cfooter/)
    {
	$bot_txt [2] = $arg;
    }
    elsif (/rfooter/)
    {
	$bot_txt [3] = $arg;
    }
    elsif (/footcolor/)
    {
	$foot_color = $arg;
    }
    else
    {
	print "illegal define in line:\n  ", $_;
	exit (1);
    }
}

## Main program.

parseargs ();
if ($where == $ps)
{
    $default_vgap = $default_vgap_ps;
    $t = $t_ps;
    $T = $T_ps;
    $I = $I_ps;
}
while (<IN>)
{
    ## Handle define: commands at the beginning of an input file.
    if ($in_defines && (/^define\: /i || /^\%/))
    {
	if (/^\%/)
	{
	    print OUT;
	    next;
	}
	else
	{
	    if (!$append_to_file)
	    {
		process_define ();
		next;
	    }
	    else
	    {
		print "cannot use define when appending to an existing file\n";
		exit (1);
	    }
	}
    }
    elsif ($in_defines)
    {
	$in_defines = 0;
	if (!$append_to_file)
	{
	    dump_header ();
	    startslide ();
	}
    }
    $latex_skip = 0;
    ## Handle inlined LaTex (needed for tables, equations, etc.).
    if ($inlatex || /^\)/)
    {
	latex_process ();
    }
    next if ($latex_skip);
    ## Just dump MagicPoint commands and comments directly into the output.
    if (/^%/)
    {
	print OUT;
    }
    ## End the current slide and start a new one.
    elsif (/^---$/)
    {
	endslide ();
	startslide ();
    }
    ## This is an mmaker command.
    elsif (/^\*/)
    {
	cmd_process ();
    }
    ## If this slide does not yet have a header, make one.
    elsif ($dumped_header == 0)
    {
	set_header ();
    }
    else
    {
	s/\*Fno /\n%font \"standard\"\n%cont\n/;
	s/\*Ftt /\n%font \"typewriter\"\n%cont\n/;
	s/\*Fbf /\n%font \"thick\"\n%cont\n/;
	s/\*Fit /\n%font \"italics\"\n%cont\n/;
	## This is an item in a bulleted list.
	if (/^[ ]*\./)
	{
	    insert_bullet ();
	}
	## This is an item in a numbered list.
	elsif (/^[ ]*\#/)
	{
	    insert_numbered_item ();
	}
	## Otherwise this line is nothing special and so it should be dumped to
	## the output verbatim.
	else
	{
	    print OUT;
	}
    }
}
close (IN);
if ($inlatex)
{
    latex_end ();
}
if ($dumped_header)
{
    endslide ();
}
close (OUT);
open (LAST,"> .mmaker-last-slide");
print LAST $current_slide, "\n";
close (LAST);
exit (0);


# need a command:
#  *Ac     -- center
#  *Al     -- left
#  *Ar     -- right
#  *P      -- pause
#  *Ftt    -- set font to "typewriter" (works inline)
#  *Fno    -- set font to "standard" (works inline)
#  *Fbf    -- set font to "thick" (works inline)
#  *Fit    -- set font to "italics" (works inline)
#  *tight  -- squeeze text together some
#  *Tight  -- squeeze text together more
#  *TIGHT  -- squeeze text together even more
#  *S x    -- set size to x
#  *V x    -- set vgap to x
#  *C x    -- set color to x
#  *Ilt x  -- slurp the last latex piece in and set size to x
#  *I x y  -- slurp image x and set to size y
#  *Br x   -- set footnote for right side
#  *Bl x   -- set footnote for left side
#  *Bc x   -- set footnote for center

# global options:
#  *S, *Br, *Bl, *Bc
#  (everything else reset after each slide)
