#!/usr/bin/perl
#
# Puz2Java version 1.2.1
#

use strict;

# locate the .puz file
my $file = $ARGV[0];

# Take the file and remove its extension to make the class name
# Note: the file name will include directory data
my $name = $file;
$name =~ s/\.[^.]*$//;
my $dir = $name;
$dir =~ s/\/[^\/]*$//;
if ($name =~ /\/([^\/]*)$/) {$name = $1;}
# Replace all spaces with underscores
$name =~ s/ /\_/g;
# Remove all "bad" characters.
$name =~ s/[^A-Za-z0-9\_\-]/\_/g;
# If the first character is a number, replace it.
if ($name =~ /^[0-9]/) {$name = "A$name";}
my $output = "$dir\/$name\.java";

print "Puz2Java for Mac version 1.2.1\n";
print "2009 Alex Boisvert\n";
print "http://www.alexboisvert.com\n\n";
print "Creating $name\.java ...\n";

# read in the .puz file
my $data;
open (my $fh, $file);
{ local $/;
  $data = <$fh>;
}
close $fh;

# Let's make sure it's actually an Across Lite file.
if ($data !~ /ACROSS&DOWN/) {
	print "Error: the file you are trying to convert is not an Across Lite binary file.\n";
	print "Typically, these files end with a file extension of .puz.\n";
	print "Find a way to convert your file to a .puz file and try again.\n";
	sleep(20);
	exit(0);
}

# get the size of the grid
my ($w, $h) = unpack("CC", substr($data, 0x2C, 2));
my $maxwords = ($w*$h - ($w*$h % 3))/3 + 5;

# fill in data structures from the file

# First, the answers (which may be scrambled).
my $answerstring = substr($data, 0x34, $w*$h);
my @answergrid; # 2d array
for my $i (0..$h-1){
  # $i = the number of this row
  $answergrid[$i] = [split(//, substr($answerstring, $i*$w, $w))];
}


# Then, the black/white grid pattern.
my $bwstring = substr($data, 0x34+$w*$h, $w*$h);
my @bwgrid; # 2d array to store black vs white squares
for my $i (0..$h-1){
  # $i = the number of this row
  $bwgrid[$i] = [split(//, substr($bwstring, $i*$w, $w))];
}


# Next, the list of clues not yet numbered.
my $cluestring = substr($data, 0x34+$w*$h+$w*$h); 
# the list of clues contains a few lines of footer material, to be
# dealt with later.
my @newclues = split(/\0/, $cluestring);
# it also contains a few lines at the beginning. 
# There are three such lines -- Title, Author, Copyright.
my @header_lines;
for my $k (1..3){
  push(@header_lines, shift(@newclues));
}

# Let's name these $title, $author, $copyright

my $title = no_quote(shift(@header_lines));
my $author = no_quote(shift(@header_lines));
my $copyright = no_quote(shift(@header_lines));


# Here we check to see if the crossword has circles in it.  This is marked
# in the PUZ file by a GEXT?.  Should be easy to find.
# circleGrid will have a chr(128) whenever there's a circle, and a
# chr(0) when there is not one.
my @circleGrid;
my $tot = $w*$h;
my $tot1 = $tot-1;
my $circleIndex = -1;
my $c128 = chr(128);
my $c0 = chr(0);
# This checks for circles
if ($cluestring =~ /GEXT.*?([$c0$c128]{$tot})/) {
	my $circleString = $1;
	$circleIndex = 1;
	for my $i (0..$h-1){
    	# $i = the number of this row
    	$circleGrid[$i] = [split(//, substr($circleString, $i*$w, $w))];
  	}
}

# All right! Let's go!
my @numgrid; # 2d array to store clue number positions
# we are going to make sure we are copying the data!
for my $i (0..$#bwgrid){
  for my $j (0..$#{$bwgrid[$i]}){
    $numgrid[$i]->[$j] = $bwgrid[$i]->[$j];
  }
}

# Find the first non-black square: applet needs to start there.
my $startX=0;
while ($bwgrid[0][$startX] eq ".") {
	$startX++;
}
my @acrosstemp; # list of across clues with numbers
my @downtemp; # list of down clues with numbers

# The most pressing issue now is to figure out the numbers and assign
# them to the grid and the clues.

# Black squares will be filled with -1's. We'll have an extra row on
# the top, and column on the left, filled with -1's.

unshift (@bwgrid, [(".") x $w]);
unshift (@$_, ".") for @bwgrid;

unshift (@numgrid, [(-1) x $w]);
unshift (@$_, -1) for @numgrid;

my $c;
for my $i (1..$h) {
  
  for my $j (1..$w) {
    # this square is $bwgrid[$i]->[$j]

    # add any needed -1's for future iterations
    if ($bwgrid[$i]->[$j] eq '.'){
	    $numgrid[$i]->[$j] = -1;
    } # end if

    next if $bwgrid[$i]->[$j] eq ".";


    # if a square has a -1 to its left or top (but not right or down), 
    # it's a clue. Let's allocate a number for it.
    if (($bwgrid[$i][$j-1] eq "." && $bwgrid[$i][$j+1] ne "." && $j != $w) || 
        ($bwgrid[$i-1][$j] eq "." && $bwgrid[$i+1][$j] ne "." && $i != $h)) {
      $c++;
      $numgrid[$i]->[$j] = $c;
    } # end if
    else {$numgrid[$i]->[$j] = "00";}

	# We also make temporary arrays with across and down answers
	# We'll have to make them better later.

    # across clue (-1 to its left but not right)
    if ($bwgrid[$i][$j-1] eq "." && $bwgrid[$i][$j+1] ne "." && $j != $w){ 
      push(@acrosstemp, shift(@newclues)) 
    } # end if

    # down clue (-1 above it but not below)
    if ($bwgrid[$i-1][$j] eq "." && $bwgrid[$i+1][$j] ne "." && $i != $h){ 
      push(@downtemp, shift(@newclues)) 
    } # end if
  } # end $j
} # end $i

# Now we make more stuff for the applet.  
# We make the "good" clue grids, for one.
# We also make acrossarray, downarray, which are used in the clue lists.
# Finally, we make acrossenterarray and downenterarray, 
# helpful when the user presses the "enter" key.

my $at = 0;
my $dt = 0;
my $num = 1;
my $lastX;
my $lastY;
my $lastAcross=0;
my $lastDown = 0;
my @acrossEnterArray;
my @downEnterArray;
my @across;
my @down;
my @acrossArray;
my @downArray;
for my $i (1..$h) { 
  for my $j (1..$w) {
    # this square is $numgrid[$i]->[$j]
    if ($numgrid[$i]->[$j] == $num) {	# found a number in the grid
    	if ($bwgrid[$i][$j-1] eq "." && $bwgrid[$i][$j+1] ne "." && $j != $w) {	# Across clue
    		$across[$num] = no_quote($acrosstemp[$at]);	# Build the good across array
    		$acrossArray[$at]->[0] = $j-1;
    		$acrossArray[$at]->[1] = $i-1;	# Build acrossArray
    		$at++;
    		
    		if ($num == 1) {
    			$lastX = $j-1;
    			$lastY = $i-1;
    		} # end if num == 1
    		else {
    			$acrossEnterArray[$lastAcross]->[0] = $j-1;
    			$acrossEnterArray[$lastAcross]->[1] = $i-1;
    		} # end else
    		$lastAcross = $num;
    	} # end Across clue
    	
    	if ($bwgrid[$i-1][$j] eq "." && $bwgrid[$i+1][$j] ne "." && $i != $h) {	# Found a down clue; repeat the process
    		$down[$num] = no_quote($downtemp[$dt]);	# Build the good down array
    		$downArray[$dt]->[0] = $j-1;
    		$downArray[$dt]->[1] = $i-1;	# Build downArray
    		$dt++;
    		
    		if ($num != 1) {
    			$downEnterArray[$lastDown]->[0] = $j-1;
    			$downEnterArray[$lastDown]->[1] = $i-1;
    		}
    		$lastDown = $num;
    	} # end 'Found a down clue'
    	$num++;
    } # end 'found a number'
   } # end $j
 } # end $i
 
$acrossEnterArray[$lastAcross]->[0] = $lastX;
$acrossEnterArray[$lastAcross]->[1] = $lastY;
$downEnterArray[$lastDown]->[0] = $lastX;
$downEnterArray[$lastDown]->[1] = $lastY;

# Since perl doesn't zero-initialize arrays, we need to fill in the gaps in 
# our two arrays.

for my $i (0..$#acrossEnterArray) {
	for my $j (0..1) {
		if ($acrossEnterArray[$i]->[$j] eq "") {
			$acrossEnterArray[$i]->[$j] = 0;
		} # end if
	} # end $j
} # end $i

for my $i (0..$#downEnterArray) {
	for my $j (0..1) {
		if ($downEnterArray[$i]->[$j] eq "") {
			$downEnterArray[$i]->[$j] = 0;
		} # end if
	} # end $j
} # end $i
 
# Just a few more variables to define before creating the java file.  
# These deal with the size of the applet.

my $blockSize = 25;
my $numSize = 9;
my $ansSize = 16;
my $marginTop = 10;
my $marginLeft = 4;

if ($h > 17) {	# We want the applet smaller for Sunday puzzles
	$blockSize = 21;
	$numSize = 7;
	$ansSize = 12;
	$marginTop = 7;
	$marginLeft = 2;
}

# We deduce the size of the applet from the above information
my $appWidth = $blockSize*$w + 230;
my $appHeight = $blockSize*$h + 150;

# One last thing to do -- find a value for the number of
# visible rows in the across and down clues.
my $tmp = to_html($across[1]);
my $tmpsz = 1; $tmpsz++ while $tmp =~ /\<p\>/g;
my $acrossRows = (18 - (18 % $tmpsz))/$tmpsz;
$tmp = to_html($down[1]);
my $tmpsz = 1; $tmpsz++ while $tmp =~ /\<p\>/g;
my $downRows = (18 - (18 % $tmpsz))/$tmpsz;

# Now it's time to output the Java file and pray that it works.

open JAVA, ">$output" or die "Can't write to $output";

print JAVA <<EOPS;
//-------------------------------------------------------
//
// Written by Carl Haynes
//
// Submitted to Sun Microsystems for their
// java.applet.Applet Contest 8/31/95
//
// Modified by Alex Boisvert 2007-2009
// To use this file: you will first need to compile it.
// You may use the compiler available online at
// http://www.innovation.ch/java/java_compile.htm
// Once you have done that, you will get an output file
// named $name.class.  Put that on your server
// and add the following code to an HTML document:
//
// <applet code=$name.class width=$appWidth height=$appHeight></applet>
//--------------------------------------------------------

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;

public class $name extends java.applet.Applet implements ActionListener, ListSelectionListener {
    final	static	int	kAppWidth 	= $appWidth;
    final	static	int	kAppHeight 	= $appHeight;

    final	static	int	kBlockWidth	= $blockSize;
    final	static	int	kBlockHeight	= $blockSize;

    final	static	int	kBlocksWide	= $w;
    final	static	int	kBlocksHigh	= $h;
    final 	static	int	kButtonWidth	= 100;
    final 	static	int	kButtonHeight	= 25;

    final	static	int	kUp = 0;
    final	static	int	kDown = 1;

    final static 	int kAcross = 0;

    final static int kPaddingTop =	40;
    final static int kPaddingLeft = 5;
    final static int kPaddingClues = 15;
    final static int kQuestionAreaHeight = 40;

    int gDirection = kAcross;
    int gCurX	= $startX;
    int	gCurY	= 0;

    int		clipLeft = -1;
    int		clipTop = -1;
    int		clipWidth = -1;
    int 		clipHeight = -1;

    int		gBlockMinY	= 0;
    int		gBlockMaxY 	= 0;
    int		gBlockMinX = 0;
    int		gBlockMaxX	= 0;

    int		gOldBlockMinY	= 0;
    int		gOldBlockMaxY 	= 0;
    int		gOldBlockMinX = 0;
    int		gOldBlockMaxX	= 0;
    
    Button RevealAll;
    Button RevealWord;
    Button CheckAll;
    Button CheckWord;

    JList AcrossList;
    JList DownList;
      
	private JTextField AcrossText;
	private JTextField DownText;
	private JTextField titleText;
	private JTextField authorText;
	private JTextArea copyrightText;


     String	letters[] = {	"A", "B", "C", "D", "E",  
 "F", "G", "H", "I", "J", "K", "L", "M", 
"N", "O", "P", "Q", "R", "S", "T", 
"U", "V", "W", "X", "Y", "Z"}; 
  
     /*---------------------------------------------------------------*/ 
     /*---------------------------------------------------------------*/ 

  
	final static String author = "$author";
	final static String title = "$title";
	final static String copyright = "$copyright";
  
    final static int 	layout[][] = { 
EOPS

for my $i (1..$h) {
	print JAVA "{";
	for my $j (1..$w) {
		print JAVA $numgrid[$i]->[$j];
		if ($j != $w) {print JAVA ", ";} 
		else {
			print JAVA "}";
			if ($i != $h) { print JAVA ",\n";} else {print JAVA "\n";}
		}
	}
}

print JAVA <<EOPS;
     }; 
  
  
     final static String answers[][] = { 
EOPS

for my $i (0..$h-1) {
	print JAVA "{";
	for my $j (0..$w-1) {
		print JAVA "\"".$answergrid[$i]->[$j]."\"";
		if ($j != $w-1) {print JAVA ", ";} 
		else {
			print JAVA "}";
			if ($i != $h-1) { print JAVA ",\n";} else {print JAVA "\n";}
		}
	}
}
			
print JAVA <<EOPS;
     }; 
  
  
  
     final static String gQuestionsAcross[] = { 
EOPS

for my $i (0..$maxwords-1) {
  print JAVA "\"".$across[$i]."\",   // ".$i."\n";
}
print JAVA "\"\"    // ".$maxwords."\n";
print JAVA "   };\n\n";
print JAVA "     final static String AcrossVector[] = { \n";

# This is the vector for the clue list.  It only takes non-empty clues
# and we need to 'HTML' them up for word wrap.
# At the same time, we set up the acrossIndices vector.

my $ctr = 0;
my @acrossIndices;

for my $i (1..$lastAcross-1) {
  if ($across[$i] ne "") {
  	$across[$i] = to_html($i.". ".$across[$i]);
  	print JAVA "\"".$across[$i]."\", \n";
	$acrossIndices[$i] = $ctr;
	$ctr++;
  }
}
print JAVA "\"".to_html($lastAcross.". ".$across[$lastAcross])."\"\n   };\n";
$acrossIndices[$lastAcross] = $ctr;

# We need to set the empty entries to 0.

for my $i (0..$lastAcross) {
	if ($acrossIndices[$i] eq "") {
		$acrossIndices[$i] = 0;
	} # end if
} # end for

# We do the same thing for down. 

print JAVA <<EOPS;
  
  
  
     final static String gQuestionsDown[] = { 
EOPS

for my $i (0..$maxwords-1) {
  print JAVA "\"".$down[$i]."\",   // ".$i."\n";
}
print JAVA "\"\"    // ".$maxwords."\n";
print JAVA "   };\n\n";
print JAVA "     final static String DownVector[] = { \n";

$ctr = 0;	# Don't forget to reset the counter!
my @downIndices;

for my $i (1..$lastDown-1) {
  if ($down[$i] ne "") {
  	$down[$i] = to_html($i.". ".$down[$i]);
  	print JAVA "\"".$down[$i]."\", \n";
	$downIndices[$i] = $ctr;
	$ctr++;
  }
}
print JAVA "\"".to_html($lastDown.". ".$down[$lastDown])."\"\n   };\n";
$downIndices[$lastDown] = $ctr;

for my $i (0..$lastDown) {
	if ($downIndices[$i] eq "") {
		$downIndices[$i] = 0;
	} # end if
} # end for

print JAVA "\n\n\n";

if ($circleIndex != -1) {	# Only do this if there are circles in the grid
	print JAVA "     final static String circleGrid[][] = { \n";
	for my $i (0..$h-1) {
		print JAVA "{";
		for my $j (0..$w-1) {
			print JAVA "\"";
			if ($circleGrid[$i]->[$j] eq chr(128)) {print JAVA "O";}
			print JAVA "\"";
			if ($j != $w-1) {print JAVA ", ";} 
			else {
				print JAVA "}";
				if ($i != $h-1) { print JAVA ",\n";} else {print JAVA "\n";}
			}	# end else
		}	# end for $j
	}	# end for $i
print JAVA "};\n";
} # end if $circleIndex

# Not much more perl to do until the very end ...

print JAVA <<EOPS;
    /*---------------------------------------------------------------*/

    String gGuesses[][] = new String[kBlocksWide][kBlocksHigh];
    int ColorMatrix[][] = new int[kBlocksWide][kBlocksHigh];
    
    int NumberCorrectAnswers = 0;
    int NumberWhiteSquares = 0;

    boolean	gUpdateActiveAreaFlag = false;
    boolean	gChangedActiveAreaFlag = false;

    Font buttonFont = null;
    Font tileFont = null;

    /*-------------------------------------------------------------*/

    public void init() {
	int viewWidth;
	int left, top;
	
	setLayout(new BorderLayout());
	Panel southPanel = new Panel();	/* Panel for buttons */
	FlowLayout leftLayout = new FlowLayout(FlowLayout.LEFT);
	southPanel.setLayout(leftLayout);

	RevealAll = new Button ("Reveal All");
	RevealAll.addActionListener(this);
	RevealWord = new Button ("Reveal Word");
	RevealWord.addActionListener(this);
	CheckAll = new Button ("Check All");
	CheckAll.addActionListener(this);
	CheckWord = new Button ("Check Word");
	CheckWord.addActionListener(this);

	Font cpFont = new Font ("Helvetica", Font.PLAIN, 12);
   String cpString = "   " + copyright + "\\n    Created at alexboisvert.com";
	copyrightText = new JTextArea(cpString);
	copyrightText.setEditable(false);
	copyrightText.setBackground(Color.WHITE);
	copyrightText.setBorder(null);
	copyrightText.setFont(cpFont);

	southPanel.add(CheckWord);
	southPanel.add(CheckAll);
	southPanel.add(RevealWord);
	southPanel.add(RevealAll);
	southPanel.add(copyrightText);
	add(southPanel,BorderLayout.SOUTH);

	/* Now we add a panel for the clue lists */ 
	

    Panel eastPanel = new Panel();
    eastPanel.setLayout(new BoxLayout(eastPanel, BoxLayout.PAGE_AXIS));

	AcrossList = new JList(AcrossVector);
    AcrossList.setSelectionMode(
    ListSelectionModel.SINGLE_SELECTION);
    AcrossList.setFixedCellWidth(200);
    AcrossList.setSelectedIndex(0);   
    AcrossList.setVisibleRowCount($acrossRows);   
    AcrossList.addListSelectionListener(this);
    JScrollPane pane = new JScrollPane(AcrossList);
        
    DownList = new JList(DownVector);
    DownList.setSelectionMode(
    ListSelectionModel.SINGLE_SELECTION);
    DownList.setFixedCellWidth(200);
    DownList.setVisibleRowCount($downRows);    
	DownList.addListSelectionListener(this);
    JScrollPane pane2 = new JScrollPane(DownList);
        
        
    AcrossText = new JTextField("Across");
	DownText = new JTextField("Down");

	Font helFontBold = new Font ("Helvetica", Font.BOLD, 14);
	Font helFont = new Font ("Helvetica", Font.PLAIN, 14);
	
	AcrossText.setFont(helFontBold);
	AcrossText.setEditable(false);
	AcrossText.setBackground(Color.WHITE);
	AcrossText.setBorder(null);
	DownText.setFont(helFontBold);
	DownText.setEditable(false);
	DownText.setBackground(Color.WHITE);
	DownText.setBorder(null);
        
    eastPanel.add(AcrossText);
    eastPanel.add(pane);
    eastPanel.add(DownText);
    eastPanel.add(pane2);
    add(eastPanel, BorderLayout.EAST);

	/* Now let's add a panel for the title and author */

	Panel northPanel = new Panel();
	northPanel.setLayout(leftLayout);
	titleText = new JTextField(title);
	authorText = new JTextField(author);

	titleText.setFont(helFontBold);
	titleText.setEditable(false);
	titleText.setBackground(Color.WHITE);
	titleText.setBorder(null);
	authorText.setEditable(false);
	authorText.setFont(helFont);
	authorText.setBackground(Color.WHITE);
	authorText.setBorder(null);

	northPanel.add(titleText);
	northPanel.add(authorText);

	add(northPanel,BorderLayout.NORTH);
    
	NewGame();
    
    
	buttonFont = new java.awt.Font("Courier", Font.PLAIN, 12);
	tileFont = new java.awt.Font("Helvetica", Font.PLAIN, 36);
	
    }

    /*---------------------------------------------------------------*/


    public void NewGame() {
	for (int j = 0 ; j < kBlocksHigh ; j++) {
	    for (int i = 0 ; i < kBlocksWide ; i++) {
		gGuesses[i][j] = "";	
		if (layout[j][i] != -1)
			{
			NumberWhiteSquares++;
			}
	    }
	}

	gOldBlockMinY	= 0;
	gOldBlockMaxY 	= 0;
	gOldBlockMinX = 0;
	gOldBlockMaxX	= 0;

	gDirection = kAcross;
	gCurX = $startX;
	gCurY = 0;
	SetActiveBlock(gCurX, gCurY, gDirection);
	

    }

    /*----------------------------------------------*/

    public void paint(Graphics g) {
	int left = 0;
	int right = kAppWidth - 1;
	int top = 0;
	int bottom = kAppHeight - 1;
	int tempLeft = 0;
	int tempRight = 0;
	int tempTop = 0;
	int	viewWidth;
	int	viewHeight;
	int buttonWidth = 0;
	int buttonHeight = 0;
	int buttonLeft = 0;
	int buttonTop = 0;
	int tileLeft;
	int tileTop;

	g.setColor(getForeground());
    
	Font f = new java.awt.Font("Helvetica", 0, 12);
	g.setFont(f);
    
	Font numFont = new java.awt.Font("Helvetica", 0, $numSize);
    
	Font answerFont = new java.awt.Font("Helvetica", Font.BOLD, $ansSize);
	Font questionFont = new java.awt.Font("Helvetica", 0, 18);
	Font questionFont18 = new java.awt.Font("Helvetica", 0, 14);

	FontMetrics answerFontMetrics = g.getFontMetrics(answerFont);
	FontMetrics questionFontMetrics = g.getFontMetrics(questionFont);
	FontMetrics questionFont18Metrics = 
g.getFontMetrics(questionFont18); 
    
	/* g.setColor(Color.lightGray);
	g.draw3DRect(0, 0, kAppWidth - 1, kAppHeight - 1, true); */
    
	viewWidth = kBlocksWide * kBlockWidth;
	viewHeight = kBlocksHigh * kBlockHeight;
    
    
	top = kPaddingTop;
	left = kPaddingLeft;
	g.setColor(Color.white);
	g.fill3DRect(left, top, viewWidth, kQuestionAreaHeight, false);
    
	g.setFont(f);
	String s = new String(	
String.valueOf(layout[gBlockMinY][gBlockMinX]));
	s = s.concat(" - ");
	if (gDirection == kAcross)
	    s = s.concat("across");
	else
	    s = s.concat("down");
	g.drawString(s, left + 5, top + 12);	
	g.setFont(questionFont);
	if (gDirection == kAcross) {
	    Font userFont = questionFont;
	
	    if 
(questionFontMetrics.stringWidth(gQuestionsAcross[layout[gBlockMinY][gBlockMinX]]) 
> viewWidth - 4)
	    {
		userFont = questionFont18;
		g.setFont(questionFont18);
	    }
	
	    g.drawString(gQuestionsAcross[layout[gBlockMinY][gBlockMinX]], 
			 left + 5, (top + kQuestionAreaHeight) - 8);
	
	}	
	else {
	    Font userFont = questionFont;
	
	    if 
(questionFontMetrics.stringWidth(gQuestionsDown[layout[gBlockMinY][gBlockMinX]]) 
> viewWidth - 4)
	    {
		userFont = questionFont18;
		g.setFont(questionFont18);
	    }
	
	    g.drawString(gQuestionsDown[layout[gBlockMinY][gBlockMinX]], 
			 left + 5, (top + kQuestionAreaHeight) - 8);
	}

	left = kPaddingLeft;
	top = (kPaddingTop + kPaddingClues) + kQuestionAreaHeight; 

	for (int j = 0 ; j < kBlocksHigh ; j++) {
	    for (int i = 0 ; i < kBlocksWide ; i++) {
		tempLeft = left + (i * kBlockWidth);
		tempTop = top + (j * kBlockHeight);
	
		if (InActiveBlock(i, j)) {
		    if (i == gCurX && j == gCurY)
			g.setColor(Color.cyan);
		    else
			g.setColor(Color.yellow);
		    g.fillRect(tempLeft, tempTop, kBlockWidth, 
kBlockHeight);
		}
		else {
		    g.setColor(Color.white);
		    g.fillRect(tempLeft, tempTop, kBlockWidth, 
kBlockHeight);
		}
	
		g.setColor(Color.black);
		g.drawRect(tempLeft, tempTop, kBlockWidth , kBlockHeight );
EOPS

if ($circleIndex != -1) {	# Only do this if there are circles in the grid
	print JAVA "	if (circleGrid[j][i] == \"O\") {";
	print JAVA "		g.setColor(Color.black);";
	print JAVA "		g.drawOval(tempLeft,tempTop,kBlockWidth,kBlockHeight);";
	print JAVA "	}";
}

print JAVA <<EOPS;
	
		if (layout[j][i] == -1){
		    g.setColor(Color.black);
		    g.fillRect(tempLeft, tempTop, kBlockWidth, 
kBlockHeight);
		}
		else if (layout[j][i] != 0) {
		    String numStr = String.valueOf(layout[j][i]);
	    
		    g.setFont(numFont);
		    g.drawString(numStr, tempLeft + $marginLeft , tempTop + $marginTop);
	    
		}
	
		// -- put in text if needed
		
		if (layout[j][i] != -1) {
		    if (gGuesses[i][j].length() != 0) {
			int sWidth = 0;
			
			if (ColorMatrix[i][j] == 1)
			    g.setColor(Color.red);
			else if (ColorMatrix[i][j] == 2)
			    g.setColor(Color.blue);
			else
				g.setColor(Color.black);
			
			sWidth = 
answerFontMetrics.stringWidth(gGuesses[i][j]);
			g.setFont(answerFont);
			g.drawString( gGuesses[i][j], tempLeft + 
((kBlockWidth / 2) - (sWidth / 2) + 3), (tempTop + kBlockHeight) - 3);
		    }
		    
		}	
		
	    }
	  } 
    }

    /*----------------------------------------------*/

    void PaintWord(Graphics g, int minX, int maxX, int minY, int maxY) {
	int viewWidth = kBlocksWide * kBlockWidth;
	int viewHeight = kBlocksHigh * kBlockHeight;
	int left = kPaddingLeft;
	int top = (kPaddingTop + kPaddingClues) + kQuestionAreaHeight; 
	int tempLeft = 0;
	int tempRight = 0;
	int tempTop = 0;
    
	left += (minX * kBlockWidth);
	top += (minY * kBlockHeight);
	/*
	g.clipRect(	left, top, 
		   (kBlockWidth * (maxX - minX)) + kBlockWidth, 
		   (kBlockHeight * (maxY - minY)) + kBlockHeight);
		   */
	       
	       
	Font f = new java.awt.Font("Helvetica", 0, 12);
	g.setFont(f);
	       
	Font numFont = new java.awt.Font("Helvetica", 0, $numSize);
	       
	Font answerFont = new java.awt.Font("Helvetica", Font.BOLD, $ansSize);
	FontMetrics answerFontMetrics = g.getFontMetrics(answerFont);
	       
	viewWidth = kBlocksWide * kBlockWidth;
	viewHeight = kBlocksHigh * kBlockHeight;
	       
	left = kPaddingLeft;
	top = (kPaddingTop + kPaddingClues) + kQuestionAreaHeight; 
	       
	for (int j = minY ; j <= maxY ; j++) {
	    for (int i = minX ; i <= maxX ; i++) {
		tempLeft = left + (i * kBlockWidth);
		tempTop = top + (j * kBlockHeight);
		       
		if (InActiveBlock(i, j)) {
		    if (i == gCurX && j == gCurY)
			g.setColor(Color.cyan);
		    else
			g.setColor(Color.yellow);
		    g.fillRect(tempLeft, tempTop, kBlockWidth, 
kBlockHeight);
		}
		else {
		    g.setColor(Color.white);
		    g.fillRect(tempLeft, tempTop, kBlockWidth, 
kBlockHeight);
		}
		       
		g.setColor(Color.black);
		g.drawRect(tempLeft, tempTop, kBlockWidth , kBlockHeight );
		     
EOPS

if ($circleIndex != -1) {	# Only do this if there are circles in the grid
	print JAVA "	if (circleGrid[j][i] == \"O\") {";
	print JAVA "		g.setColor(Color.black);";
	print JAVA "		g.drawOval(tempLeft,tempTop,kBlockWidth,kBlockHeight);";
	print JAVA "	}";
}

print JAVA <<EOPS;     
		
		if (layout[j][i] == -1) {
		    g.setColor(Color.black);
		    g.fillRect(tempLeft, tempTop, kBlockWidth, kBlockHeight);
		}
		else if (layout[j][i] != 0) {
		    String numStr = String.valueOf(layout[j][i]);
			   
		    g.setFont(numFont);
		    g.drawString(numStr, tempLeft + $marginLeft , tempTop + $marginTop);
			   
		}
		       
		// -- put in text if needed
		
		if (layout[j][i] != -1) {
		    if (gGuesses[i][j].length() != 0) {
			int sWidth = 0;
			
			if (ColorMatrix[i][j] == 1)
			    g.setColor(Color.red);
			else if (ColorMatrix[i][j] == 2)
			    g.setColor(Color.blue);
			else
				g.setColor(Color.black);
			
			sWidth = 
answerFontMetrics.stringWidth(gGuesses[i][j]);
			g.setFont(answerFont);
			g.drawString( gGuesses[i][j], tempLeft + 
((kBlockWidth / 2) - (sWidth / 2) + 3), (tempTop + kBlockHeight) - 3);
		    }
		    
		}	
		
	    }
	}	
    }

    /*----------------------------------------------*/

    void PaintQuestionArea(Graphics g) {
	Font f = new java.awt.Font("Helvetica", 0, 12);
	Font questionFont = new java.awt.Font("Helvetica", 0, 18);
	Font questionFont18 = new java.awt.Font("Helvetica", 0, 14);
	FontMetrics questionFontMetrics = g.getFontMetrics(questionFont);
    
	int viewWidth = kBlocksWide * kBlockWidth;
	int viewHeight = kBlocksHigh * kBlockHeight;
    
	int top = kPaddingTop;
	int left = kPaddingLeft;
	//g.clipRect(left, top, viewWidth, kQuestionAreaHeight);
    
	g.setColor(Color.white);
	g.fill3DRect(left, top, viewWidth, kQuestionAreaHeight, false);
    
	g.setFont(f);
	String s = new String(	
String.valueOf(layout[gBlockMinY][gBlockMinX]));
	s = s.concat(" - ");
	if (gDirection == kAcross)
	    s = s.concat("across");
	else
	    s = s.concat("down");
	g.drawString(s, left + 5, top + 12);	
	g.setFont(questionFont);
	int fontSize = 24;
	if (gDirection == kAcross) {
	    Font userFont = questionFont;
	
	    if 
(questionFontMetrics.stringWidth(gQuestionsAcross[layout[gBlockMinY][gBlockMinX]]) 
> viewWidth - 4) {
		userFont = questionFont18;
		g.setFont(questionFont18);
	    }
	
	    g.drawString(gQuestionsAcross[layout[gBlockMinY][gBlockMinX]], 
			 left + 5, (top + kQuestionAreaHeight) - 8);
	
	}	
	else {
	    Font userFont = questionFont;
	
	    if 
(questionFontMetrics.stringWidth(gQuestionsDown[layout[gBlockMinY][gBlockMinX]]) 
> viewWidth - 4) {
		userFont = questionFont18;
		g.setFont(questionFont18);
	    }
	
	    g.drawString(gQuestionsDown[layout[gBlockMinY][gBlockMinX]], 
			 left + 5, (top + kQuestionAreaHeight) - 8);
	}

    }

    /*----------------------------------------------*/

    private boolean InActiveBlock(int x, int y) {
	if (x < gBlockMinX)
	    return(false);
	if (x > gBlockMaxX)
	    return(false);
	if (y < gBlockMinY)
	    return(false);
	if (y > gBlockMaxY)
	    return(false);
    
	return(true);
    }

    /*----------------------------------------------*/

    private void SetActiveBlock(int x, int y, int direction) {
	int tempx;
	int tempy;

	gOldBlockMinY	= gBlockMinY;
	gOldBlockMaxY 	= gBlockMaxY;
	gOldBlockMinX = gBlockMinX;
	gOldBlockMaxX	= gBlockMaxX;


	if (direction == kAcross) {
	    gBlockMinY = y;
	    gBlockMaxY = y;
	    tempx = x;
	    while (tempx > 0 && layout[y][tempx] != -1) {
		tempx--;
	    }
	    if (tempx > 0)
		gBlockMinX = tempx + 1;
	    else {
		if (layout[y][0] == -1)
		    gBlockMinX = 1;
		else
		    gBlockMinX = 0;
	    }

	    tempx = x;
	    while (tempx < kBlocksWide && layout[y][tempx] != -1)
	    {
		tempx++;
	    }
	    gBlockMaxX = tempx -1;
	}
	else {
	    gBlockMinX = x;
	    gBlockMaxX = x;
	    tempy = y;
	    while (tempy > 0 && layout[tempy][x] != -1) {
		tempy--;
	    }
	    if (tempy > 0)
		gBlockMinY = tempy + 1;
	    else {
		if (layout[0][x] == -1)
		    gBlockMinY = 1;
		else
		    gBlockMinY = 0;
	    }

	    tempy = y;
	    while (tempy < kBlocksHigh && layout[tempy][x] != -1) {
		tempy++;
	    }
	    gBlockMaxY = tempy -1;
	}	
    }

    /*----------------------------------------------*/

    public void update(Graphics g)  {
	if (clipLeft != -1 && clipTop != -1) {
	    //g.clipRect(clipLeft, clipTop, clipWidth, clipHeight);
	    clipLeft = clipTop = clipWidth = clipHeight = -1;
	}

	if (gChangedActiveAreaFlag == false && gUpdateActiveAreaFlag == 
false) {		
	    paint(g);
	    return;
	}

	if (gChangedActiveAreaFlag == true) {
	    PaintQuestionArea(g);
	    PaintWord(g, gOldBlockMinX, gOldBlockMaxX, gOldBlockMinY, 
gOldBlockMaxY);
	    PaintWord(g, gBlockMinX, gBlockMaxX, gBlockMinY, gBlockMaxY);
	    gChangedActiveAreaFlag = false;
	    return;
	}

	//-----------------------------------------------
	
	if (gUpdateActiveAreaFlag == true) {
	    gUpdateActiveAreaFlag = false;
	    PaintWord(g, gBlockMinX, gBlockMaxX, gBlockMinY, gBlockMaxY);
	    return;
	}
	
    }

    /*----------------------------------------------*/

    private void beep() {
	play(getCodeBase(), "nope.au");
    }

    /*----------------------------------------------*/

    public boolean mouseDown(java.awt.Event evt, int x, int y) {
	int viewWidth = kBlocksWide * kBlockWidth;
	int left = kPaddingLeft;
	int top = (kPaddingTop + kPaddingClues) + kQuestionAreaHeight; 

	requestFocus();

	if (x < left)
	    return false;
	if (y < top)
	    return false;
    
	int j = y - top;
	j /= kBlockHeight;
    
	int i = x - left;
	i /= kBlockWidth;
    
	if (i >= 0 && i < kBlocksWide && j >= 0 && j < kBlocksHigh) {
		if ((i == gCurX && j == gCurY)) {
			if ( (gDirection == kAcross && j == 0 && layout[j+1][i] != -1) ||
			     (gDirection == kDown && i == 0 && layout[j][i+1] != -1) ||
			     (gDirection == kAcross && (layout[j-1][i] != -1 || layout[j+1][i] != -1)) ||
			     (gDirection == kDown && (layout[j][i-1] != -1 || layout[j][i+1] != -1)) ) {
				ChangeDirection();
				gChangedActiveAreaFlag = true;
				repaint();
				ListsUpdate();
			}
		}
		else {
	   	 	if (layout[j][i] != -1) {
				if (InActiveBlock(i, j)) {
					gCurX = i;
					gCurY = j;
				    gUpdateActiveAreaFlag = true;
				    repaint();
					}
				else {
					gCurX = i;
					gCurY = j;
					if ( (gDirection == kAcross && (i == 0 || layout[j][i-1] == -1) && (i == kBlocksWide-1 || layout[j][i+1] == -1)) ) {
						gDirection = kDown;
					}
				    if ((gDirection == kDown && (j == 0 || layout[j-1][i] == -1) && (j == kBlocksHigh-1 || layout[j+1][i] == -1)) ) {
						gDirection = kAcross;
					}
		 		    SetActiveBlock(i, j, gDirection);
				    gChangedActiveAreaFlag = true;
				    repaint();
				}
			ListsUpdate();
			return true;
	   		}
	   	}
	}
	return true;
    }

    /*----------------------------------------------*/

    public boolean mouseUp(java.awt.Event evt, int x, int y) {
	requestFocus();
	return true;
    }

    /*----------------------------------------------*/

    public boolean mouseDrag(java.awt.Event evt, int x, int y) {
	requestFocus();
	return true;
    }


    /*----------------------------------------------*/

    public boolean mouseExit(java.awt.Event evt) {
	return true;
    }

    /*----------------------------------------------*/

    public boolean mouseEnter(java.awt.Event evt) {
	requestFocus();
	return true;
    }

    /*----------------------------------------------*/

    public boolean mouseMove(java.awt.Event evt, int x, int y) {
	requestFocus();
	return true;
    }

    /*----------------------------------------------*/

    public boolean keyDown(java.awt.Event evt, int key) {

	int tempx;
	int tempy;
	boolean tempWIC=false;
	
	/* If a letter is typed ... */
	
	if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z')) {
	    char charArray[] = new char[1];
    
	    charArray[0] = (char)key;
	    
	    tempWIC=WasItCorrect(gCurX,gCurY);
    
	    gGuesses[gCurX][gCurY] = new String(charArray); 
	    gGuesses[gCurX][gCurY] = gGuesses[gCurX][gCurY].toUpperCase();
    	
    	if (WasItCorrect(gCurX,gCurY) == true && tempWIC == false)
    		{
    		NumberCorrectAnswers++;
    		}
    	if (WasItCorrect(gCurX,gCurY) == false && tempWIC == true)
    		{
    		NumberCorrectAnswers--;
    		}
    	
	    if (gDirection == kAcross) {
		if (gCurX < kBlocksWide - 1 && layout[gCurY][gCurX+1] != -1)
			{
			gCurX++;
			ListsUpdate();
			}
	    }
	    else {
		if (gCurY < kBlocksHigh - 1 && layout[gCurY + 1][gCurX] != -1)
			{
			gCurY++;
			ListsUpdate();
			}
	    }
	    gUpdateActiveAreaFlag = true;
	    repaint();
	    if (NumberCorrectAnswers == NumberWhiteSquares)
	    	{
	    	JOptionPane.showMessageDialog(null, "The puzzle has been successfully completed.", "Congratulations!", JOptionPane.INFORMATION_MESSAGE);
	    	NumberWhiteSquares++;
	    	repaint();
	    	}
	    return true;
	}
	
	/* If an arrow key is pressed ... */

	switch ((char)key) {
		case Event.RIGHT:
			if (gDirection == kAcross) {
				if (gCurX < kBlocksWide - 1) {
					tempx = gCurX+1;
					tempy = gCurY;
					while (layout[gCurY][tempx] == -1) {
						++tempx;
						if (tempx == kBlocksWide) {
							tempx = gCurX;
							}
						}
					gCurX = tempx;
					gCurY = tempy;
					if (InActiveBlock(tempx, tempy)) {
				    	  gUpdateActiveAreaFlag = true;
				   	   repaint();
					}
					else {
		   			  SetActiveBlock(tempx, tempy, gDirection);
		  			  gChangedActiveAreaFlag = true;
		  			  repaint();
					}
				ListsUpdate();
				}
	    	}
			else { /* if gDirection == kDown */
				if ((gCurX == 0 || layout[gCurY][gCurX-1] == -1) && (gCurX == kBlocksWide-1 || layout[gCurY][gCurX+1] == -1)) {
					if (gCurX < kBlocksWide - 1) {
						tempx = gCurX+1;
						tempy = gCurY;
						while (layout[gCurY][tempx] == -1) {
							++tempx;
							if (tempx == kBlocksWide) {
								tempx = gCurX;
								}
							}
						gCurX = tempx;
						gCurY = tempy;
						if (InActiveBlock(tempx, tempy)) {
				    		  gUpdateActiveAreaFlag = true;
				   		   repaint();
						}
						else {
		   				  SetActiveBlock(tempx, tempy, gDirection);
		  				  gChangedActiveAreaFlag = true;
		  				  repaint();
						}
					ListsUpdate();
					}
				}
				else {
					ChangeDirection();
	    			if (gGuesses[gCurX][gCurY] != "" && gCurX < kBlocksWide - 1 && layout[gCurY][gCurX+1] != -1) {
	    				gCurX++;
	    			}
	    			gChangedActiveAreaFlag = true;
	  				repaint();
					ListsUpdate();
				}
	  		}
	    break;
	    case Event.LEFT:
			if (gDirection == kAcross) {
				if (gCurX != 0) {
					tempx = gCurX-1;
					tempy = gCurY;
					while (layout[gCurY][tempx] == -1) {
						--tempx;
						if (tempx == -1) {
							tempx = gCurX;
							}
						}
					gCurX = tempx;
					gCurY = tempy;
					if (InActiveBlock(tempx, tempy)) {
				    	  gUpdateActiveAreaFlag = true;
				   	   repaint();
					}
					else {
		   			  SetActiveBlock(tempx, tempy, gDirection);
		  			  gChangedActiveAreaFlag = true;
		  			  repaint();
					}
				ListsUpdate();
				}
	    	}
	  		else { /* if gDirection == kDown */
				if ((gCurX == 0 || layout[gCurY][gCurX-1] == -1) && (gCurX == kBlocksWide-1 || layout[gCurY][gCurX+1] == -1)) {
					if (gCurX != 0) {
						tempx = gCurX-1;
						tempy = gCurY;
						while (layout[gCurY][tempx] == -1) {
							--tempx;
							if (tempx == -1) {
								tempx = gCurX;
								}
							}
						gCurX = tempx;
						gCurY = tempy;
						if (InActiveBlock(tempx, tempy)) {
				    		  gUpdateActiveAreaFlag = true;
				   		   repaint();
						}
						else {
		   				  SetActiveBlock(tempx, tempy, gDirection);
		  				  gChangedActiveAreaFlag = true;
		  				  repaint();
						}
					ListsUpdate();
					}
				}
				else {
					ChangeDirection();
	    			if (gGuesses[gCurX][gCurY] != "" && gCurX < kBlocksWide - 1 && layout[gCurY][gCurX+1] != -1) {
	    				gCurX--;
	    				}
	    			gChangedActiveAreaFlag = true;
	  				repaint();
					ListsUpdate();
				}
	  		}
	    break;
	    case Event.UP:
			if (gDirection == kDown) {
				if (gCurY != 0) {
					tempx = gCurX;
					tempy = gCurY-1;
					while (layout[tempy][gCurX] == -1) {
						--tempy;
						if (tempy == -1) {
							tempy = gCurY;
							}
						}
					gCurX = tempx;
					gCurY = tempy;
					if (InActiveBlock(tempx, tempy)) {
				    	  gUpdateActiveAreaFlag = true;
				   	   repaint();
					}
					else {
		   			  SetActiveBlock(tempx, tempy, gDirection);
		  			  gChangedActiveAreaFlag = true;
		  			  repaint();
					}
				ListsUpdate();
				}
	    	}
	  		else { /* if gDirection == kAcross */
				if ((gCurY == 0 || layout[gCurY-1][gCurX] == -1) && (gCurY == kBlocksHigh-1 || layout[gCurY+1][gCurX] == -1)) {
					if (gCurY != 0) {
						tempx = gCurX;
						tempy = gCurY-1;
						while (layout[tempy][gCurX] == -1) {
							--tempy;
							if (tempy == -1) {
								tempy = gCurY;
								}
							}
						gCurX = tempx;
						gCurY = tempy;
						if (InActiveBlock(tempx, tempy)) {
				    		  gUpdateActiveAreaFlag = true;
				   		   repaint();
						}
						else {
		   				  SetActiveBlock(tempx, tempy, gDirection);
		  				  gChangedActiveAreaFlag = true;
		  				  repaint();
						}
					ListsUpdate();
					}
				}
				else {
					ChangeDirection();
	    			if (gGuesses[gCurX][gCurY] != "" && gCurX < kBlocksWide - 1 && layout[gCurY][gCurX+1] != -1) {
	    				gCurY--;
	    				}
	    			gChangedActiveAreaFlag = true;
	  				repaint();
					ListsUpdate();
				}
	  		}
	    break;
	    case Event.DOWN:
			if (gDirection == kDown) {
				if (gCurY < kBlocksHigh -1) {
					tempx = gCurX;
					tempy = gCurY+1;
					while (layout[tempy][gCurX] == -1) {
						++tempy;
						if (tempy == kBlocksHigh) {
							tempy = gCurY;
							}
						}
					gCurX = tempx;
					gCurY = tempy;
					if (InActiveBlock(tempx, tempy)) {
				    	  gUpdateActiveAreaFlag = true;
				   	   repaint();
					}
					else {
		   			  SetActiveBlock(tempx, tempy, gDirection);
		  			  gChangedActiveAreaFlag = true;
		  			  repaint();
					}
				ListsUpdate();
				}
	    	}
	  		else { /* if gDirection == kAcross */
				if ((gCurY == 0 || layout[gCurY-1][gCurX] == -1) && (gCurY == kBlocksHigh-1 || layout[gCurY+1][gCurX] == -1)) {
					if (gCurY < kBlocksHigh -1) {
						tempx = gCurX;
						tempy = gCurY+1;
						while (layout[tempy][gCurX] == -1) {
							++tempy;
							if (tempy == kBlocksHigh) {
								tempy = gCurY;
							}
						}
						gCurX = tempx;
						gCurY = tempy;
						if (InActiveBlock(tempx, tempy)) {
				    		  gUpdateActiveAreaFlag = true;
				   		   repaint();
						}
						else {
		   				  SetActiveBlock(tempx, tempy, gDirection);
		  				  gChangedActiveAreaFlag = true;
		  				  repaint();
						}
					ListsUpdate();
					}
				}
				else {
					ChangeDirection();
	    			if (gGuesses[gCurX][gCurY] != "" && gCurY < kBlocksHigh - 1 && layout[gCurY+1][gCurX] != -1) {
	    				gCurY++;
	    			}
	    			gChangedActiveAreaFlag = true;
	  				repaint();
					ListsUpdate();
				}
			}
	    break;
	    
	  /* Space, backspace or delete ... */
	  
	  case ' ':
		if (WasItCorrect(gCurX,gCurY) == true)
			{
			NumberCorrectAnswers--;
			}
		gGuesses[gCurX][gCurY] = "";
			
		if (gDirection == kAcross) {
		    if (gCurX < kBlocksWide - 1 && layout[gCurY][gCurX+1] != -1) {
			gCurX++;
		    }
		}
		else {
		    if (gCurY < kBlocksHigh - 1 && layout[gCurY + 1][gCurX] != -1) {
			gCurY++;
		    }
		}
		gUpdateActiveAreaFlag = true;
		ListsUpdate();
		repaint();
	    break;
	  case 0x08:
	    if (gGuesses[gCurX][gCurY] != "") {
			if (WasItCorrect(gCurX,gCurY) == true)
			{
			NumberCorrectAnswers--;
			}
			gGuesses[gCurX][gCurY] = "";
			gUpdateActiveAreaFlag = true;
			repaint();
	    	}
	    else {
		if (gDirection == kAcross) {
		    if (gCurX != 0 && layout[gCurY][gCurX-1] != -1) {
			gCurX--;
			if (WasItCorrect(gCurX,gCurY) == true)
			{
			NumberCorrectAnswers--;
			}
			gGuesses[gCurX][gCurY] = "";
			gUpdateActiveAreaFlag = true;
			repaint();	
			ListsUpdate();
		    }
		}
		else {
		    if (gCurY != 0 && layout[gCurY - 1][gCurX] != -1) {
			gCurY--;
			if (WasItCorrect(gCurX,gCurY) == true)
			{
			NumberCorrectAnswers--;
			}
			gGuesses[gCurX][gCurY] = "";
			gUpdateActiveAreaFlag = true;
			repaint();
			ListsUpdate();
		    }
		}
	    }
	    break;
	   case Event.DELETE:
	   	if (gGuesses[gCurX][gCurY] != "") {
		if (WasItCorrect(gCurX,gCurY) == true)
			{
			NumberCorrectAnswers--;
			}
		gGuesses[gCurX][gCurY] = "";
		gUpdateActiveAreaFlag = true;
		repaint();
	    }
	    break;
 
	  /* If the Enter or Return key is pressed ... */
     case 0x03:
         EnterPressed();
         break;

     case 0x0A:
         EnterPressed();
         break;

	    
	  default:
	    beep();
	    break;
	}
	return true;
    }


    /*----------------------------------------------*/

    int random(int max) {
	return (int)Math.floor(Math.random() * max);
    }

    /*----------------------------------------------*/

    boolean PtInRect(int x, int y, int left, int top, int right, int 
bottom) {
	if (x < left)
	    return(false);
    
	if (x > right)
	    return(false);
    
	if (y < top)
	    return(false);
    
	if (y > bottom)
	    return(false);
    
	return(true);
    }

    /*----------------------------------------------*/

    void ChangeDirection() {
	if (gDirection == kDown) {
	    gDirection = kUp;	
	}
	else
	    gDirection = kDown;
	SetActiveBlock(gCurX, gCurY, gDirection);	
    }
	
	/*----------------------------------------------*/
	
	public boolean WasItCorrect(int i, int j) {
	if (gGuesses[i][j].equalsIgnoreCase(answers[j][i]) == true)
		{
		return true;
		}
	else
		{
		return false;
		}
	}
	
	/*----------------------------------------------*/
	
	public void Reveal(int x1, int x2, int y1, int y2) {
	for (int i=x1;i<=x2;i++) {
		for (int j=y1;j<=y2;j++) {
			if ( WasItCorrect(i,j) == false)
				{
				ColorMatrix[i][j]=1;
				gGuesses[i][j]=answers[j][i];
				NumberCorrectAnswers++;
				}
			}
		}
	}
	
	/*----------------------------------------------*/
	
	public void Check(int x1, int x2, int y1, int y2) {
	for (int i=x1;i<=x2;i++) {
		for (int j=y1;j<=y2;j++) {
			if ( gGuesses[i][j] != "" && WasItCorrect(i,j) == false)
				{
				gGuesses[i][j]="%";
				if (ColorMatrix[i][j] != 1)
					{
					ColorMatrix[i][j]=2;
					}
				}
			}
		}
	}
	
	/*----------------------------------------------*/
		
	public void actionPerformed(ActionEvent e)
		{
	      if (e.getSource() == RevealAll)
			{
			Reveal(0,kBlocksWide-1,0,kBlocksHigh-1);
     			repaint();
			}
		if (e.getSource() == RevealWord)
			{
	    		Reveal(gBlockMinX,gBlockMaxX,gBlockMinY,gBlockMaxY);
	    		repaint();			
			}
		if (e.getSource() == CheckWord)
			{
	    		Check(gBlockMinX,gBlockMaxX,gBlockMinY,gBlockMaxY);
	    		repaint();			
			}
		if (e.getSource() == CheckAll)
			{
	    		Check(0,kBlocksWide-1,0,kBlocksHigh-1);
	    		repaint();			
			}
		}		
		
	/*----------------------------------------------*/
		
	public void valueChanged(ListSelectionEvent evt) 
		{
		JList ListSource = (JList)evt.getSource();
		if (ListSource.getSelectedIndex() != -1)
			  {
		int AcrossArray[][] = {		
EOPS

my $acrossArraySize = $#acrossArray;
my $downArraySize = $#downArray;

for my $i (0..$acrossArraySize-1) {
	print JAVA "{".$acrossArray[$i]->[0].",".$acrossArray[$i]->[1]."}, ";
	if ($i % 8 == 7) { print JAVA "\n";}
}
print JAVA "{".$acrossArray[$acrossArraySize][0].",".$acrossArray[$acrossArraySize][1];
print JAVA "}\n   };\n";

# Now the same for down

print JAVA "		int DownArray[][] = {\n";
for my $i (0..$downArraySize-1) {
	print JAVA "{".$downArray[$i]->[0].",".$downArray[$i]->[1]."}, ";
	if ($i % 8 == 7) { print JAVA "\n";}
}
print JAVA "{".$downArray[$downArraySize][0].",".$downArray[$downArraySize][1];
print JAVA "}\n   };\n";

print JAVA <<EOPS;
		if (ListSource == AcrossList)
			{
			int CurIndex = AcrossList.getSelectedIndex();
			int i = AcrossArray[CurIndex][0];
			int j = AcrossArray[CurIndex][1];
			if (InActiveBlock(i, j) == false || gDirection == kDown) 
				{
		   	 	gCurX = i;
				gCurY = j;
				gDirection = kAcross;
	 	   		SetActiveBlock(i, j, gDirection);
		    	gChangedActiveAreaFlag = true;
		    	repaint();
		    	requestFocus();
				}
			DownList.getSelectionModel().clearSelection();
			}
		if (ListSource == DownList)
			{
			int CurIndex = DownList.getSelectedIndex();
			int i = DownArray[CurIndex][0];
			int j = DownArray[CurIndex][1];
			if (InActiveBlock(i, j) == false || gDirection == kAcross) 
				{
		   	 	gCurX = i;
				gCurY = j;
				gDirection = kDown;
		    	SetActiveBlock(i, j, gDirection);
		    	gChangedActiveAreaFlag = true;
		    	repaint();
		    	requestFocus();
		    	}
			AcrossList.getSelectionModel().clearSelection();
			}
		  }
		}

	/*----------------------------------------------*/
public void EnterPressed() {
       if (gDirection == kAcross) {
               int enterArray[][] = {
EOPS

for my $i (0..$lastAcross-1) {
	print JAVA "{".$acrossEnterArray[$i]->[0].",".$acrossEnterArray[$i]->[1]."}, ";
	if ($i % 8 == 7) {print JAVA "\n";}
}
print JAVA "{".$acrossEnterArray[$lastAcross]->[0].",".$acrossEnterArray[$lastAcross]->[1]."} ";
print JAVA "\n               };\n";
print JAVA <<EOPS;
       int curNum = layout[gBlockMinY][gBlockMinX];
       gCurX = enterArray[curNum][0];
       gCurY = enterArray[curNum][1];
       }
       else {
               int enterArray[][] = {
EOPS

# Same for down now ...

for my $i (0..$lastDown-1) {
	print JAVA "{".$downEnterArray[$i]->[0].",".$downEnterArray[$i]->[1]."}, ";
	if ($i % 8 == 7) {print JAVA "\n";}
}
print JAVA "{".$downEnterArray[$lastDown]->[0].",".$downEnterArray[$lastDown]->[1]."} ";
print JAVA "\n               };\n";

print JAVA <<EOPS;
       int curNum = layout[gBlockMinY][gBlockMinX];
       gCurX = enterArray[curNum][0];
       gCurY = enterArray[curNum][1];
       }
       SetActiveBlock(gCurX,gCurY,gDirection);
       gChangedActiveAreaFlag = true;
       repaint();
       ListsUpdate();
}
	/*----------------------------------------------*/

	public void ListsUpdate()
		{
     int AcrossIndices[] = { 
EOPS
for my $i (0..$lastAcross-1) {
	print JAVA $acrossIndices[$i].", ";
	if ($i % 20 == 19) {print JAVA "\n";}
}
print JAVA $acrossIndices[$lastAcross]."};\n";
print JAVA <<EOPS; 
     int DownIndices[] = { 
EOPS
for my $i (0..$lastDown-1) {
	print JAVA $downIndices[$i].", ";
	if ($i % 20 == 19) {print JAVA "\n";}
}
print JAVA $downIndices[$lastDown]."};\n";

print JAVA <<EOPS;
 
		int lonum,cluevalue;
		if (gDirection == kAcross)
			{		// take care of across first
			lonum = layout[gBlockMinY][gBlockMinX];
			cluevalue = AcrossIndices[lonum];
			AcrossList.setSelectedIndex(cluevalue);
			AcrossList.ensureIndexIsVisible(cluevalue);
					// now take care of down
			DownList.getSelectionModel().clearSelection();
			}
		else
			{		// take care of down first
			lonum = layout[gBlockMinY][gBlockMinX];
			cluevalue = DownIndices[lonum];
			DownList.setSelectedIndex(cluevalue);
			DownList.ensureIndexIsVisible(cluevalue);
					// now take care of across
			AcrossList.getSelectionModel().clearSelection();
			}

		}
}	// end program
EOPS

close JAVA;

# If javac exists ...
if (-e "/usr/bin/javac") {
	print "Java compiler found.  Now compiling $name.java.\n";
	print "Javac may give a warning you can ignore below.\n\n";
	$dir =~ s/ /\\ /g;
	system("/usr/bin/javac -target 1.4 -source 1.4 $dir/$name.java");
	print "\n";
} else {
	print "No java compiler found.\n";
	print "Instructions for compiling $name.java can be found\nin the $name.java file/\n";
}
print "Done!\n";

# subs

# This first one fixes quotes and converts some common characters to unicode.

sub no_quote {
	my $word=shift;
	$word =~ s/\"/\\\"/g;
	my $hexchars = '';
	foreach my $c (split(//,$word)) {
		if (ord($c)>128) {$hexchars .= '\\u00'.sprintf "%x", ord($c);}
		else {$hexchars .= $c;}
	}
	return $hexchars;
}

# This guy turns strings into HTML, for the clue lists.

sub to_html {
	my $word=shift;
	my $test="";
	my $temp;
	my $newWord="";
	while (length($word) > 28) {
		$test = substr($word,0,28);
		my $i = rindex($test," ");
		$test = substr($test,0,$i)."<p>";
		$newWord .= $test;
		$word = substr($word,$i+1);
	} # end while
	$newWord .= $word;
	$newWord = "<HTML>".$newWord."</HTML>";
	return $newWord;
}
