#!/usr/local/bin/perl -w

##
## flashkanji - generate html "flashcards" derived from the edict, enamdict
## and kanjidic dictionaries by using the "lookup" program.
##
## flashkanji - Copyright (C) David Sitsky, August 1997.
##

## Please modify the following 5 variables to reflect your site's 
## configuration.
##
$lookup = "/home/sits/lookup/lookup";     # Location of lookup program
$jconv = "/home/sits/bin/jconv";          # Location of jconv program
$edict = "/home/sits/lib/edict";          # Location of edict file 
$kanjidic = "/home/sits/lib/kanjidic";    # Location of kanjidic file
$titlegif = "/home/sits/devel/title.gif"; # Location of title.gif (this comes
				          # with the flashkanji distribution)

##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation; either version 1, or (at your option)
##  any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program; if not, write to the Free Software
##  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

## Some banner strings for the flashcard html files.
##
require "ctime.pl";
$version = "1.0";
$date = &ctime(time);
$created = "Created by flashkanji $version, $date";
$copyright =
    "Copyright (C) <a href = \"http://cap.anu.edu.au/~sits\">" .
    "David Sitsky</a> <a href = \"mailto:sits\@cafe.anu.edu.au\">" .
    "sits\@cafe.anu.edu.au</a>.";
$html_prologue = "<body text=\"#ffffff\" bgcolor=\"#666666\" link=\"#00ff00\"\
vlink=\"#999999\">";

## Global variables which record which switches have been activated in the
## program.
##
$grade = -1;			# The grade to use in our kanji set (if any).
$limit = -1;			# Limit on number of kanji compounds to use.
$random_compounds = 0;		# Are the selection of compounds random?
$random_order = 0;		# Is the presentation of flashcards randomised?
$reverse_test = 0;		# Is english flashed instead of kanji?
$directory = "";		# Directory to put resulting html files.
$kanjifile = "";		# Filename of kanji to flash (if any).
$rcfile = "";			# Name of rc file use when executing lookup.
$resultfile = "";		# Name of log file to use with lookup.
$crapfile = "";			# Name of temporary file.
$verbose = 1;			# Verbosity of flashkanji (0 == quiet).
$henshall = 0;			# Are we using Henshall indexes?
$frequency = 0;			# Are we using Frequency indexes?
$range_min = -1;		# Minimum index number in kanji set (if any).
$range_max = -1;		# Maximum index number in kanji set (if any).
$strict = 0;			# Are compound kanji only taken from kanji set?
$forward = 0;			# Is forward referencing in compounds allowed?
$any = 0;			# No restrictions on kanji character compounds?
$disallow_hiragana = 0;		# Are hiragana disallowed in compounds?

## Index numbers taken from "A Guide to Remembering Japanese Characters" by
## Kenneth G. Henshall for determining grade 1-6 kanji characters.
##
@henshall_grades = (1, 77, 222, 417, 612, 807, 997);

## Array recording kanji set we are "flashing" over.
##
@KANJI = ();

## Kanji that may be used in generating compounds.  For example, when flashing
## grade 2 kanji, grade 1 kanji may also be used when generating compounds.
##
@KNOWLEDGE = ();

$max_kanji = 7000;		# Upper bound on number of kanji.

&process_command_options();	# Parse command line options.
&check_compatible_options();	# Ensure options used are compatible.
&make_kanji_and_knowledge_sets(); # Set KANJI and KNOWLEDGE arrays.
&get_kanji_matches();		# Get all the useful data using lookup.

## Generate the html files using the data from the lookup logging file.
##
&generate_html_files($directory, $limit, 
		     $random_compounds, $resultfile, 
		     $reverse_test);

## This function parses those switches in ARGV and sets the appropriate
## variables.
##
sub process_command_options {
    local($i);
    srand();			# For random number generators.
    for ($i = 0; $i <= $#ARGV; ) {
	if ($ARGV[$i] eq "-kanji" && $i < $#ARGV) {
	    &usage if ($grade != -1);
	    $kanjifile = $ARGV[$i+1]; 
	    $i+=2;
	} elsif ($ARGV[$i] eq "-henshall") {
	    $henshall = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-frequency") {
	    $frequency = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-strict") {
	    $strict = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-forward") {
	    $forward = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-any") {
	    $any = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-range" && $i < $#ARGV) {
	    if ($ARGV[$i+1] =~ /(\d+):(\d+)/) {
		$range_min = $1;
		$range_max = $2;
		if ($range_min > $range_max || $range_min < 1 || 
		    $range_max > $max_kanji) {
		    print STDERR "error: invalid -range argument\n";
		    &usage;
		}
	    } elsif ($ARGV[$i+1] =~ /G(\d+)/) {
		$grade = $1;
		if ($grade < 1 || $grade > 6) {
		    print STDERR "error: Invalid grade \"$grade\"",
		                 "(must be between 1 and 6)\n";
		    &usage;
		}
	    } else {
		print STDERR "error: Invalid range argument \"$ARGV[$i+1]\"\n";
		&usage;
	    }
	    $i+=2;
	} elsif ($ARGV[$i] eq "-limit" && $i < $#ARGV) {
	    &usage if ($ARGV[$i+1] < 0);
	    $limit = $ARGV[$i+1];
	    $i+=2;
	} elsif ($ARGV[$i] eq "-directory" && $i < $#ARGV) {
	    $directory = $ARGV[$i+1];
	    $i+=2;
	} elsif ($ARGV[$i] eq "-randomcompounds") {
	    $random_compounds = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-randomorder") {
	    $random_order = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-reversetest") {
	    $reverse_test = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-disallowhiragana") {
	    $disallow_hiragana = 1;
	    $i++;
	} elsif ($ARGV[$i] eq "-quiet") {
	    $verbose = 0;
	    $i++;
	} else {
	    print STDERR "error: unrecognized argument \"$ARGV[$i]\"\n";
	    &usage;
	}
    }
}

## This function checks that the command options set are compatible with
## each other.  It also ensures that the dictionaries and support programs
## are accessible.
##
sub check_compatible_options {
    if ($directory eq "") {
	print STDERR "error: must specify -directory option\n";
    }
    if ($henshall == 0 && $frequency == 0 && $kanjifile eq "") {
	print STDERR 
	    "error: must specify either -henshall, -frequency or -kanji\n";
	&usage;
    }
    if ($forward == 1 && $any == 1) {
	print STDERR
	    "error: cannot specify both -forward and -any\n";
	&usage;
    }
    if ($kanjifile ne "" && $strict==0 && $henshall == 0 && $frequency == 0) {
	print STDERR "error: must specify either -henshall or -frequency if ",
	             "-strict is not used\n";
	&usage;
    }
    if ($kanjifile eq "" && ($range_min == -1 && $grade == -1)) {
	print STDERR "error: please specify -range argument\n";
	&usage;
    }
    if ($grade != -1 && $frequency) {
	print STDERR "error: grade argument incompatible with -frequency\n";
	&usage;
    }
    (-e $edict)||die "error: edict file \"$edict\" does not exist\n";
    (-r $edict)||die "error: edict file \"$edict\" is not readable\n";
    (-e $kanjidic)||die "error: kanjidic file \"$kanjidic\" does not exist\n";
    (-r $kanjidic)||die "error: kanjidic file \"$kanjidic\" is not readable\n";
    (-e $lookup)||die "error: \$lookup value \"$lookup\" does not exist\n";
    (-x $lookup)||die "error: \"$lookup\" is not executable\n";
    (-e $jconv)||die "error: \$jconv value \"$jconv\" does not exist\n";
    (-x $jconv)||die "error: \"$jconv\" is not executable\n";
    if (! (-e $directory)) {
	print "Creating directory \"$directory\"\n";
	mkdir($directory,0755) || 
	    die "error: failed to create directory \"$directory\": $!\n";
    }
    $rcfile = "$directory/rcfile.tmp";
    $resultfile = "$directory/result.tmp";
    $crapfile = "$directory/crap.tmp";
}

## This function will initialise the KANJI and KNOWLEDGE arrays appropriately.
## 
sub make_kanji_and_knowledge_sets {
    if ($kanjifile ne "") {

	## Read kanji set from file and put into KANJI.
	##
	print "Making kanji array from file \"$kanjifile\".\n" if ($verbose);
	&make_kanji_from_file($kanjifile, *KANJI);

	## If strict is not set, set KNOWLEDGE to all kanji which have an
	## index less than the lowest index value specified in the kanji set.
	## These kanji should be known to the "flashee".
	##
	if ($strict == 0) {
	    print "Generating pre-requisite kanji array.\n" if ($verbose);
	    &make_knowledge_from_kanji(*KANJI, *KNOWLEDGE);
	}
    } else {

	## Kanji set specified as an index range.  If grade number specified,
	## determine index numbers from @hensgall_grades array.
	##
	if ($grade != -1) {
	    $range_min = $henshall_grades[$grade-1];
	    $range_max = $henshall_grades[$grade]-1;
	}
	if ($verbose) {
	    print "Generating kanji array using ",
	        ($henshall ? "Henshall" : "Frequency"), " indexing, minimum ",
	        $range_min, " maximum ", $range_max, "\n";
	}

	## Make the kanji set from this range, and set the KNOWLEDGE array
	## as above if we are not strict.
	##
	&make_kanji_from_range($range_min, $range_max, *KANJI);
	if ($strict == 0) {
	    print "Generating pre-requisite kanji array.\n" if ($verbose);
	        &make_kanji_from_range(1, $range_min-1, *KNOWLEDGE);
	}
    }
}

# This function reads a list of kanji in a file (one per line) and initialises
# the kanji array from them.
#
sub make_kanji_from_file {
    local($kfile, *kanji) = @_;
    local($i);

    (-e $kfile) || die "error: kanji file \"$kfile\" does not exist\n";
    (-r $kfile) || die "error: kanji file \"$kfile\" is not readable\n";
    open(KFILE,$kfile) || die "error: failed to open \"$kfile\": $!\n";
    for ($i = 0; <KFILE>; ) {
	if (! (/^\s*#/ || /^\s*$/) ) { 
	    if (/^\s*(.*)\s*$/) {
	        $kanji[$i++] = $1;
	    } else {
		print "Couldn't parse line \"$_\"\n";
		exit 1;
	    }
        }
    }
    close KFILE;
}
	
## This function will initialise the kanji array from a range specification.
## 
sub make_kanji_from_range {
    local($min, $max, *kanji) = @_;
    local($j, $regexp, $prefix);

    return if ($max < $min);
    $prefix = ($henshall == 1) ? "E" : "F";

    ## Generate the appropriate range expression so that the desired kanji
    ## can be extracted quickly.
    ##
    $regexp = &regexp_up($min, length($max), $prefix);
    $regexp = "(" . $regexp . ")||(" . 
	&regexp_down($max, length($min), $prefix) . ")";

#    print "regexp is \"$regexp\"\n";
    
    ## Generate the lookup rcfile.
    ##
    open(RC,">$rcfile") || die "error: failed to open \"$rcfile\": $!\n";
    print RC "verbose off\n";
    print RC "load \"$kanjidic\"\n";
    print RC "select 0\n";
    print RC "fold off\n";
    print RC "limit 7000\n";
    print RC "log to \"$resultfile\"\n\n";
    print RC "!$regexp\n";
    print RC "log off\n";
    print RC "exit\n";
    close RC;
    `echo \" exit\" | $lookup -rc $rcfile 2>&1 > $crapfile`;
    unlink("$rcfile");
    unlink("$crapfile");

    ## Read the lookup log file and initialise the kanji array.
    ##
    open (RESULT,"$resultfile") || die "Failed to open \"$resultfile\": $!\n";
    while (<RESULT>) {
	if (! (/^\[read/ || /^\s+$/ ) ) {
	    if (/^(.+)\s[0-9a-z].*\s$prefix(\d+)\s/) {
		$kanji[$2 - $min] = $1;
	    }
	}
    }
}

## This function will intialise the knowledge array using the kanji array.
## It will determine what the minimum indexed kanji is in the kanji array
## by using lookup, and will then get the list of those kanji which are
## indexed before this minimum value and put them into @knowledge.
##
sub make_knowledge_from_kanji {
    local(*kanji, *knowledge) = @_;
    local($j, $regexp, $prefix, $minimum);

    ## Create regular expression for list of kanji being used.
    ##
    for ($regexp = "(^$kanji[0])", $j = 1; $j <= $#kanji; $j++) {
	$regexp = "$regexp|(^$kanji[$j])";
    }

    ## Create lookup rcfile.
    ##
    open(RC,">$rcfile") || die "error: failed to open \"$rcfile\": $!\n";
    print RC "verbose off\n";
    print RC "load \"$kanjidic\"\n";
    print RC "select 0\n";
    print RC "fold off\n";
    print RC "limit $max_kanji\n";
    print RC "log to \"$resultfile\"\n\n";
    print RC "!$regexp\n";
    print RC "log off\n";
    print RC "exit\n";
    close RC;

    ## Make sure the file is in euc format.
    ##
    &make_file_euc("$rcfile");
    `echo \" exit\" | $lookup -rc $rcfile 2>&1 > $crapfile`;
    unlink("$rcfile");
    unlink("$crapfile");

    ## Extract the results from the lookup logging file, and then create
    ## the knowledge array from the indexing range that has been calculated.
    ##
    open (RESULT,"$resultfile") || die "Failed to open \"$resultfile\": $!\n";
    $minimum = $max_kanji;
    $prefix = ($henshall == 1) ? "E" : "F";
    while (<RESULT>) {
	if (! (/^\[read/ || /^\s+$/ ) ) {
	    if (/^.+\s[0-9a-z].*\s$prefix(\d+)\s/) {
		$minimum = $1 if ($1 < $minimum);
	    }
	}
    }
    close RESULT;
    unlink("$resultfile");
    if ($verbose) {
	print "Constructing pre-requisite kanji min 1 max ", $minimum-1, ".\n";
    }
    &make_kanji_from_range(1, $minimum-1, *knowledge);
}
   
## Simple routine which uses the jconv program to convert a file into euc
## format.
##
sub make_file_euc {
    local($filename) = @_;
    `$jconv -oe $filename $filename.tmp`;
    rename("$filename.tmp", "$filename");
}    

## Routine to create a regular expression from the number $value up to
## a maximum number with $limit digits.  The $prefix string is appended
## to each sub regexp generated.
##
sub regexp_up {
    local($value, $limit, $prefix) = @_;
    local($limit_minus_one) = $limit-1;
    local($regexp, $tmp);
    while (! ($value =~ /^\[\d-\d\](\[\d-\d\]){$limit_minus_one}/) ) {
	if ($value =~ /^(.*)(\d)$/) {
	    $value = "$1\[$2-9\]";
	    $regexp = "(\\s$prefix$value\\s)";
	} elsif ($value =~ /^(.*)(\d)\[\d(.*)$/) {
	    if ($2 == 9) {
		$value = "$1\[9-9\]\[9$3";
	    } else {
		$tmp = $2+1;
		$value =~ s/\[9-9\]/\[0-9\]/g;
		$value =~ /^(.*)(\d)\[\d(.*)$/;
		$value = "$1\[$tmp-9\]\[0$3";
	    }
	    $regexp = "$regexp|(\\s$prefix$value\\s)";
	} elsif ($value =~ /^\[\d-9\](.*)$/) {
	    $value = "\[1-9\]\[0-9\]$1";
	    $value =~ s/\[9-9\]/\[0-9\]/g;
	    $regexp = "$regexp|(\\s$prefix$value\\s)";
	}
    }
    $regexp;
}

## Routine to create a regular expression from the number $value down to
## a minimum number with $limit digits.  The $prefix string is appended
## to each sub-regexp generated.
##
sub regexp_down {
    local($value, $limit) = @_;
    local($limit_minus_one) = $limit-1;
    local($regexp, $tmpstr, $header, $tmp);

    while (! ($value =~ /^\[\d-\d\](\[\d-\d\]){$limit_minus_one}$/) ) {
	if ($value =~ /^(.*)(\d)$/) {
	    $value = "$1\[0-$2\]";
	    $regexp = "(\\s$prefix$value\\s)";
	} elsif ($value =~ /^(\d)\[(\d)-(\d)\](.*)$/) {
	    if ($1 == 1) {
		$value = "\[1-1\]\[$2-$3\]$4";
	    } else {
		$tmp = $1-1;
		$tmpstr = $4;
		$tmpstr =~ s/\[\d-\d\]/\[0-9\]/g;
		$value = "\[1-$tmp\]\[0-9\]$tmpstr";
	    }
	    $regexp = "$regexp|(\\s$prefix$value\\s)";
	} elsif ($value =~ /^(.*)(\d)\[(\d)-(\d)\](.*)$/) {
	    if ($2 == 0) {
		$value = "$1\[0-0\]\[$3-$4\]$5";
	    } else {
		$tmp = $2-1;
		$header = $1;
		$tmpstr = $5;
		$tmpstr =~ s/\[\d-\d\]/\[0-9\]/g;		
		$value = "$header\[0-$tmp\]\[0-9\]$tmpstr";
	    }
	    $regexp = "$regexp|(\\s$prefix$value\\s)";
	} elsif ($value =~ /^\[\d-\d\]\[\d-\d\](.*)/) {
	    $value = $1;
	    $value =~ s/\[\d-\d\]/\[0-9\]/g;
	    $value = "\[1-9\]$value";
	    $regexp = "$regexp|(\\s$prefix$value\\s)";
	}
    }
    $regexp;
}

## This function will given the KANJI and KNOWLEDGE arrays, generate an
## appropriate rcfile for the lookup command, and invoke lookup.  $resultfile
## will record all the useful data that will be used for generating the
## html files.
##
sub get_kanji_matches {
    local($search) = "";

    ## Create the $search regular expression for all kanji that should already
    ## be known (if we aren't strict).
    ##
    if ($strict == 0) {
	for ($i = 0; $i <= $#KNOWLEDGE; $i++) {
	    if ($i == 0) {
		$search = "$KNOWLEDGE[$i]";
	    } else {
		$search = "$KNOWLEDGE[$i]|$search";
	    }
	}
    }

    print "Creating lookup rcfile.\n" if ($verbose);
    open(RC,">$rcfile") || die "error: failed to open \"$rcfile\": $!\n";
    print RC "verbose off\n";
    print RC "load \"$edict\"\n";
    print RC "load \"$kanjidic\"\n";
    print RC "select 1\n";
    print RC "fold off\n";

    ## Pattern to make entries out of kanjidic more readable to the end user.
    ##
    print RC "modify /^(\\c).+(S\\d+)(\\w|\\s|\\.|\\-|\\:)+(\\h|\\k)",
        "((\\h|\\k|\\s|\\.|\\-|\\:)+)(T1(\\h|\\k|\\s)+)?(T2(\\h|\\k|\\s)+)?/",
        "\\1 \\2 \\4\\5/\n";
    print RC "modify 1\n";
    print RC "select 0\n";
    print RC "fold off\n";
    print RC "log to \"$resultfile\"\n";

    ## Mix up the order of elements in @KANJI if -randomorder was specified.
    ##
    if ($random_order) {
	local ($element1, $element2, $size, $tmp);
	$size = $#KANJI;
	for ($i = 0; $i < $size*100; $i++) {
	    $element1 = rand($size);
	    $element2 = rand($size);
	    $tmp = $KANJI[$element1];
	    $KANJI[$element1] = $KANJI[$element2];
	    $KANJI[$element2] = $tmp;
	}
    }

    ## If forward references are allowed, set the $search regular expression
    ## to contain everything in the @KANJI set immediately.
    ##
    if ($forward) {
	for ($i = 0; $i <= $#KANJI; $i++) {
	    $search = ($search eq "") ? $KANJI[$i] : "$search|$KANJI[$i]";
	}
    } elsif ($any) {
	$search = "\\c";
    }

    ## Generate the appropriate regular expressions, with preference given
    ## to kanji compounds, and then compounds which contain hiragana in them.
    ##
    if ($search eq "") {
	print RC "msg ## query 0\n";
	print RC "!(^<$KANJI[0]>),1\n";
	print RC "!(^<$KANJI[0]($KANJI[0]|\\h)+>)\n";
	print RC "!(^<(\\h)+$KANJI[0]($KANJI[0]|\\h)*>)\n";
	$search = "$KANJI[0]";
	$i = 1;
    } else {
	$i = 0;
    }
    for (; $i <= $#KANJI; $i++) {
	print RC "msg ## query $i\n";
	print RC "!(^<$KANJI[$i]>),1\n";
	print RC "!(^<$KANJI[$i]($KANJI[$i]|$search)+>)|",
	    "(^<($search)+$KANJI[$i]($KANJI[$i]|$search)*>)\n";
	if ($disallow_hiragana == 0) {
	    print RC "!(^<$KANJI[$i]($KANJI[$i]|$search)*",
	        "\\h($KANJI[$i]|\\h|$search)*>)|",
	        "(^<($search)+$KANJI[$i]\\h($KANJI[$i]|\\h|$search)*>)\n";
	}
	if ($forward == 0 && $any == 0) {
	    $search = "$KANJI[$i]|$search" if ($i != $#KANJI);
	}
    }
    print RC "msg ## finished\n";
    print RC "log off\n";
    print RC "exit\n";
    close RC;

    &make_file_euc("$rcfile");
    print "Invoking lookup.\n" if ($verbose);
    `echo \" exit\" | $lookup -rc $rcfile 2>&1 > $crapfile`;
    unlink("$rcfile");
    unlink("$crapfile");
}

## This function will generate a list of html files into the directory
## $dir.  The $file variable contains the filename of a lookup logging
## file which contains all the information required.
##
sub generate_html_files {
    local($dir, $max, $random, $file, $reverse) = @_;
    local($i, $j, $kanjiline, $element1, $element2, $tmp, @compound);
    local($kanji, $line);

    print "Generating HTML files.\n" if ($verbose);

    ## Create the initial "kanji.html" file.
    ##
    open(FILE, $file) || die "error: failed to open file \"$file\": $!\n";
    open(START, ">$dir/kanji.html") ||
	die "error: failed to create file \"$dir/kanji.html\": $!\n";
    print START "$html_prologue\n";
    print START "<title>flashkanji</title>\n";
    print START "<img src=\"title.gif\" width=336 height=48> <p> <hr> <p>\n";
    print START "The <em>flashkanji</em> homepage is accessible from ",
              "<a href=http://cap.anu.edu.au/~sits/flashkanji>here</a>.\n";
    print START
	"Please feel free to send me any comments or suggestions. <p>\n";
    print START "<a href=\"hd0.html\">Click here to start</a> <p> <hr> \n";
    print START "<em>$created <br> $copyright</em>\n";
    close START;
    `cp $titlegif $dir`;

    $line = <FILE>;
    chop($line);
    for ($i = 0; (! ($line =~ /^## finished/) ); $i++) {
        $size = 0;
        $tmp = $i+1;
	if ($line =~ /^## query $i/) {

	    ## Handle results for kanji $i.
	    ##
	    $line = <FILE>;
	    while ($line =~ /\[read/) {
		$line = <FILE>;
	    }
	    chop ($line);

	    ## Grab the kanjidic line and make it more readable.
	    ##
	    $kanjiline = $line;
	    $kanjiline =~ s/(S\d+)\s/$1 \[/;
	    $kanjiline =~ s/\s([^S\w\{\[])/\] \[$1/g;
	    $kanjiline =~ s/\s\{/\] \{/;

	    ## Grab the compound lines and save them.
	    ##
	    while ($line = <FILE>) {
		chop ($line);
		if ($line =~ /^## /) {
		    last;
		} elsif ($line =~ /\[read/) {
		    next;
		} else {
		    $compound[$size++] = $line;
		}
	    }
	} else {
	    die "Unmatched line \n\"$line\"\n";
	}

        ## If -randomcompounds has been set, then suffle the order of the
	## compounds array.
        ## 		     
	if ($random) {
	    for ($j = 0; $j < $size*100; $j++) {
		$element1 = rand($size);
		$element2 = rand($size);
		$tmp = $compound[$element1];
		$compound[$element1] = $compound[$element2];
		$compound[$element2] = $tmp;
	    }
	}

        ## Generate a page with no expansions, where the kanji definition
	## has been expanded, and where each compound in turn is expanded,
	## all linked appropriately.
        ##
	$size = $limit if ($limit != -1 && $limit < $size);
        &generate_page("$dir", -1, $i, *compound, $size, $kanjiline, $reverse);
        &generate_page("$dir", $size, $i, *compound, $size, $kanjiline,
		       $reverse);
        for ($j = 0; $j < $size; $j++) {
	    &generate_page("$dir", $j, $i, *compound, $size, $kanjiline,
			   $reverse);
	}
    }
    close FILE;
    unlink("$file");

    ## Create the final html page.
    ##		  
    open(FINISH, ">$dir/hd$i.html") ||
        die "error: failed to create file \"$dir/hd$i.html\": $!\n";
    print FINISH "$html_prologue\n";
    print FINISH "<title>flashkanji</title>\n";
    print FINISH "<img src=\"title.gif\" width=336 height=48> <p> <hr> <p>\n";
    print FINISH "<big>Finished!</big> <p>\n";
    print FINISH "Click <a href=\"kanji.html\">here</a> ",
		  "to return to the start.\n <p> <hr> \n";
    print FINISH "<em>$created <br> $copyright</em>\n";
    close FINISH;
}

## generate_page will generate an HTML file with the appropriate content 
## and links.
##
## $kanjiline contains a modified entry of the kanji which is being
## "flashed" taken from the kanjidic file.
## @compound is an array which contains a list of compounds which contains
## the kanji being studied.
## $index indicates which entry is to be expanded in this page.  A value
## of -1 indicates no entry, 0 to $size-1 indicates an index into the
## @compound array, and $size indicates the full $kanjiline itself.
## Non-expanded entries will just display the kanji, not the translation or
## readings, but will have links to a page which expands that entry.
## $entry indicates the flashcard number being processed.  $dir is the
## directory where the file will be created.
##
sub generate_page {
    local($dir, $index, $entry, *compound, $size, $kanjiline, $reverse) = @_;
    local($i, $tmp, $filename);

    if ($index == -1) {
	$filename = "hd$entry.html";
    } else {
	$filename = "tl$entry.html";
    }
    if ($index == -1) {
	open(HTML, ">$dir/$filename") ||
	    die "error: failed to create file \"$filename\": $!\n";
    } else {
	open(HTML, ">$dir/$index$filename") ||
	    die "error: failed to create file \"$index$filename\": $!\n";
    }

    $tmp = $entry + 1;
    print HTML "<title>Flashcard $tmp</title>\n";

    ## Process the kanji line.
    ##
    $kanjiline =~ /^(.*)(\sS.*)$/;
    if ($index == $size) {
	print HTML "<big>$1</big> $2\n <p> <hr> <p>\n";
    } else {
	print HTML "<a href=\"${size}tl${entry}.html\">";
	if ($reverse) {
	    print HTML ".. </a>$2\n";
	} else {
	    print HTML ".. </a><big>$1</big>\n";
	}
	print HTML "<p> <hr> <p>\n";
    }

    ## Process the compound lines (with any necessary expansions).
    ##
    for ($i = 0; $i < $size; $i++) {
	if ($index == $i) {
	    print HTML ".. $compound[$i] <br>\n";
	} else {
	    $compound[$i] =~ /^(.*)\s(\[.*)$/;
	    print HTML "<a href=\"${i}tl${entry}.html\">";
	    if ($reverse) {
		print HTML ".. </a>$2 <br>\n";
	    } else {
		print HTML ".. </a>$1 <br>\n";
	    }
	}
    }
    print HTML "<p> <hr> <p>\n" if ($size > 0);
    $tmp = $entry+1;
    print HTML "<a href=\"hd$tmp.html\">Next flashcard</a>\n";
    close HTML;
}

sub usage {
    print "usage: flashkanji ";
    print "((-henshall|-frequency) -range (num:num|Gnum) [-strict] |\n";
    print "                   (-henshall|-frequency|-strict) -kanji <file>)\n",
          "                   -directory <dir> [-limit <num>] ",
          "[-randomcompounds]\n";
    print "                  [-randomorder] [-forward|-any] [-reversetest]\n",
          "                  [-disallowhiragana] [-quiet]\n\n";
    print " -henshall           :: index kanji by Henshall numbers\n";
    print " -frequency          :: index kanji by frequency numbers\n";
    print " -range num:num|Gnum :: numerical index range or grade number\n";
    print " -kanji <file>       :: kanji file to be flashed\n";
    print " -strict             :: only use range of kanji specified for",
    "compounds\n";
    print " -directory <dir>    :: directory to put HTML files\n";
    print " -limit <num>        :: maximum number of compounds to output\n";
    print " -randomcompounds    :: randomise which compounds to use\n";
    print " -randomorder        :: randomise order of kanji set\n";
    print " -reversetest        :: flash meanings insted of kanji\n";
    print " -forward            :: allow forward references in kanji set\n";
    print " -any                :: allow use of any kanji for compounds\n";
    print " -disallowhiragana   :: disallow hiragana in compounds\n";
    print " -quiet              :: run silently\n";
    exit 1;
}


