// Copyright 2001-2003, Danger, Inc.  All Rights Reserved.
// This file is subject to the Danger, Inc. Sample Code License,
// which is provided in the file SAMPLE_CODE_LICENSE.
// Copies are also available from http://developer.danger.com/

package com.danger.predictoball;

import danger.app.Event;
import danger.app.ResourceDatabase;
import danger.app.Timer;
import danger.ui.Color;
import danger.ui.Pen;
import danger.ui.Screen;
import danger.ui.ScreenWindow;
import danger.ui.StaticTextBox;
import java.util.Random;

/**
 * The screen that displays the Predictoball. This class handles
 * the bulk of the UI interaction.
 */
public class PredictoballWindow
	extends ScreenWindow
{
	/** in an ideal world, the time between animation frames, in msec */
	static private final int ANIMATION_FRAME_MSEC = 200;

	/** non-null; random number generator used to make predictions */
	private Random mRandom;

	/** non-null; animation timer */
	private Timer mTimer;

	/** whether or not animation is in progress */
	private boolean mAnimating;

	/** current frame of animation */
	private int mFrameNum;

	/** current horizontal ball offset; typically <code>0</code>, may be
	 * non-<code>0</code> while animating */
	private int mBallOffset;

	/** current prediction text background color; typically white, but may
	 * be some other gray while animating */
	private int mTextBackground;

	/** null-ok; the application object; set by {@link #setApp} */
	private Predictoball mApp;

	/** null-ok; the default prediction text (when prompting for a
	 * prediction); set by {@link #setApp} */
	private String mDefaultText;

	/** null-ok; the possible predictions; set by {@link #setApp} */
	private String[] mPredictions;

	/** null-ok; the UI element that holds the prediction */
	private StaticTextBox mPredictionBox;



	// ------------------------------------------------------------------------
	// constructors

	/**
	 * Construct an instance.
	 */
	public PredictoballWindow()
	{
		mRandom = new Random();
		mTimer = new Timer(ANIMATION_FRAME_MSEC, true, this);
		mAnimating = false;
		mFrameNum = 0;
		mBallOffset = 0;
		mTextBackground = Color.GRAY15;
	}



	// ------------------------------------------------------------------------
	// public instance methods

	// standard UI method
	public boolean eventWidgetUp(int inWhichWidget, Event event)
	{
		switch (inWhichWidget) {
			case Hiptop2Events.DEVICE_BUTTON_CANCEL:
			case Event.DEVICE_BUTTON_BACK: {
				mApp.returnToLauncher();
				return true;
			}
		}

		return super.eventWidgetUp(inWhichWidget, event);
	}

	// standard UI method
	public boolean receiveEvent(Event e)
	{
		switch (e.type) {
			case Events.CMD_HELP: {
				mApp.showAlert(Resources.HELP_WINDOW, null);
				return true;
			}
			case Events.CMD_RUN: {
				if (! mAnimating) {
					startAnimating();
				}
				return true;
			}
			case Event.EVENT_TIMER: {
				nextAnimationFrame();
				return true;
			}
		}

		return super.receiveEvent(e);
	}

	// standard UI method
	public void paint(Pen pen)
	{
		int width = Screen.getWidth();
		int height = Screen.getHeight();
		int centerX = width / 2;
		int centerY = height / 2;
		int radius = Math.min(centerX, centerY);

		radius += radius / 10;
		centerX += (radius / 20) * mBallOffset;

		clear(pen);

		// draw the ball
		pen.setColor(Color.GRAY0);
		pen.fillOval(centerX - radius, centerY - radius,
					 centerX + radius, centerY + radius);

		if (mPredictionBox.isVisible()) {
			// draw the background color of the prediction box
			pen.setColor(mTextBackground);
			int left = mPredictionBox.getLeft() + 2;
			int top = mPredictionBox.getTop() + 2;
			int right = mPredictionBox.getRight() - 2;
			int bottom = mPredictionBox.getBottom() - 2;
			pen.fillRect(left, top, right, bottom);
		}

		// paint the children, which will consist of either: nothing,
		// the prediction box, or the prediction box and the "predict!"
		// button
		paintChildren(pen);
	}



	// ------------------------------------------------------------------------
	// package instance methods

	/**
	 * Set the application object, and set up the UI elements.
	 *
	 * @param app non-null; the application object
	 */
	/*package*/ void setApp(Predictoball app)
	{
		mApp = app;

		ResourceDatabase rdb = mApp.getResources();
		mPredictions = rdb.getStringArray(Resources.PREDICTIONS);
		mDefaultText = rdb.getString(Resources.DEFAULT_TEXT);
		mPredictionBox = 
			(StaticTextBox) getChildWithID(Resources.PREDICTION_TEXT);
		mPredictionBox.setTransparent(true);

		setPredictionText(mDefaultText);
	}



	// ------------------------------------------------------------------------
	// private instance methods

	/**
	 * Set the prediction text.
	 *
	 * @param text non-null; the new text
	 */
	private void setPredictionText(String text)
	{
		mPredictionBox.setText(text);
	}

	/**
	 * Set whether or not the prediction button and menu item are enabled.
	 *
	 * @param enabled whether to enable or disable
	 */
	private void setPredictionEnabled(boolean enabled)
	{
		getActionMenu().getItemWithID(Resources.PREDICT_MENU_ITEM)
			.setEnabled(enabled);

		if (enabled) {
			showAllChildren();
			setFocusedChild(getChildWithID(Resources.PREDICT_BUTTON), true);
		}
		else {
			hideAllChildren();
		}
	}

	/**
	 * Start animating. This is also the point at which the new prediction
	 * text is selected.
	 */
	private void startAnimating()
	{
		mFrameNum = -1;
		mAnimating = true;
		setPredictionEnabled(false);

		mRandom.setSeed(mRandom.nextInt(100) + System.currentTimeMillis());
		setPredictionText(mPredictions[mRandom.nextInt(mPredictions.length)]);

		mTimer.start();
	}

	/**
	 * Stop animating, and allow the user to ask for another prediction.
	 */
	private void stopAnimating()
	{
		mTimer.stop();
		mAnimating = false;
		setPredictionEnabled(true);
	}

	/**
	 * Set the state for the next frame of animation.
	 */
	private void nextAnimationFrame()
	{
		mFrameNum++;
		boolean changed = true;

		switch (mFrameNum) {
			case 0: mBallOffset = -1; break;
			case 1: mBallOffset = -2; break;
			case 2: mBallOffset = -1; break;
			case 3: mBallOffset = 0; break;
			case 4: mBallOffset = 1; break;
			case 5: mBallOffset = 2; break;
			case 6: mBallOffset = 1; break;
			case 7: mBallOffset = 0; break;
			case 8: mBallOffset = -1; break;
			case 9: mBallOffset = -2; break;
			case 10: mBallOffset = -1; break;
			case 11: mBallOffset = 0; break;
			case 12: mBallOffset = 1; break;
			case 13: mBallOffset = 2; break;
			case 14: mBallOffset = 1; break;
			case 15: mBallOffset = 0; break;
			case 16: {
				mPredictionBox.show();
				mTextBackground = Color.GRAY3;
				break;
			}
			case 17: mTextBackground = Color.GRAY6; break;
			case 18: mTextBackground = Color.GRAY9; break;
			case 19: mTextBackground = Color.GRAY12; break;
			case 20: mTextBackground = Color.GRAY15; break;
			case 60: mTextBackground = Color.GRAY12; break;
			case 61: mTextBackground = Color.GRAY9; break;
			case 62: mTextBackground = Color.GRAY6; break;
			case 63: mTextBackground = Color.GRAY3; break;
			case 64: {
				mPredictionBox.setText(mDefaultText);
				mTextBackground = Color.GRAY0; 
				break;
			}
			case 65: mTextBackground = Color.GRAY3; break;
			case 66: mTextBackground = Color.GRAY6; break;
			case 67: mTextBackground = Color.GRAY9; break;
			case 68: mTextBackground = Color.GRAY12; break;
			case 69: {
				mTextBackground = Color.GRAY15;
				stopAnimating();
				break;
			}
			default: {
				changed = false;
			}
		}

		if (changed) {
			invalidate();
		}
	}
}
