#!/usr/bin/perl -w
#
# Usage:
#     mk-page.pl [-cols N ] [-title "Title"] [ -max N ] [ -html name ] [ -f ]
#                [ -b ] [-background image] [ -v ] [ -p ] [ --prompt ]
#                directory (or path/to/file)
#
# reads all .jpg's out of "directory" and makes html code suitable for
# a completed .html file. Images are laid out side by side (with optional
# border, -b) on a row until "-cols" has been reached (2 is the default),
# or as specified in the config file (described below). Rows are continually
# created till all images are exhausted, or until -max images are on the
# page, at which point a new page is created. (html files are derived from
# the directory name, unless -html is given as a basename)
# 
# If html file exists, user must confirm overwrite, unless -f is given,
# forcing overwrite without requiring input.
#
# Captions are created for all images as part of a <table>. A background image
# can be specified with the --background option.
#
# mk-page.pl filters out all images that end with *-big.jpg because
# it assumes those files are the "big" images that correspond to the
# smaller versions of the same images. (A link to the large image is
# made if a -big.jpg file exists.)
#
# Links to large files call mk-big-page2.html, which is another perl
# program like this one but it's intent is to show images one at a time,
# and lets the user go from one item to the next (or previous).
# If you don't want to use that, use -p, which forces "plain links"
# dirctly to the -big.jpg file. (The user will have to use "back" to
# return to the page made by this script.)
#
# If the file "Files" exists in the directory (or if the last arg specified
# is a filename), then the file is read for filenames from the directory
# in which the file resides. The filenames may have a relative or absolute
# path, or even  URL, which will override the directory assumption.
# 
# Captions can be specified in the file. If no file or no caption is
# given, the caption for the image is the filename itself.
#
# A "link" can be given with each image. Currently, this must be a
# jpg file. The script automatically looks for a *-big.jpg file that
# corresponds to the "file.jpg" root name. If it exists, the link
# is made. (Thus, it doens't need to be specified in the file.)
#
# The first line in the file describes the name of the html file and its
# title (which assumes you will redirect the output of this script TO it.)
# The special string "--" must be used to specify a new row (or you'll have
# one big long row; no auto-counting is done, although a command-line
# option should be made to do that).
#
# The format of the file is:
#     web-page.html|Title of Page
#     ---  (this line is optional -- as the first one, it's a no-op. see below)
#     file1.jpg|Caption for File1|link
#     file2.jpg|Caption for File2|link
#     ---  (new row) only the first two hyphens are matched
#     file3.jpg|Caption for File3|link
#     file4.jpg|Caption for File4|link

# Packages and pragmas.
use File::Basename;
use Getopt::Long;

use strict;

# Constants.
my $cmd = basename($0);			# name by which command called
my $ver = 'TODO';			# program version

# Variables (may be overridden by arguments).
my $background = "";			# background image file
my $border = 0;
my $cols = 2;				# number of colums per row. Only used when reading raw directory.
my $debug = 0;				# verbose mode
my $force_ow = 0;
my $help = 0;				# display usage
my $htmlfile = "";			# defaults to directory.html if no other specified
my $max_images = 999;
my $plain_link = 0;
my $src = "";				# source directory
my $title;				# page title
my $version = 0;			# display version
my $prompt_cap = 0;			# use text fields instead of "captions"
my $captions_prog = "cgi/captions.cgi";	# for use with --prompt

# More variables.
my $num_images = 0;  # counts number of images being output to current page.

# Parse command line.
my %opts;
GetOptions('background=s'	=> \$background,
	   'border'		=> \$border,
	   'cols=i'		=> \$cols,
	   'debug'		=> \$debug,
	   'force_ow'		=> \$force_ow,
	   'help'		=> \$help,
	   'htmlfile=s'		=> \$htmlfile,
	   'max_images=i'	=> \$max_images,
	   'plain_link'		=> \$plain_link,
	   'title=s'		=> \$title,
	   'version'		=> \$version,
	   'prompt'		=> \$prompt_cap,
	  ) or usage();

$src = shift;

show_version() if ($version);
usage() if ($help);

# Check arguments.
my $bail = 0;
if ($src eq "") {
    print("Must specify source directory.\n");
    $bail = 1;
}
if ($max_images <= 0) {
    print("Maximum number of images must be greater than zero.\n");
    $bail = 1;
}
if ($cols <= 0) {
    print("Number of columns must be greater than zero.\n");
    $bail = 1;
}
usage() if ($bail);

# Add necessary HTML to background image, if given.
if ($background ne "") {
    $background = "BACKGROUND=\"$background\"";
}

my $from_dir = 0;
my $dir;
my @words;

# If there's an index file, read it, otherwise, read all the files
# in the specified directory.
# @words will contain the list, wherever it came from.
if (-d $src && -T "$src/Files") {
    $src = "$src/Files";
}
if (-T "$src" && open(FILES, "$src")) {
    $dir = dirname($src);
    while (<FILES>) {
        s/#.*$//;		# ignore comments and blank lines
        next if /^\s*$/;
	chomp;
        push @words, $_;
    }
    close FILES;
    if ($debug) {
        print "Warning: reading from file: \"-max\" option ignored.\n";
    }
    $max_images = 999;
} else {
    $dir = $src;
    if (! opendir DIR, "$dir") {
	print "Unable to open $dir: $!\n";
	exit -1;
    }
    $from_dir = 1;
    @words = grep !/-big/, grep /\.jpg/i, readdir DIR;
    map(s|^|$dir/|, @words);
    closedir DIR;
}

#print "There are $#words words, and they are:\n";
#map { print, print "\n"; } @words;

if ( $#words == 0 ) {
    print "No images in $dir: $!\n";
    exit 0;
}

my $total = $#words + 1;
my $start = 0;  # index to start reading from @words (see next block)
my $counter;
my $pages;

if ($from_dir == 1) {
    # @words doesn't contain what we need, build it ourselves
    my $foo = basename($src);  # "dir"
    if ($title eq "") {
	$title = $foo;
    }
    if ($htmlfile eq "") {
	($htmlfile = $foo . ".html") =~ tr/A-Z/a-z/; # dir.html
    }
    $counter = "$foo"; # file to use for counting with count.cgi
    $pages = int $total/$max_images;
    if ($total % $max_images) {
        $pages++;
    }
} else {
    # the first line has html file to use, TITLE of the page, and
    # the file to use to store visitor count data.
    my ($tmphtml, $tmptitle);
    ($tmphtml, $tmptitle, $counter) = split /\|/, $words[0];
    if ($htmlfile eq "") {
        $htmlfile = $tmphtml;  # always let command-line opts override
    }
    if ($title eq "") {
	$title = $tmptitle;    # always let command-line opts override
    }
    $start = 1;
}
if ($htmlfile !~ m/\.html$/) {
    $htmlfile = $htmlfile . ".html";  # sanity check
}


# Public methods.

=head2 usage

Display usage information and exit.

=cut

sub usage {
    print <<EOF;

Usage: $cmd [options] src-dir (or dir/FILENAME)
--background image	specify image for background
--border		put a border around images for aesthetics
--cols N 		align images N columns wide (default: 2) *
--debug			print actions that program takes
--prompt		SEE BELOW
--force_ow		force overwrite of output file if it exists
--help			display this message
--htmlfile name		filename to use for output .html file
--max_images N		maximum number of images per page (default: 999) *
--plain_link		create ordinary links to large images
--title "Title" 	title of page *
--version		display program version

If a directory contains a descriptor file, options with * have no effect.

If --prompt is given, the html page that's created has editable text
fields added under the current caption for each picture. You can edit
the captions for the images as well as the title on the page, and when
the "change captions" button is pressed, image/caption pairs are output
to the designated descriptor file.  If an existing descriptor file exists,
the values contained within are used as a default.

NOTE 1: Descriptor file must be writable by the owner of the CGI program.
NOTE 2: Order/sequence of images listed in descriptor file may not be
    preserved with --prompt.
NOTE 3: This option is really used to simplify the editing of captions
    for images, but, because it cannot preserve the order of the images
    on the page (at least until I can somehow pass the "order" information
    among the descriptor file, the html page, and the cgi program), it is
    intended for the user to edit the file afterwards to specify image order.
NOTE 4: You cannot use a | character in a caption, since that's used in
    the descriptor file as a delimeter between img name and caption.
NOTE 5: Descriptor files can also list a link for images, whether it's
    another (usually larger) jpg image, or another URL entirely. This
    is not supported by this feature.

EOF
    exit(1);
}

=head2 show_version

Display version information and exit.

=cut

sub show_version {
    print("$cmd version $ver\n".
          "Copyright (C) Dan Heller <argv\@danheller.com>\n\n".
          "$cmd comes with ABSOLUTELY NO WARRANTY.\n\n".
          "This is free software, and you are welcome\n".
          "to redistribute it under certain conditions.\n\n".
          "See `http://www.gnu.org/copyleft/gpl.html' for details.\n");
    exit 0;
}


my $page_cnt = 0;
my $newfile;
sub start_page
{
    $newfile = $htmlfile;

    $page_cnt++;
    if ($from_dir == 1 && $total > $max_images) { # prepare for multiple pages
        $newfile =~ s/.html$/$page_cnt.html/; # foo1.html, foo2.html, etc.
    }
    print "Creating $newfile...";
    if (-e $newfile && $force_ow == 0) {
	my $repl = "";
	print "File exists. Overwrite? ";
	if (<STDIN> !~ "[yY]") {
	    print "Ok. Try Again Later.\n";
	    exit 0;
	}
    }
    if (open (OUT, ">$newfile") == 0) {
	print "Error opening $newfile: $!\n";
	exit 1;
    }

    my($title) = $_[0];
    print OUT "<html><head>\n\n<title>";
    if ($from_dir == 1 && $total > $max_images) { # prepare for multiple pages
	print OUT "$title (Page $page_cnt of $pages)";
    } else {
	print OUT "$title";
    }
    print OUT "</title></head>\n<BODY $background>\n";
    if ($from_dir == 1 && $total > $max_images) { # prepare for multiple pages
	print OUT "<H1>$title (Page $page_cnt of $pages)</H1>\n\n";
    } else {
	print OUT "<H1>$title</H1>\n\n";
    }
    if ($prompt_cap) {
	print OUT "<FORM ACTION=\"$captions_prog\" METHOD=\"GET\">\n\n";
	print OUT "<br><INPUT TYPE=TEXT NAME=\"TITLE\" VALUE=\"$title\" SIZE=20><br>\n";
	print OUT "<input type=hidden name=htmlfile value=\"$newfile\">\n";
	print OUT "<input type=hidden name=columns value=\"$cols\">\n";
    }
    ($counter = "count/$newfile") =~ s/.html$//;
}

my $img_line_cnt = 0;
my $new_table = 1;
my $new_page = 1;

sub end_page
{
    if ($new_table == 0) {
	# end this table
	print OUT "\n</th></tr></table>\n</center>\n\n";
    }

    if ($from_dir && $total > $max_images) {  #create next/prev links
	my $tmpfile;
        print OUT "\n<center><h2> ";
	if ($page_cnt > 1) {
	    my($tmp) = $page_cnt - 1;
	    ($tmpfile = $htmlfile) =~ s/.html$/$tmp.html/;
	    print OUT "[ <a href=\"$tmpfile\"> Prev Page </a> ] ";
	}
	if ($page_cnt < $pages) {
	    my($tmp) = $page_cnt + 1;
	    ($tmpfile = $htmlfile) =~ s/.html$/$tmp.html/;
	    print OUT "[ <a href=\"$tmpfile\"> Next Page </a> ] ";
	}
	print OUT "</h2></center>\n\n";
    }
    if ($prompt_cap) {
	print OUT "<INPUT TYPE=\"submit\" VALUE=\"Change Captions\">\n";
	print OUT "</FORM>\n";
    }
    # end the page
    print OUT "<!--#include file=\"end-links\"-->\n";
    print OUT "<!--#exec cmd=\"cgi/count.cgi $counter\"-->\n</body></html>\n";
    print OUT "<!--#config timefmt=\"%D %r\"-->\n";
    print OUT "Page last modified:\n";
    print OUT "<!--#flastmod file=\"$htmlfile\"-->";
    close OUT;
    print "Done.\n";
}

my $imgfile;

for (my $i = $start; $i < $total; $i++) {
    my $caption = "";
    my $link = "";
    my $link_is_html = 0;
    if ($debug) {
	print "words[$i] = $words[$i]\n";
    }
    ($imgfile, $caption, $link) = split /\|/, $words[$i];
    if ($debug) {
	print "imgfile=\"$imgfile\", caption=\"$caption\", link=\"$link\"\n";
    }
    $imgfile = "" if (!defined($imgfile)); # code relies on defined values
    $caption = "" if (!defined($caption));
    $link = "" if (!defined($link));

    if ($link eq "") { # Look for a big file
	$link = $imgfile;
	$link =~ s/\.jpg$/-big.jpg/; # "file.jpg" => "file-big.jpg"
	# print "null link, setting to \"$link\"\n";
    }
    # if the link is a web address, just assume it's fine.
    if ($link =~ m/^http:/ || $link =~ m/\.html$/ || $link =~ m/\.htm$/) {
        $link_is_html = 1;
    } else {
	# test to see if the link really exists (if it's a filename)
	my $testlink = $link;
	if (dirname($testlink) eq ".") {
	    # imgfile specified is in local dir -- make a pathname
	    # that's at least relative to the directory we know to exist.
	    $testlink = "$dir/$link";
	}
	if (-e "$testlink") {  # final check
	    $link = $testlink;
	} else {
	    $link = "";
	}
    }

    if ($caption eq "") {
        ($caption = basename($link eq "" ? $imgfile : $link)) =~
	    s/(-big)?.jpg$//;
    }

    # see if we need to end the current table...either we hit a line that
    # starts with "--", or we're reading from a directory listing, and there
    # are already two images in this row
    if ($imgfile =~ m/^--/ || ($from_dir == 1 && $img_line_cnt == $cols) ||
            $num_images == $max_images) {
        # new/end block
	# if this ISN'T a block separator (--), then check if we've
	# exceeded max_images, and start a new page.
	if ($num_images == $max_images && $imgfile !~ m/^--/) {
	    end_page();
	    $new_page = 1;	# do another page
	} elsif ($new_table == 0) {  # if we ended the page, table's closed
	    # close this table
	    print OUT "\n</th></tr></table>\n</center>\n\n";
	}
	$new_table = 1;
	$img_line_cnt = 0;
	next if ($imgfile =~ m/^--/);
    }
    # we're ready to output html. See if it's a new page.
    if ($new_page == 1) {
	start_page($title);
        $new_page = 0;
	$new_table = 1;
	$num_images = 0;
    }
    if ($new_table == 1) {
        print OUT "<center>\n<table><tr><th>\n\n";
	$new_table = 0;  # reset
	$img_line_cnt = 0;
    } 
    # make the imgfile into full path/URL if it's not already
    if (dirname($imgfile) eq ".") { # imgfile specified is local to dir
	$imgfile = "$dir/$imgfile"; # prepend directory name.
    }
    if ($img_line_cnt >= 1) {
	print OUT "\n</th><th>\n\n"; # next image in table of images
    }

my $hbig_a = "<a href=\"LINKFILE\">";	# plain link
my $lbig_a = "<a href=\"LINKFILE\">";	# plain link
my $xbig_a = "<a href=\"cgi/mk-big-page2.cgi\?indexhtml=HTMLFILE\&directory=../DIR\&imgidx=LINKFILE\&heading=CAPTIONX\">";
my $xbig_b = "</a>";

my $fototmpl = "<table border=$border> <caption align=bottom>\n";
$fototmpl .= "<b><i>Xbig_a CAPTION Xbig_b </i></b>\nXTEXT</caption> <tr><th>\n";
$fototmpl .= "Xbig_a <img hspace=0 align=right border=0 src=\"XXX\"> Xbig_b\n";
$fototmpl .= "</th></tr></table>\n";
    # write out the html for this image
    my $xtext = "";  # if --prompt was given
    my $Xbig_a;
    my $Xbig_b = $xbig_b;
    if ($link ne "") {  # there's a link, add the substitutions
	if ($plain_link || $link_is_html) {
	    if (dirname($link) eq ".") {
		$link = "/" . $link;
	    }
	    if ($link_is_html) {
	        # $link .= "\"><img WIDTH=50 HEIGHT=46 border=0 align=left src=\"/images/photo-tour.gif";
	    }
	    $_ = $lbig_a;
	    s|DIR|$dir|g;
	    s|LINKFILE|$link|g;
	    $Xbig_a = $_;
	} else {
	    my $baselink = basename($link);
	    my $captionX = $caption;
	    $captionX =~ s/\s/%20/g;
	    $_ = $xbig_a;
	    s|HTMLFILE|/$newfile|g;  # add "/" for mk-big-page2.cgi
	    s|DIR|$dir|g;
	    s|LINKFILE|$baselink|g;
	    s|CAPTIONX|$captionX|g;
	    $Xbig_a = $_;
	}
    } else {
	$Xbig_a = "";  # no link -- leave it alone
	$Xbig_b = "";
    }
    if ($prompt_cap) {
	my $file = basename($imgfile);
	$xtext = "<br><INPUT TYPE=TEXT NAME=\"$file\" VALUE=\"$caption\" SIZE=20>";
    } 
    $_ = $fototmpl;
    s|Xbig_a|$Xbig_a|g;
    s|Xbig_b|$xbig_b|g;
    s|CAPTION|$caption|g;
    s|XXX|$imgfile|g;
    s|CAPTION|$caption|g;
    s|XTEXT|$xtext|g;
    print OUT;
    $num_images++;   # counting actual images output (for $max_images)
    $img_line_cnt++;
}
end_page();

exit 0;

# for later use...
sub getcap
{
    my $heading;
    my $extra;
    my($capname) = "$imgfile";
    $capname =~ s/\.jpg$/.cap/;

    if (open CAPFILE, "$capname") {
	$heading = <CAPFILE>; # caption in file takes precedence
	while (<CAPFILE>) {
	    chomp;
	    $extra .= $_ . "<br>";
	}
	close (CAPFILE);
    } else {
	# ($words[$idx], $heading) = ($words[$idx] =~ /^\s*(\S+)\s*(.*)/);
	if ($heading eq "") {
	    $heading = "$title";
	}
	$extra = " ";
    }
}
