// Copyright 1996, Marimba Inc. All Rights Reserved.
// @(#)WordSmithWidget.java, 1.4, 11/21/96

package wordsmith;

import java.awt.*;
import java.util.*;
import java.io.*;
import java.net.*;

import marimba.channel.*;
import marimba.persist.*;
import marimba.gui.*;
import marimba.io.*;

/**
 * Widget to draw puzzle
 *
 * @author      Carl W. Haynes III
 * @version     1.4, 11/21/96
 */

public class WordSmithWidget extends GroupWidget {

    char letters[][] = new char[TILES_WIDE][TILES_HIGH];

    char letterPool[] = {
	'A','A','A','A','A','A','A','A','A',
	'B','B','B',
	'C','C','C',
	'D','D','D',
	'E','E','E','E','E','E','E','E','E','E','E','E',
	'F','F','F',
	'G','G','G',
	'H','H','H','H',
	'I','I','I','I','I','I','I','I',
	'J','J','J',
	'K','K','K',
	'L','L','L','L','L',
	'M','M','M','M','M',
	'N','N','N','N','N',
	'O','O','O','O','O','O','O','O',
	'P','P','P','P',
	'Q',
	'R','R','R','R','R','R',
	'S','S','S','S','S','S','S','S',
	'T','T','T','T','T','T',
	'U','U','U','U','U','U','U',
	'V','V','V',
	'W','W','W','W',
	'X','X',
	'Y','Y','Y','Y',
	'Z','Z'
    };


    static final int TILE_SIZE = 40;
    static final int TILES_WIDE = 15;
    static final int TILES_HIGH = 8;

    static final int BORDER_H = 10;
    static final int BORDER_V = 50;

    Image tilesImage = null;
    Image letterImage = null;
    Image darkLetterImage = null;

    char dragging = (char)-1;
    int draggingX = -1;
    int draggingY = -1;
    int originX = -1;
    int originY = -1;

    /** for clipping while dragging */
    int lastLeft = -1;
    int lastTop = -1;
    int lastRight = -1;
    int lastBottom = -1;

    static final int RACK_LEFT = BORDER_H;
    static final int RACK_TOP = 20;
    static final int RACK_WIDTH = (TILE_SIZE*10) + (5*11);
    static final int RACK_HEIGHT = TILE_SIZE+10;

    /** my own modal dialogs */
    boolean blockInput = false;

    Image rackImage;

    Rack rack;

    /** eliminating extra key strokes? */
    boolean keyTrack = false;

    /** the dictionary */
    Dict dict;

    /** score */
    int score = 0;


    /** score images */
    Image num[] = new Image[10];

    /** main score image */
    Image scoreImage;

    /** placement */
    static final int SCORE_LEFT = BORDER_H;;
    static final int SCORE_TOP = 430;
    static final int SCORE_WIDTH = (18 * 5) + 10;
    static final int SCORE_HEIGHT = 24;
    final static int numWidth = 18;
    final static int numHeight = 24;

    /** number of tiles left */
    int tilesLeft = 0;
    Image tilesLeftImage = null;
    static final int TILESLEFT_LEFT = BORDER_H;;
    static final int TILESLEFT_TOP = 430;
    static final int TILESLEFT_WIDTH = (18 * 3) + 10;
    static final int TILESLEFT_HEIGHT = 24;

    /** high scores */
    HighScoreManager highScores = null;

    /**
     * Default constructor.
     */
    public WordSmithWidget() {
	for (int i = 0 ; i < TILES_WIDE ; i++) {
	    for (int j = 0 ; j < TILES_HIGH ; j++) {
		letters[i][j] = (char)-1;
	    }
	}

	rack = new Rack();
    }

    /*
     * init
     */
    public void setContext(ApplicationContext context) {
	dict = new Dict(context);
    }

    /**
      * set the high score manager
      */
    public void setHighScoreManager(HighScoreManager hsm) {
	this.highScores = hsm;
    }

    /*
     * init
     */
    public void init() {
	WindowWidget ww = (WindowWidget)getWidget("okmessage");
	ww.hide();

	ww = (WindowWidget)getWidget("badwordmsg");
	ww.hide();

    	for (int i = 0 ; i < 10 ; i++) {
	    num[i] = getImage("images/"+i+".gif");
            if (Toolkit.getDefaultToolkit().prepareImage(num[i], -1, -1, this)) {
            }
	}

	createOffscreens();
    }

    /** starting up - get the high score manager*/
    public void start() {
	if (dict == null) {
	    dict = new Dict();
	}

	newGame();
    }

    /** create the main offscreen image */
    public void createOffscreens() {
	tilesImage = createImage(TILES_WIDE*TILE_SIZE, TILES_HIGH*TILE_SIZE);
	letterImage = createImage(TILE_SIZE, TILE_SIZE);
	darkLetterImage = createImage(TILE_SIZE, TILE_SIZE);
	rackImage = createImage(RACK_WIDTH, RACK_HEIGHT);
	scoreImage = createImage(SCORE_WIDTH, SCORE_HEIGHT);
	tilesLeftImage = createImage(TILESLEFT_WIDTH, TILESLEFT_HEIGHT);
    }

    /** update the offscreen image */
    public void updateScoreImage() {
	Graphics g = scoreImage.getGraphics();
	g.setColor(Color.black);
	g.fillRect(0, 0, SCORE_WIDTH, SCORE_HEIGHT);


	//DebugStr("score: " + score);
	int tenthousands = score / 10000;
	//DebugStr("10000: " + tenthousands);

	int thousands = (score - (tenthousands * 10000)) / 1000;
	//DebugStr("1000: " + thousands);

	int hundreds = score - (tenthousands * 10000);
	hundreds -= thousands * 1000;
	hundreds /= 100;
	//DebugStr("100: " + hundreds);

	int tens = score - (tenthousands * 10000);
	tens -= thousands * 1000;
	tens -= hundreds * 100;
	tens /= 10;
	//DebugStr("10: " + tens);

	int ones = score - (tenthousands * 10000);
	ones -= thousands * 1000;
	ones -= hundreds * 100;
	ones -= tens * 10;

	//DebugStr("1: " + ones);

	int imageLeft = 0;
	int imageWidth = 0;

	imageLeft = SCORE_WIDTH - (numWidth + 5);
	imageWidth = num[ones].getWidth(null);
	g.drawImage(num[ones], (imageLeft + numWidth) - imageWidth, 0, null);

	imageLeft -= numWidth;
	imageWidth = num[tens].getWidth(null);
	g.drawImage(num[tens], (imageLeft + numWidth) - imageWidth, 0, null);

	imageLeft -= numWidth;
	imageWidth = num[hundreds].getWidth(null);
	g.drawImage(num[hundreds], (imageLeft + numWidth) - imageWidth, 0, null);

	imageLeft -= numWidth;
	imageWidth = num[thousands].getWidth(null);
	g.drawImage(num[thousands], (imageLeft + numWidth) - imageWidth, 0, null);

	imageLeft -= numWidth;
	imageWidth = num[tenthousands].getWidth(null);
	g.drawImage(num[tenthousands], (imageLeft + numWidth) - imageWidth, 0, null);


	g.dispose();
    }

    /** update the offscreen image */
    public void updateTilesLeftImage() {
	Graphics g = tilesLeftImage.getGraphics();
	g.setColor(Color.black);
	g.fillRect(0, 0, TILESLEFT_WIDTH, TILESLEFT_HEIGHT);

	int hundreds = tilesLeft / 100;

	int tens = tilesLeft - (hundreds * 100);
	tens /= 10;

	int ones = tilesLeft - (hundreds * 100);
	ones -= tens * 10;

	int imageLeft = 0;
	int imageWidth = 0;

	imageLeft = TILESLEFT_WIDTH - (numWidth + 5);
	imageWidth = num[ones].getWidth(null);
	g.drawImage(num[ones], (imageLeft + numWidth) - imageWidth, 0, null);

	imageLeft -= numWidth;
	imageWidth = num[tens].getWidth(null);
	g.drawImage(num[tens], (imageLeft + numWidth) - imageWidth, 0, null);

	imageLeft -= numWidth;
	imageWidth = num[hundreds].getWidth(null);
	g.drawImage(num[hundreds], (imageLeft + numWidth) - imageWidth, 0, null);

	g.dispose();
    }

    /** update the offscreen image */
    public void updateRackImage() {
	Graphics g = rackImage.getGraphics();
	g.setColor(hilite);
	g.fillRect(0, 0, RACK_WIDTH, RACK_HEIGHT);
	Bevel.drawWindowBorder(g, 0, 0, RACK_WIDTH, RACK_HEIGHT);
	g.setFont(font);
	FontMetrics fm = g.getFontMetrics(font);

	char rackLetters[] = rack.getLetters();
	for (int i = 0 ; i < Rack.NUM_LETTERS ; i++) {
	    if (rackLetters[i] == (char)-1) {
		g.setColor(hilite);
		Bevel.drawFieldBorder(g, ((TILE_SIZE+5)*i)+5, 5, TILE_SIZE, TILE_SIZE);
	    }
	    else {
		g.setColor(background);
		g.fillRect(((TILE_SIZE+5)*i)+5, 5, TILE_SIZE, TILE_SIZE);
		Bevel.drawWindowBorder(g, ((TILE_SIZE+5)*i)+5, 5, TILE_SIZE, TILE_SIZE);
		char c[] = {rackLetters[i]};
		String s = new String(c);
		int strW = fm.stringWidth(s);
		int ly = 5 + (TILE_SIZE/2);
		ly += fm.getHeight()/2 ;
		ly -= 5;
	
		g.setColor(foreground);
		g.drawString(s, (((TILE_SIZE+5)*i)+5) + ((TILE_SIZE/2)-(strW/2)), ly);

	    }
	}
	g.dispose();
    }

    /** update the offscreen image */
    public void updateLetterImage(char letter) {
	Graphics g = letterImage.getGraphics();
	g.setFont(font);
	FontMetrics fm = g.getFontMetrics(font);

	g.setColor(background);
	g.fillRect(0, 0, TILE_SIZE, TILE_SIZE);
	Bevel.drawWindowBorder(g, 0, 0, TILE_SIZE, TILE_SIZE);
	char c[] = {letter};
	String s = new String(c);
	int strW = fm.stringWidth(s);
	int ly = TILE_SIZE/2;
	ly += fm.getHeight()/2 ;
	ly -= 5;
	
	g.setColor(foreground);
	g.drawString(s, (TILE_SIZE/2)-(strW/2), ly);

	g.dispose();

	//---- DARKER IMAGE
	g = darkLetterImage.getGraphics();
	g.setFont(font);
	fm = g.getFontMetrics(font);

	g.setColor(background.darker());
	g.fillRect(0, 0, TILE_SIZE, TILE_SIZE);
	Bevel.drawWindowBorder(g, 0, 0, TILE_SIZE, TILE_SIZE);
	
	g.setColor(foreground);
	g.drawString(s, (TILE_SIZE/2)-(strW/2), ly);

	g.dispose();

    }

    /** update the offscreen image */
    public void updateTilesImage() {
	updateTilesImage((char)-2);
    }

    /** update the offscreen image */
    public void updateTilesImage(char hiliteChar) {
	Graphics g = tilesImage.getGraphics();
	
	g.setFont(font);
	FontMetrics fm = g.getFontMetrics(font);

	//g.setColor(hilite);
	g.setColor(Color.black);
	g.fillRect(0, 0, TILE_SIZE*TILES_WIDE, TILE_SIZE*TILES_HIGH);

	int imgHeight = TILES_HIGH*TILE_SIZE;
	for (int i = 0 ; i < TILES_WIDE ; i++) {
	    for (int j = 0 ; j < TILES_HIGH ; j++) {
		if (letters[i][j] != (char)-1) {
		    if (letters[i][j] == hiliteChar)
			g.setColor(background.darker());
		    else 
			g.setColor(background);
		    g.fillRect(i*TILE_SIZE, imgHeight-((j+1)*TILE_SIZE), TILE_SIZE, TILE_SIZE);
		    Bevel.drawWindowBorder(g, i*TILE_SIZE, imgHeight-((j+1)*TILE_SIZE), TILE_SIZE, TILE_SIZE);
		    char c[] = {letters[i][j]};
		    String s = new String(c);
		    int strW = fm.stringWidth(s);
		    int ly = imgHeight-((j*TILE_SIZE) + (TILE_SIZE/2));
		    ly += fm.getHeight()/2 ;
		    ly -= 5;

		    g.setColor(foreground);
		    g.drawString(s, (i*TILE_SIZE) + ((TILE_SIZE/2)-(strW/2)), ly);
		}
	    }
	}
	g.dispose();
    }


    /**
      * paint
      */
    public void paint(Graphics g, int x, int y, int w, int h) {

	super.paint(g, x, y, w, h);

	g.drawImage(tilesImage, BORDER_H, height-((TILES_HIGH*TILE_SIZE)+BORDER_V), this);
	g.drawImage(rackImage, RACK_LEFT, RACK_TOP, this);
	g.drawImage(scoreImage, (width-BORDER_H)-SCORE_WIDTH, SCORE_TOP, this);
	g.drawImage(tilesLeftImage, BORDER_H, TILESLEFT_TOP, this);

	if (dragging != (char)-1) {
	    if (inRack(draggingX, draggingY)) {
		g.drawImage(darkLetterImage, draggingX-(TILE_SIZE/2), draggingY-(TILE_SIZE/2), this);
	    }
	    else {
		g.drawImage(letterImage, draggingX-(TILE_SIZE/2), draggingY-(TILE_SIZE/2), this);
	    }
	}

	// for debugging
	//g.drawRect(x, y, w-1, h-1);
    }

    /**
      * paint
      */
    public void paint(Graphics g) {
	super.paint(g);

	g.drawImage(tilesImage, BORDER_H, height-((TILES_HIGH*TILE_SIZE)+BORDER_V), this);
	g.drawImage(rackImage, RACK_LEFT, RACK_TOP, this);
	g.drawImage(scoreImage, (width-BORDER_H)-SCORE_WIDTH, SCORE_TOP, this);
	g.drawImage(tilesLeftImage, BORDER_H, TILESLEFT_TOP, this);

	if (dragging != (char)-1) {
	    if (inRack(draggingX, draggingY)) {
		g.drawImage(darkLetterImage, draggingX-(TILE_SIZE/2), draggingY-(TILE_SIZE/2), this);
	    }
	    else {
		g.drawImage(letterImage, draggingX-(TILE_SIZE/2), draggingY-(TILE_SIZE/2), this);
	    }
	}
    }

    /* clip painting to tile area */
    public void repaintRack() {
	repaint(RACK_LEFT, RACK_TOP, RACK_WIDTH, RACK_HEIGHT);
    }

    /* clip painting to tiles left area */
    public void repaintTilesLeft() {
	repaint(TILESLEFT_LEFT, TILESLEFT_TOP, TILESLEFT_WIDTH, TILESLEFT_HEIGHT);
    }


    public void newGame() {
	blockInput = false;

	WindowWidget ww = (WindowWidget)getWidget("okmessage");
	ww.hide();

	ww = (WindowWidget)getWidget("badwordmsg");
	ww.hide();

	score = 0;

	// clear
	for (int i = 0 ; i < TILES_WIDE ; i++) {
	    for (int j = 0 ; j < TILES_HIGH ; j++) {
		letters[i][j] = (char)-1;
	    }
	}
	
	tilesLeft = 0;
	for (int i = 0 ; i < TILES_WIDE ; i++) {
	    int maxj = TILES_HIGH-3 + random(4);
	    //int maxj = TILES_HIGH;
	    for (int j = 0 ; j < maxj ; j++) {
		letters[i][j] = letterPool[random(letterPool.length)];
		tilesLeft++;
	    }
	}

	updateTilesImage();
	updateTilesLeftImage();

	rack.reset();
	updateRackImage();

	updateScoreImage();

	CommandButtonWidget cbw = (CommandButtonWidget)getWidget("checkButton");
	cbw.disable();
	cbw = (CommandButtonWidget)getWidget("clearButton");
	cbw.disable();
	
	repaint();
    }


    /** clicked in tile area */
    public void mouseDownInTiles(int x, int y) {
	int i = (x-BORDER_H) / TILE_SIZE;
	int j = height-(y+BORDER_V);
	j /= TILE_SIZE;
	if (letters[i][j] == (char)-1) {
	    dragging = (char)-1;
	    return;
	}

	if (j != TILES_HIGH-1 && letters[i][j+1]!=(char)-1) {
	    dragging = (char)-1;
	    return;
	}

	dragging = letters[i][j];
	originX = i;
	originY = j;
	removeTile(i, j);

	updateLetterImage(dragging);


	repaint();
    }



    /** remove single title */
    public void removeTile(int i, int j) {
	letters[i][j] = (char)-1;
	tilesLeft--;

	Graphics g = tilesImage.getGraphics();
	//g.setColor(hilite);
	g.setColor(Color.black);
	g.fillRect(i*TILE_SIZE, (TILE_SIZE*TILES_HIGH)-((j+1)*TILE_SIZE), TILE_SIZE, TILE_SIZE);
	g.dispose();

	repaint(i*TILE_SIZE, (TILE_SIZE*TILES_HIGH)-((j+1)*TILE_SIZE), TILE_SIZE, TILE_SIZE);


    }


    /** place tile where it belongs */
    public void addTile(int i, int j, char letter) {
	letters[i][j] = letter;
	tilesLeft++;
	
	int imgHeight = TILES_HIGH*TILE_SIZE;

	Graphics g = tilesImage.getGraphics();

	g.setFont(font);
	FontMetrics fm = g.getFontMetrics(font);

	g.setColor(background);
	g.fillRect(i*TILE_SIZE, imgHeight-((j+1)*TILE_SIZE), TILE_SIZE, TILE_SIZE);
	Bevel.drawWindowBorder(g, i*TILE_SIZE, imgHeight-((j+1)*TILE_SIZE), TILE_SIZE, TILE_SIZE);
	char c[] = {letters[i][j]};
	String s = new String(c);
	int strW = fm.stringWidth(s);
	int ly = imgHeight-((j*TILE_SIZE) + (TILE_SIZE/2));
	ly += fm.getHeight()/2 ;
	ly -= 5;
	
	g.setColor(foreground);
	g.drawString(s, (i*TILE_SIZE) + ((TILE_SIZE/2)-(strW/2)), ly);

	g.dispose();
	repaint(i*TILE_SIZE, (TILE_SIZE*TILES_HIGH)-((j+1)*TILE_SIZE), TILE_SIZE, TILE_SIZE);
    }


    /** disable everything */
    public void startDialog() {
	blockInput = true;
	updateButtons();
    }

    /** disable everything */
    public void endDialog() {
	blockInput = false;
	updateButtons();
    }


    public void updateButtons() {
	if (blockInput == true) {
	    CommandButtonWidget cbw = (CommandButtonWidget)getWidget("checkButton");
	    cbw.disable();
	    cbw = (CommandButtonWidget)getWidget("clearButton");
	    cbw.disable();
	    return;
	}

	CommandButtonWidget cbw = (CommandButtonWidget)getWidget("checkButton");
	if (rack.numTilesUsed() < 3) {
	    cbw.disable();
	}
	else {
	    cbw.enable();
	}

	cbw = (CommandButtonWidget)getWidget("clearButton");
	if (rack.numTilesUsed() == 0) {
	    cbw.disable();
	}
	else {
	    cbw.enable();
	}
    }


    public void checkForWin() {
	if (tilesLeft > 2)
	    return;

	try {
	    int place = -1;
	    if ((place = highScores.place(score, HighScoreManager.LOCAL)) != -1) {
		new HighScoreFrame(getFrame(),
				   new URL(getPresentation().getBase(),"highscore.gui"),
				   highScores,
				   score,
				   getPresentation()).show();
	    }	
	    else {
		new PlayerDialog(getFrame(),
				 new URL(getPresentation().getBase(),
					 "youwon.gui")).show();
	    }	
	} catch (MalformedURLException e) {
	    e.printStackTrace();
	}
    }


    /**
     * Event handler for Window Management events: Asks for the
     * channel to be stopped (and soon destroyed) when the presentation
     * is closed.
     */
    public boolean handleEvent(Event evt) {
	switch (evt.id) {

	  case Event.ACTION_EVENT:
	    if (evt.target instanceof CommandButtonWidget) {
		CommandButtonWidget button = (CommandButtonWidget)evt.target;
		if ("clear".equalsIgnoreCase(button.getLabel())) {
		    //startDialog();
		    //WindowWidget ww = (WindowWidget)getWidget("okmessage");
		    //ww.show();
		    int i = 0;
		    while ((i = rack.numTilesUsed()) != 0) {
			char letter = rack.getLetter(i-1);
			int origX = rack.getOriginX(i-1);
			int origY = rack.getOriginY(i-1);
			rack.removeTile(i-1);
			addTile(origX, origY, letter);
		    }
		    
		    updateRackImage();
		    updateTilesLeftImage();
		    updateButtons();
		    repaint();
		}
		else if ("check".equalsIgnoreCase(button.getLabel())) {
		    if (dict == null) {
			dict = new Dict();
		    }

		    if (dict.checkWord(rack.getWord())) {
			int i = rack.numTilesUsed();
			score += (int)Math.pow(2.0, (double)i);
			updateScoreImage();
			rack.clear();
			updateRackImage();
			updateButtons();
			repaint();

			checkForWin();

		    }
		    else {
			startDialog();
			WindowWidget ww = (WindowWidget)getWidget("badwordmsg");
			RichTextBoxWidget rtbw = (RichTextBoxWidget)ww.getWidget("msg");
			rtbw.setText(rack.getWord() + " is not in the dictionary.");
			ww.show();
		    }
		}
		else if ("tester".equalsIgnoreCase(button.getName())) {
		    DebugStr("tester");
		    //score += random(1000);
		    //updateScoreImage();
		    //repaint();
		}
		else if ("okmessage_ok".equalsIgnoreCase(button.getName())) {
		    WindowWidget ww = (WindowWidget)getWidget("okmessage");
		    ww.hide();
		    endDialog();
		}
		else if ("badwordmsg_override".equalsIgnoreCase(button.getName())) {
		    //int i = rack.numTilesUsed();
		    //score += (int)Math.pow(2.0, (double)i.0);
		    //updateScoreImage();

		    WindowWidget ww = (WindowWidget)getWidget("badwordmsg");
		    ww.hide();
		    endDialog();
		    rack.clear();
		    updateRackImage();
		    updateButtons();

		    repaint();
		    checkForWin();
		}
		else if ("badwordmsg_cancel".equalsIgnoreCase(button.getName())) {
		    WindowWidget ww = (WindowWidget)getWidget("badwordmsg");
		    ww.hide();
		    endDialog();
		}
	    }

	    break;

	  case Event.MOUSE_DOWN:
	    requestFocus();
	    if (blockInput == true) {
		return(true);
	    }

	    
	    if (evt.y > (height-((TILES_HIGH*TILE_SIZE)+BORDER_V))) {
		if (evt.x > BORDER_H && (evt.x < width-(BORDER_H*2))) {
		    if (evt.clickCount == 2) {
			int i = (evt.x-BORDER_H) / TILE_SIZE;
			int j = height-(evt.y+BORDER_V);
			j /= TILE_SIZE;

			if (originX == i && originY == j) {
			    if (letters[i][j] != (char)-1) { 
				if (rack.getNextAvailable() != (char)-1) {
				    rack.addTile(originX, originY, letters[i][j]);
				    updateRackImage();
				    removeTile(i, j);
				    updateTilesLeftImage();
				    updateButtons();
				    repaint();
				    return(true);
				}
			    }
			}
		    }

		    draggingX = evt.x;
		    draggingY = evt.y;
		    lastLeft = draggingX-(TILE_SIZE/2);	
		    lastTop = draggingY-(TILE_SIZE/2);
		    lastRight = lastLeft + TILE_SIZE;
		    lastBottom = lastTop + TILE_SIZE;
		    mouseDownInTiles(evt.x, evt.y);
		}
	    }
	    else {
		int xx = inRackTile(evt.x, evt.y);
		if (xx != -1) {
		    if (rack.tileAvailableForMoving(xx)) {
			dragging = rack.getLetter(xx);
			originX = rack.getOriginX(xx);
			originY = rack.getOriginY(xx);

			rack.removeTile(xx);
			updateRackImage();

			draggingX = evt.x;
			draggingY = evt.y;
			lastLeft = draggingX-(TILE_SIZE/2);	
			lastTop = draggingY-(TILE_SIZE/2);
			lastRight = lastLeft + TILE_SIZE;
			lastBottom = lastTop + TILE_SIZE;

			repaint();
		    }
		}
	    }

	    return true;

	  case Event.MOUSE_DRAG:
	    if (blockInput==false &&  dragging != (char)-1) {
		draggingX = evt.x;
		draggingY = evt.y;

		int newLeft = draggingX-(TILE_SIZE/2);	
		int newRight = newLeft + TILE_SIZE;
		int newTop = draggingY-(TILE_SIZE/2);
		int newBottom = newTop + TILE_SIZE;

		int clipLeft = (newLeft<lastLeft)?newLeft:lastLeft;
		int clipTop = (newTop<lastTop)?newTop:lastTop;
		int clipRight = (newRight>lastRight)?newRight:lastRight;
		int clipBottom = (newBottom>lastBottom)?newBottom:lastBottom;

		int clipWidth = clipRight-clipLeft;
		int clipHeight = clipBottom-clipTop;

		repaint(clipLeft, clipTop, clipWidth, clipHeight);

		lastLeft = newLeft;
		lastTop = newTop;
		lastRight = lastLeft + TILE_SIZE;
		lastBottom = lastTop + TILE_SIZE;
	    }
	    return true;

	  case Event.MOUSE_UP:
	    if (dragging != (char)-1) {
		if (inRack(evt.x, evt.y)) {
		    rack.addTile(originX, originY, dragging);
		    updateRackImage();
		    updateTilesLeftImage();
		}
		else {
		    addTile(originX, originY, dragging);
		    updateTilesLeftImage();
		}
		updateButtons();

		dragging = (char)-1;
		repaint();
	    }
	    return true;

	  case Event.KEY_PRESS:
	    if (keyTrack == false) {
		char c = (char)evt.key;
		if (c>='a'&& x<='z') {
		    c -= 32;
		}
		if (c>='A'&& x<='Z') {
		    updateTilesImage(c);
		    keyTrack = true;
		    repaint();
		}
	    }
	    break;

	  case Event.KEY_RELEASE:
	    if (keyTrack == true) {
		updateTilesImage();
		keyTrack = false;
		repaint();
	    }
	    break;
	}
	return super.handleEvent(evt);
    }



    public boolean inRack(int x, int y) {
	if (x > RACK_LEFT && x < RACK_LEFT+RACK_WIDTH) {
	    if (y > RACK_TOP && y < RACK_TOP+RACK_HEIGHT) {
		if (rack.getNextAvailable() != (char)-1) {
		    return(true);
		}
	    }
	}
	return(false);
    }


    public int inRackTile(int x, int y) {
	if (x < RACK_LEFT || x > RACK_LEFT+RACK_WIDTH) {
	    return -1;
	}
	if (y < RACK_TOP+5 || y > RACK_TOP+(RACK_HEIGHT-5)) {
	    return -1;
	}

	int xx = x;
        xx -= RACK_LEFT;
	xx /= (TILE_SIZE+5);
	if ((x-(xx*(TILE_SIZE+5))) < 5) {
	    return -1;
	}

	if (xx >= Rack.NUM_LETTERS)
	    return -1;

	//DebugStr(""+x + " / " + xx);

	return(xx);
    }

    /**
     * returns random number between 0 and max-1
     */
    private int random(int max) {
	return (int)Math.floor(Math.random() * max);
    }

    /**
     * loops around until it gets to a frame
     */
    private Frame getFrame() {
	Component p = (Component)getPlayerPanel();
	while (!(p instanceof Frame))
	    p = p.getParent();
	return((Frame)p);
    }

    /**
     * for debugging
     */
    public void DebugStr(String s) {
        System.out.println(this.getClass().getName() + ": " + s);
	System.out.flush();
    }

}

