/*
 * Board - the PipeDream board
 *
 * by Adam Doppelt
 * http://www.cs.brown.edu/people/amd/
 */
import java.awt.*;
import java.applet.Applet;

public class Board extends MirrorCanvas implements Runnable {
    final static Color BACKGROUND = Color.blue;
    final static Color LINES = Color.white;
    final static int SIZE = 8;
    final static int DIED_DELAY = 2000;

    final static String PRE_MESSAGE = "Click on the board to start playing.";
    final static String FILL_UP = "I hear the water swirling...";    
    final static String PLAYING = "Now, lay pipe for your life!";
    final static String PAUSED = "Paused. It better be important.";
    final static String BETWEEN =
          "You made it! Click to begin the next level.";
    final static String GAME_OVER =
         "Gagging silently, you succumb to the inky depths.";
    final static String NO_IMAGES = "Could not load images!";

    
    final static int PIXELS = SIZE * (Piece.SIZE + 1) + 1;
    
    final static Color MESSAGE_FOREGROUND = Color.white;    
    final static Color MESSAGE_BACKGROUND = Color.black;
    final static int MESSAGE_HEIGHT = 30;

    Replace replace_;
    Thread kicker_;
    Font font_;
    Queue queue_;
    Piece pieces_[][];
    Water water_;

    Piece start_;
    int startRow_, startCol_;

    Applet applet_;
    boolean loaded_, playing_, between_;
    long waterDied_;
    
    public Board(Container container, Applet applet) {
	super(PIXELS, PIXELS + MESSAGE_HEIGHT);
	
	loaded_ = false;
	playing_ = false;
	between_ = false;
	
	new Score(container);
	container.add("Center", this);
	queue_ = new Queue(container);

	applet_ = applet;
	font_ = new Font("TimesRoman", Font.PLAIN, 14);
	loaded_ = true;
	waterDied_ = 0;
    }

    public void paint(Graphics g) {
	if (offscreen_ == null) {
	    super.paint(g);	    
	    String base = applet_.getCodeBase().toString();
	    Slicer slicer = new Slicer(
		applet_, base + "pipes.gif", 2, 4);
	    Image cells[][] = slicer.GetAllCells(true);

	    if (cells == null) {
		applet_.showStatus(NO_IMAGES);
		SetMessage(NO_IMAGES);
		return;
	    }
	
	    StartPiece.SetupStatics(this, cells[0][0]);
	    WEPiece.SetupStatics(this, cells[1][0]);
	    NSPiece.SetupStatics(this, cells[2][0]);
	    NSEWPiece.SetupStatics(this, cells[3][0]);

	    NWPiece.SetupStatics(this, cells[0][1]);
	    NEPiece.SetupStatics(this, cells[1][1]);
	    SEPiece.SetupStatics(this, cells[2][1]);
	    SWPiece.SetupStatics(this, cells[3][1]);

	    start();
	}
	else
	    super.paint(g);
    }
    
    public void StartGame() {
	waterDied_ = 0;	
	Score.Reset();
	NextLevel();
    }
    
    public void NextLevel() {
	Score.AdvanceLevel();
	Clear();
	queue_.ResetQueue();

	startRow_ = (int)(Math.random() * (SIZE - 4)) + 2;
	startCol_ = (int)(Math.random() * (SIZE - 5)) + 2;
	start_ = new StartPiece();
	AddPiece(start_, startRow_, startCol_);
	SetMessage(FILL_UP);
	Flip();

	between_ = false;
	playing_ = true;
	replace_ = null;
	kicker_ = new Thread(this);
	kicker_.start();
    }

    public void run() {
	try {
	    Thread.sleep(Score.GetInitialDelay());
	} catch (InterruptedException e) { ; }
	
	SetMessage(PLAYING);
	kicker_ = null;
 	water_ = new Water(this, start_, startRow_, startCol_);
    }

    public void WaterDied() {
	waterDied_ = System.currentTimeMillis();
	if (replace_ != null) {
	    replace_.stop();
	    replace_ = null;
	}
	water_ = null;
	
	if (Score.EnoughForNext()) {
	    between_ = true;
	    SetMessage(BETWEEN);
	}
	else {
	    playing_ = false;
	    SetMessage(GAME_OVER);
	}
    }
    
    public void start() {
	if (offscreen_ == null)
	    return;
	Clear();
	SetMessage(PRE_MESSAGE);
    }
    
    public void stop() {
	if (kicker_ != null) {
	    kicker_.stop();
	    kicker_ = null;
	}
	if (replace_ != null) {
	    replace_.stop();
	    replace_ = null;
	}
	if (water_ != null) {
	    water_.stop();
	    water_ = null;
	}
	playing_ = false;
    }
    
    public void SetMessage(String message) {
	offscreen_.setFont(font_);
	FontMetrics metrics = getFontMetrics(font_);
	int x = (int)((size().width - metrics.stringWidth(message)) / 2.0);
	int y = (int)((MESSAGE_HEIGHT + metrics.getMaxDescent()) / 2.0);
	offscreen_.setColor(MESSAGE_BACKGROUND);
	offscreen_.fillRect(0, PIXELS, PIXELS, MESSAGE_HEIGHT);
	offscreen_.setColor(MESSAGE_FOREGROUND);
	offscreen_.drawString(message, x, y + PIXELS + 3);
	repaint();
//	onscreen_.drawImage(image_, 0, 0, null);
    }
    
    public void AddPiece(Piece piece, int row, int col) {
	pieces_[row][col] = piece;
	piece.StampAt(offscreen_, col * (Piece.SIZE + 1) + 1,
		      row * (Piece.SIZE + 1) + 1);
	Flip();
    }

    public void ReplaceIt(Piece newPiece, int row, int col) {
	AddPiece(newPiece, row, col);
	replace_ = null;
    }
    
    public void AddPiece(int row, int col) {
	if (replace_ == null) {
	    if (row >= 0 && row < SIZE && col >= 0 && col < SIZE) {
		if (pieces_[row][col] != null) {
		    if (!pieces_[row][col].ContainsWater()) {
			Piece newPiece = queue_.GetNextPiece();
			pieces_[row][col] = null;
			replace_ = new Replace(this, offscreen_, onscreen_,
					       newPiece, row, col);
		    }
		}
		else {
		    Piece newPiece = queue_.GetNextPiece();		    
		    AddPiece(newPiece, row, col);
		}
	    }
	}
    }
    
    public Piece PieceAt(int row, int col) {
	if (row >= 0 && row < SIZE && col >= 0 && col < SIZE)
	    return pieces_[row][col];
	else
	    return null;
    }

    public void DrawWater(Water water) {
	water.Draw(offscreen_);
	water.Draw(onscreen_);
    }
    
    public void Clear() {
	offscreen_.setColor(BACKGROUND);
	offscreen_.fillRect(0, 0, PIXELS, PIXELS);

	offscreen_.setColor(LINES);	
	pieces_ = new Piece[SIZE][SIZE];
	for(int loop = 0; loop < SIZE; ++loop) {
	    offscreen_.drawLine(loop * (Piece.SIZE + 1), 0,
				loop * (Piece.SIZE + 1), PIXELS);
	    offscreen_.drawLine(0, loop * (Piece.SIZE + 1),
				PIXELS, loop * (Piece.SIZE + 1));
	}
	Flip();
    }

    public boolean handleEvent(Event event) {
	if (!loaded_)
	    return false;
	
	if (event.id == Event.MOUSE_UP) {
	    if (playing_) {
		if (between_) {
		    if (System.currentTimeMillis() - waterDied_ > DIED_DELAY)
			NextLevel();
		}
		else {
		    int col = event.x / (Piece.SIZE + 1);
		    int row = event.y / (Piece.SIZE + 1);
		    AddPiece(row, col);
		}
	    }
	    else if (System.currentTimeMillis() - waterDied_ > DIED_DELAY)
		StartGame();
	    return true;
	}
	else
	    return false;
    }
}
