#!/usr/local/bin/perl 

### MORE LATER - This has not been tested with 4 level hierarchy!!!
### MORE LATER - Should we preserve image filename extensions???
### MORE LATER - Add Eric Wilhelm's Text::Slidez

#  Warning!  This is PastaCode(tm), like spagetti code only more expensive

=head1  wydiwys  =====  What You Draw Is What You See  =====

make a web presentation from a list of graphics
Version 0.7  2009 Jul 17  KHL

Thus wydiwys may be obsolete, please check  http://www.server-sky.com/wydiwys

 Usage:   cat design_file1 design_file2 [...] | wydiwys
 or       wydiwys < design_file
              The design control file is on standard input

WYDIWYS outputs many html files to the presentation output directory,
along with hardlinks to images.  It also builds the subdirectory design/,
which contains a copy of the original design and template files, as well as
a prototype design file that can be used for rebuilding the presentation.

The WYDIWYS presentation behavior is defined by the template file, and
the stylesheets and javascript files that calls.  You will not normally
need to modify WYDIWYS to make radical changes in presentation behavior.

WYDIWYS is licensed under GPL2, and may also be used with the Perl Artistic
License.  See www.gnu.org for more information about the GPL2.  Original
design Copyright 2009 by Keith Lofstrom under the above terms, added
material copyright the respective authors. 

Make your mother proud;  please share with others!

=head1  Presentation control buttons

There are 5 navigation buttons,  FIRST, LAST, PREV, NEXT, and ENTER
These are provided by multiple keyboard keys.  The last 3 buttons can
be provided by an RF/USB clicker a.k.a. Wireless Presenter.

The "F11" (full or windowed screen) button is not used by the javascript
and is passed through to the browser.

This version of the program ignores the mouse, though hyperlinks
are certainly possible and may be included in a later version.

The code mapping key recognition occurs in the javascript included
in the template file (for now, template.html ).  Here are the codes
(decimal) in the template as of 2009 May 25:

 FIRST:  36, keyboard "home", no code on presenter
 LAST:   35, keyboard "end", no code on presenter

 NEXT:   40, keyboard "down arrow"
 NEXT:   39, keyboard "right arrow"
 NEXT:   34, keyboard "page down"
 NEXT:   34, presenter "forward" or ">" button
 NEXT:   32, keyboard "space"

 PREV:   38, keyboard "up arrow"
 PREV:   37, keyboard "left arrow"
 PREV:   33, keyboard "page up"
 PREV:   33, presenter "back" or "<" button
 PREV:    8, keyboard "backspace"

 ENTER:  13, keyboard "enter" or "return" key
 ENTER:  66, presenter "display select" button (looks like two overlaid screens)

To learn what codes java sees from various devices, you use the
keycode tester at:   http://www.asquare.net/javascript/tests/KeyCode.html
The presenter tools usually have more buttons, but the emitted codes seem
inconsistent.  Later versions of this code may find ways to map them, to
forward/last or perhaps to full/windowed screen .

=head2  design and navigation 

Typically, this program sets up a three-tier navigation system,
though multiple tiers is possible.  

The bottom tier is a linear sequence of html image pages,
each with an imbedded image (PNG and SWF preferred, but any
browser-friendly image format can be used) and some javascript
that interprets the clicks.   There are two varieties of image
page, SLIDE and BUILD.  

The FIRST, LAST, PREV, and NEXT buttons move through this series
as a flat presentation, similar to a non-hierarchical presenter. 
Clicking FIRST goes to the first slide, clicking LAST moves to 
the END slide, which is the end of the normal presentation and
the beginning of supplemental slides.  Traditional presenters
click to the very last slide, which is less useful.  If you want
the program to behave like traditional presenters, leave out the
END tag in the input design file. 

The bottom (or "leaf") tier has an important additional function:
the ENTER button.  This moves from the current image page to a
"section" page, with the current SLIDE image page highlighted.  If
we are clicking out of a SLIDE image page, a second click on ENTER
returns to that SLIDE image page.  If we are clicking out of a
BUILD image page, then the second ENTER returns us to the SLIDE
page that begins the sequence of BUILD pages.  Since slide builds
are typically presented as a set, this allows us to repeat the
whole set.

The section page organizes a group of SLIDE pages.  When we click
ENTER to move it, we will see a list of all the slides in the 
section, and a top level list entry for the master page, discussed
below.  The slide/build set we just came from will be highlighted,
using bolds and large fonts.  The slides around it will be less
highlighted, in medium font.  The other slides in the list will
be small font.  We can use FIRST, LAST, PREV, and NEXT to navigate
this list, just like we navigate through the slides.   When we find
the slide we like, we click ENTER to move back to that position in
the slide set at the bottom tier.  The first position is the master
slide (or a higher level section slide);  clicking on that moves us
to a higher level of the hierarchy, typically to the top master
slide.

There can be many section pages.  In actual fact, these are sets
of related section pages, each with a different leaf slide highlighted.
There is one more entry for the master page.  So for each section
page connecting to N leaf slides, there are actually N+1 associated
HTML pages in the set.

The top tier is the "master" list page, another text list file that 
navigates just like a section page.  Unlike lower sections, this
has no upward link.  If there are N sections, there are N pages in
the set comprising the master page.  

If there are no SECTION clauses in the input deck, then the
master page becomes the one and only section.  This is useful
for navigating short slide shows.  The master page has N entries
for N slides, and no upwards links.

Normal presentations will have two or three levels of hierarchy.
However, it should be possible to build many levels of hierarchy
with properly sequenced SECTION slides in the input deck.  This
permits very long collections of slides, for example, a week-long
course, organized by day, morning/afternoon, then section. 

=head2  input file format

wydiwys pulls the design information from standard input.
You can feed it a file with the "<" input operator, or you can
use "cat" and other tools to produce the input.  This allows 
wydiwys to be used in pipes from tools that generate or massage
the input format.

=head3 design file input command syntax

=head4 <OUTD(IR)   presentation_output_directory >

OUTDIR is the path to the presentation output directory.  The program
creates a directory named with the date and time if OUTDIR is omitted.
Do not use "." as the output directory - not only is this stupid,
the first thing wydiwys does is delete the output directory, and
start up a new one, so this will wipe out everything in the current
directory.  Probably not what you want.
  
=head4 <IND(IR)    image_source_directory_default_"." >

INDIR can be any point in the filesystem tree.  It can be ".", and
all files are referenced to the current directory (this is the 
default if INDIR is omitted).  INDIR is simply appended to the
front of each image path (which can be hierarchical).  

There can be multiple INDIR commands, which apply to all image sources
following the INDIR command, until the next INDIR command.

=head4 <TEMP(LATE) template.html >

TEMPLATE is the name of the template file including the path relative
to the current working directory.  If there is no TEMPLATE command, 
the default is named "template.html" in the current working directory.
The default template file that comes with WYDIWYS should be adequate
for most presentations, but it may be desirable to modify the template
to resize the size of flash animations, for example.

MORE LATER - a description of the template file.


=head4 <SECT(ION)  section_name    optional_uplink_name_default_"master" >

SECTION names, at any level of hierarchy, must be unique.  While
slides or builds in different sections can have the same name, they
cannot have the same name as a section.

Please do not use space, tab, carriage return, or other whitespace
in slide or section names.   Avoid using \ or / or > or " in slide
or section names.  Use "_" for white space.  The parser for this is
pretty stupid, but it is even stupider to break it with stupid names,
then complain.   The section names aaaaa, zzzzz, 00000, and index 
are reserved.

=head4 <SLIDE    slide_name      image_source_path  >

=head4 <BUILD    slide_name_or_"_or_''_for_ditto    image_source_path   >

=head4 <FLASH    flash_name      image_source_path  [loop]  >

=head4 <FILE     file_name       file_source_path   >

Link in a file.  The files  wydiwys.js  and  jquery.js  are usually linked
in, and often a stylesheet.  However, you can use a different template and
link in different javascript code and change the presentation behavior of
wydiwys - this Perl code does not need to be changed for that!

=head4 <TEXT     slide_name      text file source   [slide number]   >

This will look like Eric Wilhelm's Text::Slidez, but is not yet implemented.

=head4 <END>    

END is optional and has no argument.  END follows the end of the normal
presentation, and precedes extra slides.  

=head2  output file format

The show organizer outputs all its files into the directory specified
by OUTDIR.  That directory is flat.   The image files are included
in that directory using hardlinks - if this is program is translated
to a primitive operating system like Windows, then expensive file 
copies will be needed instead.  The real advantage of using hardlinks
for the image slides is that if the images are updated, so are the 
files in OUTDIR.  Windows users will just have to do a lot of mouse
work to move the files manually.  If that is too much work, install
service pack Linux.

The show organizer produces lots of small HTML files with embedded
java, with approximately two HTML files for every image slide.
There are 9 kinds of files in OUTDIR:

=head3 1) Image files 

Image files have the same name as the slide_section, without the .html
suffix.  Most browsers do not need a type suffix to identify image
content.  If they do - oops.  For Linux/Unix and Mac, these are hard
links to the original content.  We do not use the original content name
because the same image name may be used more than once.

=head3 2) Slide pages

Slide pages are named slidename_section.html .  Slides from different
sections can have the same base name.

=head3 3) Build pages

Like slide pages. If the input control deck specifies a name for a 
build file, then the slide is named  buildname_section.html . If
the input file name is ditto ( " or '' ) then the slide is named
slidename_N_section.html, where N is the integer number of the build
in the build sequence.
 
=head3 4) Flash pages

Like slide pages, same naming convention.

=head3 5) Section pages

Section pages are named sectionname_slidename.html, or perhaps
sectionname1_sectionname2.html for higher level sections.  There is a
section page for every slide and lower level section.

=head3 6) Master pages

Master pages are just section pages, named master_sectionname.html 
(or master_slidename.html) for simple two-level presentations. 
These are constructed by the same code that constructs all the other
levels of presentation.

=head3 7) Text pages

Text pages are pure html pages, synthesized similarly to Eric Wilhelm's
Text::Slidez .  Not yet implemented.

=head3 8) Files

Style sheets, Javascript libraries, and other useful files.

=head3 9) design directory

This directory contains design and template files suitable for
reconstructing the presentation, as well as a copy of the version
of wydiwys used for constructing the original.  With these files,
the presentation may be replicated elsewhere, and the wydiwys code
propagated to the world.

=cut

#----------------------------------------------------------------------------

use Cwd  qw(abs_path cwd);  
use strict;

# default template
my  $filetemplate = "template.html" ;

# test for input arguments -------------------------------------
# for now, there should not be any.  Later, there will be
# arguments for directories and templates.

my $numargs = @ARGV ;
if ($numargs != 0 ) {
   print "usage:  wydiwys < slidefile\n";
   print "    reads slidefile(s) from standard input, makes a slide show\n";
   exit;
}

#----------------------------------------------------------------------------
# read list from standard input and store in memory
# remove comments
# lines may spill over;  <> separates clauses, vaguely xml-like
# V2.0 may name all the elements, rather than just use position ordering

# files used to reconstruct input
my $design_all  ="";         
my $original_all="";
my $design_proto_all="#Design prototype control file to re-run WYDIWYS\n";
$design_proto_all  .="#  edit this file, then wydiwys < design_proto\n";
$design_proto_all  .="#  to build a modified presentation\n";
$design_proto_all  .="##<OUTDIR #you should put an output directory here#>\n";
$design_proto_all  .="<INDIR ..> #assumes WYDIWYS run from this directory\n";
$design_proto_all  .="#modify the above lines as needed\n";

while( <> ) {
   $original_all .= $_ ;
   chomp ;                                      # remove carriage returns
   my( $before, $after ) =  split( "#" , $_ );  # remove comments
   $design_all .=  $before ;
}

# parse design_all  into complete statements, one per line

$design_all =~ s/\s+/ /g       ; # replace long whitespace with space
$design_all =~ s/^ *< *//      ; # remove first <
$design_all =~ s/ *> *$/\n/    ; # remove last >, add linefeed
$design_all =~ s/ *> *< */\n/g ; # put in linefeeds between, take out extra space

# design_all now contains a series of lines from standard input
#           (the design commands), split on carriage returns with
#           the <> brackets removed along with all unnecessary white space

my @design_lines = split( "\n", $design_all ); # split the lines into an array

# design_lines is an array of input lines, one clause per line,
#             no <> or excess white space

# set up to parse the input lines ----------------------------------------

my $indir=  "."             ; # slide image source directory, default "."
my $outdir= localtime()     ; # presentation output directory, default datetime
$outdir =~ s/\S+\s+// ;
$outdir =~ s/\s+// ;
$outdir =~ s/\s+/_/g ;
$outdir =~ s/://g ;

# print "$outdir\n";

#  section slide -------------------------------------
my $section     ="master"   ; # name of section
my @sectionlist =("master") ; # list of all sections, in linear section order

# indexed by the section name
my %sectionslide=()         ; # hash of list of pages in each section

#  enter link hash
my %enterlink   =() ;  

#  The enterlink hash contains the links, initiated by enter, for every
#  named page in the display deck.
#
#  Every SLIDE image page generates two enterlinks, an uplink from an
#  individual slide image page to the section set, and a downlink from
#  the section set to the individual slide image page.
# 
#  Every BUILD image page generates only one enterlink, an uplink from
#  the individual build image page to the same section set as the most
#  recently preceding slide image page.  There are no downlinks from
#  the section set ot the individual build image page.
#  
#  Every SECTION entry generates two enterlinks, an uplink (typically
#  from section set to master set) and a downlink (typically from
#  master set to section set).  If the SECTION entry has two arguments,
#  then another section set is linked to instead.
#
#  Every master or section set is actually a set of individual pages
#  connected by the 5 control buttons and the links they activate.
#  
#  Here are three examples
#
####   3 level hierarchy:
#
#  The tree of connections for 9 slides and 3 builds in 3 sections
#  with 3 levels of hierarchy can look like this: 
#
#  ma_U_sec0 --- sec0_D_ma 
#     |               |
#     |          sec0_U_sld0 --- sld0_D_sec0
#     |               |               |
#     |          sec0_U_sld1 --- sld1_D_sec0
#     |               |               |
#     |               |          bld2_D_sec0
#     |               |               |
#     |          sec0_U_sld3 --- sld3_D_sec0
#     |                               |
#     |                               |
#  ma_U_sec1 --- sec1_D_ma            |
#     |               |               |
#     |          sec1_U_sld4 --- sld4_D_sec1
#     |               |               |
#     |          sec1_U_sld5 --- sld5_D_sec1
#     |                               |
#     |                               |
#  ma_U_sec2 --- sec2_D_ma       bld6_D_sec1
#                     |               |
#                sec2_U_sld7 --- sld7_D_sec2   < This could be the
#                     |               |           designated end slide
#                     |          bld8_D_sec0  
#                     |               |
#                sec2_U_sld9 --- sld9_D_sec2
#                     |               |
#                sec2_U_sldA --- sldA_D_sec2
#                     |               |
#                sec2_U_sldB --- sldB_D_sec2
#
#  master        sections        slide/buids
#  1 set of 3    3 sets of 3     9 slides
#                       or 2     3 builds
#                       or 4
#
####   2 level hierarchy:
#
#  Less common.  There are no sections, but there are nearly as
#  many pages and the result may be harder to navigate for large
#  slide sets.  Good for very small presentations, where all the
#  slides can be listed on one page.
#
#  ma_U_sld0 --- sld0_D_ma
#     |               |
#  ma_U_sld1 --- sld1_D_ma
#     |               |
#     |          bld2_D_ma
#     |               |
#  ma_U_sld3 --- sld3_D_ma
#     |               |
#  ma_U_sld4 --- sld4_D_ma
#     |               |
#  ma_U_sld5 --- sld5_D_ma
#     |               |
#  ma_U_sld7 --- sld7_D_ma   < This could be the
#     |               |        designated end slide
#     |          bld8_D_ma  
#     |               |
#  ma_U_sld9 --- sld9_D_ma
#     |               |
#  ma_U_sldA --- sldA_D_ma
#     |               |
#  ma_U_sldB --- sldB_D_ma
#
#  master        slides/builds
#  1 set of 10   9 slides
#                3 builds
#
#
####   4 level hierarchy:
#
#   4 or more levels of hierarchy will have more section
#   slides, but very large or multiday presentations will
#   be easier to organize as one slide set. 
#
#  ma_U_day0 ------------------- day0_D_ma 
#     |                               |
#     |                          day0_U_sld0 --- sld0_D_sec0
#     |                               |               |
#     |                          day0_U_sld1 --- sld1_D_sec0
#     |                               |               |
#     |                               |          bld2_D_sec0
#     |                               |               |
#     |                          day0_U_sld3 --- sld3_D_sec0
#  ma_U_day1 --- day1_D_ma                            |
#                     |                               |
#                day1_U_sec1 --- sec1_D_day1          |
#                     |               |               |
#                     |          sec1_U_sld4 --- sld4_D_sec1
#                     |               |               |
#                     |          sec1_U_sld5 --- sld5_D_sec1
#                     |                               |
#                     |                          bld6_D_sec1
#                day1_U_sec2 --- sec2_D_day1          |
#                                     |               |
#                                sec2_U_sld7 --- sld7_D_sec2    <...end...
#                                     |               |         
#                                     |          bld8_D_sec0  
#                                     |               |
#                                sec2_U_sld9 --- sld9_D_sec2
#                                     |               |
#                                sec2_U_sldA --- sldA_D_sec2
#                                     |               |
#                                sec2_U_sldB --- sldB_D_sec2
#                            
#  1 set of 2    1 set of 2      3 sets of 4     slides/builds
#                                       or 5     9 slides
#                                       or 3     3 builds
#
#  UP and DOWN go up and down the master set or each section set
#  or the slide/build set.   Further UP clicks remain at the top
#  or first element of the set.  Further DOWN clicks remain at the
#  bottom or last element of the set.
#
#  FIRST always goes to the first or top element of each set.
#
#  LAST goes to the bottom or last element of each section or
#  master set.  However, an END command following a slide or
#  build makes that slide the destination of the LAST click. 
#  That is typically the end of a normal presentation, and the
#  start of the extra slides and builds.  These can still be
#  reached with DOWN, and the END has no effect on upper sections
#  or the master.
#
#  Note that master and sections also have href links for every slide.
#  If a mouse is available, it can be used to go directly to the link
#  without using clickers or keyboard keys.  URLs will go straight to
#  the desired slide.  However, since slides become associated with
#  sections, it may be complicated to remember the name to go to.
#
#  However, you can use browser bookmarks!  This is a nice way to 
#  return to a point in a presentation after jumping off who knows
#  where.
#
#
#  current leaf slide -----------------------------------
my $slidename   ="" ;  # name if leaf slide ( filename has .html appended)
my @slidelist   =() ;  # list of all slides, in linear slide order
my @filelink    =() ;  # list of files to link
my $slidebase   ="" ;  # text of first slide in sequence of builds
my $slidename   ="" ;  # name of slide with appended section (unique)
my $sectslidename="";  # name of corresponding section slide (unique)
my $buildcount  =0  ;  # count of slides in build
my $lastslide   ="" ;  # name of last slide, before extras
my $first       ="" ;  # first image slide full name with .html
my $last        ="" ;  # last  image slide full name with .html

# indexed by the slide name
my %slidetarget =() ;  # slide image target, hardlinked to 
my %slideimage  =() ;  # slide image source path and name, hardlinked from
my %slidesection=() ;  # hash of section, per slide
my %slidetext   =() ;  # text of slide name
my %flashflag   =() ;  # if FLASH, loop true or false

$slidetext{ "master" } = "master" ;

# now parse the input lines from the file in memory --------------------

foreach ( @design_lines ) {
   my $inline = $_ ;                       # save line for parsing

   if(    /^IND\S* (\S+)/  ) {             # image input directory
      $indir = $1;                         # name of source directory
   } 

   elsif( /^OUTD\S* (\S+)/ ) {             # presentation output directory
      $outdir = $1;                        # name of target directory
      $outdir = abs_path($1);              # full path to target directory
      my $cwd = cwd();                     # what place is this?
      die "OUTDIR $1 is current directory - this will eat your own brain\n"
      if( $outdir eq $cwd ) ;
   }

   elsif( /^TEMP\S* (\S+)/ ) {             # template file
      $filetemplate = $1 ;
      $design_proto_all .= "<TEMPLATE $1>\n" ;  
   }

   elsif( /^SECT\S* (\S+) (\S+)/) {        # new section with uplink section
                                           # $1 section, $2 uplink section

      # test for _U_ or _D_ error
      die "SECTION name $1 cannot contain _U_ or _D_\n"
         if( ( $1 =~ m/_U_/ ) or ( $1 =~ m/_D_/ ) ) ;
      die "SECTION name $2 cannot contain _U_ or _D_\n"
         if( ( $2 =~ m/_U_/ ) or ( $2 =~ m/_D_/ ) ) ;
      
      push( @sectionlist, $1 ) ;           # add section to sectionlist

      # add  uplink  section page and text
      my $u = $2 . "_U_" . $1 ;
      push( @{$sectionslide{ $1 }}, $u );  # uplink section entry
      $slidetext{ $u } = $2 ;              # section text for uplink

      # add downlink section page and text
      my $d = $1 . "_D_" . $2 ;
      push( @{$sectionslide{ $2 }}, $d );  # downlink section entry
      $slidetext{ $d } = $1 ;              # section text for downlink

      $section = $1 ;
      $enterlink{ $d } = $u ;
      $enterlink{ $u } = $d ;

      $design_proto_all .= "<SECTION $1 $2>\n" ;  
   }

   elsif( /^SECT\S* (\S+)/) {              # new section with master section

      # test for _U_ or _D_ error
      die "SECTION name $1 cannot contain _U_ or _D_\n"
         if( ( $1 =~ m/_U_/ ) or ( $1 =~ m/_D_/ ) ) ;

      my $m = "master" ;                   # $1 section, $m master section
      push( @sectionlist, $1 ) ;           # add section to sectionlist

      # add  uplink  section page and text
      my $u = $m . "_U_" . $1 ;
      push( @{$sectionslide{ $1 }}, $u );  # section uplink to master
      $slidetext{ $u } = $m ;              # master text for uplink

      # add downlink section page and text
      my $d = $1 . "_D_" . $m ;
      push( @{$sectionslide{ $m }}, $d );  # master downlink to section
      $slidetext{ $d } = $1 ;              # section text for downlink
   
      $section = $1 ;
      $enterlink{ $d } = $u ;
      $enterlink{ $u } = $d ;

      # make a new design file
      $design_proto_all .= "<SECTION $1>\n" ;  
   }

   # the slide page name is $slidename_$section.html
   # the corresponding section page name is $section_$slidename.html

   elsif( /^SLIDE (\S+) (\S+)/) {      # first or independent slide
      $slidebase  = $1           ;     # slide base name

      # a more robust test is needed, probably something that errors out
      # if we push something on $sectionslide that already exists
      # test for _U_ or _D_ error
      die "SECTION name $1 cannot contain _U_ or _D_\n"
         if( ( $1 =~ m/_U_/ ) or ( $1 =~ m/_D_/ ) ) ;

      $slidename     = $slidebase . "_D_" . $section ;
      $sectslidename = $section . "_U_" . $slidebase ;

      $slidetext{ $slidename     } = $slidebase ; # text for section slide
      $slidetext{ $sectslidename } = $slidebase ; # text for section slide
      push( @slidelist, $slidename );     # add to list of displayed slides
      push( @filelink,  $slidename );     # add hardlink
      $slideimage{$slidename} = $indir . "/" . $2;  # path to slide image
      $slidesection{$slidename} = $section ;
      $buildcount = 0 ;

      # MORE LATER - save extension of original image file ???

      # add section slidename to per-section list
      push( @{$sectionslide{$section}}, $sectslidename );

      $enterlink{ $slidename } = $sectslidename ;
      $enterlink{ $sectslidename } = $slidename ;

      # MORE LATER add extension ???
      $design_proto_all .= "<SLIDE $slidebase $slidename>\n" ;  
   }

   elsif( /^FLASH (\S+) (\S+)/ ) { # independent flash slide
      $slidebase  = $1           ;     # slide base name

      # a more robust test is needed, probably something that errors out
      # if we push something on $sectionslide that already exists
      # test for _U_ or _D_ error
      die "SECTION name $1 cannot contain _U_ or _D_\n"
         if( ( $1 =~ m/_U_/ ) or ( $1 =~ m/_D_/ ) ) ;

      $slidename     = $slidebase . "_D_" . $section ;
      $sectslidename = $section . "_U_" . $slidebase ;

      $slidetext{ $slidename     } = $slidebase ; # text for section slide
      $slidetext{ $sectslidename } = $slidebase ; # text for section slide
      push( @slidelist, $slidename );     # add to list of displayed slides
      push( @filelink,  $slidename );     # add hardlink

      # MORE LATER - save extension of original image file ???
      $slideimage{$slidename} = $indir . "/" . $2;  # path to flash file

      # is there a third parameter for loop?
      # this should be extensable for multiple options ...
      my  $loopflag = "False" ;
      my  $looparg = "" ;
      if( $inline =~ m/^FLASH \S+ \S+ (\S+)/ ) {
         if( $1 eq "loop" ) { $loopflag = "True" } 
         $looparg = $1 ;
      }

      $flashflag{$slidename}  = $loopflag ;
      $slidesection{$slidename} = $section ;
      $buildcount = 0 ;

      # add section slidename to per-section list
      push( @{$sectionslide{$section}}, $sectslidename );

      $enterlink{ $slidename } = $sectslidename ;
      $enterlink{ $sectslidename } = $slidename ;

      # MORE LATER add extension ???
      $design_proto_all .= "<FLASH $slidebase $slidename $looparg>\n" ;  
   }

   elsif( /^BUILD (\S+) (\S+)/) {  # continuation or build slide
      # keep previous sectslidename
      
      if( ( $1 eq "\"" ) or ( $1 eq "\'\'" ) ) {   # " or '' means ditto
         $slidename = $slidebase . "_$buildcount" . "_$section" ;
         # MORE LATER add extension ???
         $design_proto_all .= "<BUILD \" $slidename>\n" ;  
      }
      else {
         $slidename = $1 . "_D_" . $section;         # slide name
         # MORE LATER add extension ???
         $design_proto_all .= "<BUILD $1 $slidename>\n" ;  
      }

      # MORE LATER - save extension of original image file ???
      push( @slidelist, $slidename );     # add to list of displayed slides
      push( @filelink,  $slidename );     # add hardlink
      $slideimage{$slidename} = $indir . "/" . $2;  # path to slide image
      $slidesection{$slidename} = $section ;
      $buildcount++ ;

      # no push;  does not have a corresponding entry on section page

      $enterlink{ $slidename } = $sectslidename ;
   } 

   elsif( /^TEXT (\S+) (\S+) (\d*)/) {
      # target name  source file   [slide count]
      # MORE LATER - Eric Wilhelm's Text::Slidez 
      die "Text slides not yet implemented:[$_]";
   }

   elsif( /^FILE (\S+) (\S+)/) {            # copy/hardlink a file
      push( @filelink, $1 );                # add hardlink target
      $slideimage{$1} = $indir . "/" . $2;  # path to file source
   }

   elsif( /^END/)  {               # end of main slide set, extras follow
      $last=$slidename . ".html";
      $design_proto_all .= "<END>\n"  ;
   }  

   else {
      # MORE LATER this clause should complain about unknown syntax
      die "I don't understand this statement:[$_]";
   }
}

$first = $slidelist[0] . ".html" ;
unless( $last =~ m/html/ ) { $last = $slidename . ".html" ; }

# read slide template ---------------------------------------------------

my $template = readtemplate( $filetemplate );

my ( $template_top, $image_entry, $flash_entry,
     $section_entry, $template_bottom ) =
   split( "<!-- CUT HERE -->", $template );
close(F) ;

my $slidetemplate = $template_top . $image_entry . $template_bottom ;
my $flashtemplate = $template_top . $flash_entry . $template_bottom ;

#------------------------------------------------------------------------
# arrays all built, start making directories and files

# make presentation target directory
mkdir  $outdir or die "cannot make new presentation directory $outdir\n";

# make design file directory
my    $desdir = "$outdir/design" ;
mkdir $desdir or die "cannot make design file directory $desdir\n";

# make design proto files -----------------------------------------------
# these files can be used to rebuild the presentation

# copy wydiwys itself
open( F, "< $0" ) or die "cannot read wydiwys original\n";
open( T, "> $desdir/wydiwys" ) or die "cannot write $desdir/wydiwys\n";
print T $_ for ( <F> ) ;
close( F );
close( T );

# make an image of the input design (was on stdin) to the output directory
open( F, "> $desdir/design_original" )
      or die "cannot write design file $desdir/design_original.html\n";
print F $original_all ;
close( F );

# make an image of a "design prototype file" to the output directory
open( F, "> $desdir/design_proto" )
      or die "cannot write re-design file $outdir/design_proto\n";
print F $design_proto_all ;
close( F );

#make an image of the template file to the output directory
open( F, "> $desdir/$filetemplate" )
      or die "cannot write template file $desdir/$filetemplate\n";
print F $template ;
close( F );

# make display content -------------------------------
# make hardlinks between image source and target
# foreach $slidename ( @slidelist ) {
foreach $slidename ( @filelink ) {
   my $olink = $slideimage{$slidename} ;
   my $nlink = $outdir . "/" . $slidename ;
   # MORE LATER add extension to nlink name???
   link $olink, $nlink or die "cannot link $olink to $nlink\n";
}

my $prev  ;                # where to go if previous or back button hit
my $this  ;                # the current slide
my $next  ;                # where to go if next or forward button hit
my $enter ;                # where to go if enter button hit

# build the leaf slide pages ------------------------------

for( my $index=0 ; $index <= $#slidelist ; $index++ ) {

   # find previous and next slide indexes, truncate at ends
   my( $prev_index, $next_index ) = prevnext( $index, 0, $#slidelist ) ;

   $this    =  $slidelist[$index] ;
   my $text = $slidetext{$this};
   my $sect = $slidesection{$this};
   $enter   = "$enterlink{$this}.html"       ;  # url of section slide
   $prev    = "$slidelist[$prev_index].html" ;
   $next    = "$slidelist[$next_index].html" ;

   my $teststring = "$index $this";
   # printf "$this $flashflag{$this}\n" ;

   # set up slide template
   my $outslide = $slidetemplate ;

   # change to flash slide if flagged
   if( exists $flashflag{$this} ) {
      $outslide = $flashtemplate ;
   } ;

   # insert variables into slide text
   $outslide =~ s/%%first%%/$first/g ;
   $outslide =~ s/%%last%%/$last/g   ;
   $outslide =~ s/%%this%%/$this/g ;
   $outslide =~ s/%%enter%%/$enter/g ;
   $outslide =~ s/%%prev%%/$prev/g ;
   $outslide =~ s/%%next%%/$next/g ;
   $outslide =~ s/%%test%%/$teststring/g ;
   $outslide =~ s/%%loopvalue%%/$flashflag{$this}/g;   # loop True or False

   open( F, "> $outdir/$this.html\0" )
      or die "cannot write $outdir/$this.html\n";
   print F $outslide ;
   close( F );
}


# build the section slide pages -----------------------------

# both the section and master pages are Mac-style "select expanded",
# that is, most lines are displayed small, but the selected line is
# displayed in large font, and its neighbors displayed in medium font
# the first entry is the uplink

# build the section page sets
my $sectionend ;

# outer loop - all section sets
foreach $section ( @sectionlist ) {
   $sectionend = $#{$sectionslide{$section}} ;  # index of end slide in section

   # middle loop - section page in the set, one entry highlighted
   for( my $index1 = 0 ; $index1 <= $sectionend ; $index1++ ) {

      my $teststring = "";  # add text here to put comment in HTML

      $slidename    = $sectionslide{$section}[$index1] ;

      # find previous and next slide indexes, truncate at ends
      my( $prev_index, $next_index ) = prevnext( $index1, 0, $sectionend ) ;

      my $enterpage = "$enterlink{$slidename}.html"              ;  
      my $firstpage = "$sectionslide{$section}[          0].html";
      my $lastpage  = "$sectionslide{$section}[         -1].html";
      my $nextpage  = "$sectionslide{$section}[$next_index].html";
      my $prevpage  = "$sectionslide{$section}[$prev_index].html";
      
      my $outslide  =  $template_top ;
      $outslide     =~ s/%%enter%%/$enterpage/g ;
      $outslide     =~ s/%%first%%/$firstpage/g ;
      $outslide     =~ s/%%last%%/$lastpage/g ;
      $outslide     =~ s/%%next%%/$nextpage/g ;
      $outslide     =~ s/%%prev%%/$prevpage/g ;
      $outslide     =~ s/%%test%%/$teststring/g ;

      # inner loop - entries on the section page
      for( my $index2 = 0 ; $index2 <= $sectionend ; $index2++ ) {
         my $text   =  $slidetext{$sectionslide{$section}[$index2]};
	 my $size   =  fontsize( $index1 - $index2 );
         my $href   =  "$enterlink{$sectionslide{$section}[$index2]}.html";

         my $entry  =  $section_entry     ;   # copy from template
         $entry     =~ s/%%text%%/$text/g ;   # label of entry
         $entry     =~ s/%%size%%/$size/g ;
         $entry     =~ s/%%href%%/$href/g ;
         $outslide .=  $entry ;
      }
      $outslide .= $template_bottom ;

      # section slide is ready, construct filename

      my $sectfile = $outdir . "/" . $slidename . ".html";

      open( F, "> $sectfile" ) or die "cannot write $sectfile\n";
      print F $outslide ;
      close( F );
   }
}

# and finally, symlinks to the first slide
#   whole bunches of different names, because I might forget!

my $dirfirst = $outdir . "/" . $first  ;
my $indfirst = $outdir . "/index.html" ;
my $ooofirst = $outdir . "/00000.html" ;
my $aaafirst = $outdir . "/aaaaa.html" ;
my $zzzfirst = $outdir . "/zzzzz.html" ;

link $dirfirst, $indfirst ;
link $dirfirst, $ooofirst ;
link $dirfirst, $aaafirst ;
link $dirfirst, $zzzfirst ;

# end of program
#===========================================================================
#  subroutines

# -------------------------------------------------------------------------
# load the template file into text
sub  readtemplate
{
  my ($tpath) = @_;

  local $/;                            # slurp mode (undef)
  local *F;                            # create local filehandle

  open(F, "< $tpath\0") or die "cannot read file $tpath\n";

  my $temptxt = <F>;                   # read the whole file
  close(F);                            # ignore retval
  return $temptxt ;
}

# -------------------------------------------------------------------------
# find previous and next indexes given the current index, start, and end
sub prevnext {
   my ( $index, $start, $end ) = @_ ;

   # prev = index-1  or  index (if equal to start )
   my $prev = $index-1 ;
   $prev = $start  if( $prev < $start ) ;

   my $next = $index+1 ;
   $next = $end    if( $next > $end   ) ;

   return ( $prev, $next ) ;
}

# -------------------------------------------------------------------------
# expanded font size for selected position in list
#
sub fontsize
{
   my ( $position ) = @_ ;
   if(    $position ==  0 ) { return "\"font-size:160%\"" ; }
   elsif( $position ==  1 ) { return "\"font-size:115%\"" ; }
   elsif( $position == -1 ) { return "\"font-size:115%\"" ; }
   else                     { return "\"font-size:100%\"" ; }
}

# -------------------------------------------------------------------------
# this is the end of the subroutine
