// 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/
/* Uh, Rocks! */
package com.danger.rocks;

import danger.app.*;
import danger.audio.*;
import danger.ui.*;
import danger.util.*;
import danger.util.format.StringFormat;
import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.ListIterator;


class RockWindow extends ScreenWindow
{
	//~ Static fields/initializers ---------------------------------------------

	// constants
	static final int   INTRO_SCREEN		    = 0;
	static final int   BUILDING_SCREEN	    = 1;
	static final int   IN_GAME_SCREEN	    = 2;
	static final int   INITIAL_ROCKS	    = 3;
	static final int   MAX_ROCKS		    = 8;
	static final int   MAX_MISSILES		    = 5; // max number of missiles in the air
	static final int   MAX_HERO_MISSILES    = 5;
	static final int   WAIT_TIME_ANTAGONIST = 50;
	static final int   ANNOUNCE_DELTA	    = 15;
	static final int   ANNOUNCE_DELTA_MID   = 10;
	static final int   ANNOUNCE_WAIT_TIME   = 10;
	static final int[] sPlayfields		    = 
		{
			Resources.ID_playfield1, Resources.ID_playfield2,
			Resources.ID_playfield3, Resources.ID_playfield4,
			Resources.ID_playfield6, Resources.ID_playfield7,
			Resources.ID_playfield8, Resources.ID_playfield9,
			Resources.ID_playfield10, 0
		};

	//~ Instance fields --------------------------------------------------------

	Font			 mFont;
	int				 mFontLineHeight;
	Font			 mFontOutline;
	int				 mFontOutlineLineHeight;
	Rect			 mBounds;
	int				 mHeight;
	int				 mWidth;
	int				 mLevel;
	int				 mScore;
	int				 mExtraLife;
	int				 mLives;
	byte[]			 mTextBuffer				 = new byte[50];
	boolean			 mShowCredits;
	boolean			 mBitmapsReady;
	WeakReference    mIntroBitmap;
	Bitmap			 mPlayfield;
	Bitmap[]		 mCorners					 = { null, null, null, null };
	Bitmap			 mAnnounce;
	int				 mAnnouncer;
	int				 mAnnounceX;
	int				 mAnnounceWait;
	String			 mAnnounceString;
	int				 mAnnounceCount;
	Bitmap[]		 mLivesBitmap				 = { null, null, null, null, null, null };
	Bitmap[]		 mHealthBitmap				 = { null, null, null, null };
	boolean			 mObjectsReady				 = false;
	boolean			 mAutoFire;
	int				 mAutoFireTimer;
	int				 mAntagonistAutoFireTimer;
	int				 mAntagonistLastTimeOnScreen;
	int				 mAntogonistAltScore;
	int				 mAltLives;
	int				 mTimeBetweenShots;
	int				 mLastShot;
	int				 mGameState					 = INTRO_SCREEN;
	int				 mPlayfieldID;
	int				 mPlayfieldOsc;
	int				 mWheelRotationDirection     = 1;
	int				 mResetGameTimer			 = 0;
	LinkedList		 mRocksList; /*RockObject*/
	HeroObject		 mHero						 = null;
	AntagonistObject mAntagonist				 = null;
	int				 mCurrentMissle				 = 0;
	MissileObject[]  mMissiles					 = 
		{
			null, null, null, null, null, null, null, null, null, null
		};

	//~ Constructors -----------------------------------------------------------

	//*	--------------------	RockWindow
	public RockWindow()
	{
		adjustActionMenuState();

		mBounds     = getBounds();
		mHeight     = mBounds.getHeight();
		mWidth	    = mBounds.getWidth();

		mFont					   = Font.findBoldSystemFont();
		mFontLineHeight			   = mFont.getAscent();
		mFontOutline			   = Font.findBoldOutlineSystemFont();
		mFontOutlineLineHeight     = mFontOutline.getAscent();

		mGameState		  = INTRO_SCREEN;
		mPlayfieldID	  = 0;
		mPlayfieldOsc     = 0;
	}

	//~ Methods ----------------------------------------------------------------

	void NewPlayfield()
	{
		if (rocks.sIsColor == true)
		{
			mPlayfieldOsc++;

			if (mPlayfieldOsc > 2)
			{
				mPlayfieldOsc = 0;
				mPlayfieldID++;

				if (sPlayfields[mPlayfieldID] == 0)
				{
					mPlayfieldID = 0;
				}
			}

			loadPlayfield();
		}
	}

	private void loadPlayfield()
	{
		mPlayfield     = null;

		//		mPlayfield = rocks.mMe.getBitmap(sPlayfields[mPlayfieldID]);
		mPlayfield = getJpegImage(sPlayfields[mPlayfieldID]);

		if (mPlayfield != null)
		{
			mPlayfield = mPlayfield.scaleTo(mWidth, mHeight);
		}
	}

	private Bitmap getJpegImage(int resourceID)
	{
		Resource data  = rocks.mMe.getResource(2000, resourceID);
		Bitmap   image = null;

		//	System.out.println("trying to decode image " + resourceID);
		if (data != null)
		{
			int    size  = data.getSize();
			byte[] bytes = new byte[size];

			if (bytes != null)
			{
				data.getBytes(bytes, 0, size);

				try
				{
					image = Bitmap.newFromJPEGData(bytes);
				}
				catch (Exception x)
				{
					System.out.println("failed to decode jpeg");
				}

				if (image != null)
				{
					// convert to screen space, because decoding jpeg during frame kills our speed
					image = Bitmap.convertToScreenColorSpace(image);
				}
			}
		}
		else
		{
			System.out.println("No resource " + resourceID);
		}

		return image;
	}

	void loadIntroBitmap()
	{
		// scale sprite based upon screen width, but constrain it
		Bitmap b = rocks.mMe.getBitmap(Resources.ID_IntroPage);
		int w = b.getWidth();
		int h = b.getHeight();

		w = (mWidth * w) / 240;
		h = (mWidth * h) / 240;

		b = b.scaleTo(w, h);
		mIntroBitmap     = new WeakReference(b);
	}

	// load bitmaps
	void loadBitmaps()
	{
		int count;

		if (mBitmapsReady == false)
		{
			if (rocks.sIsColor == true)
			{
				loadPlayfield();
			}

			loadIntroBitmap();

			mAnnounce = rocks.mMe.getBitmap(Resources.ID_announce);

			for (count = 0; count < 4; count++)
			{
				mCorners[count]     = rocks.mMe.getBitmap(Resources.ID_display_corner_f01 +
						count);
				mHealthBitmap[count] = rocks.mMe.getBitmap(Resources.ID_health_f01 +
						count);
			}

			for (count = 0; count < 6; count++)
			{
				mLivesBitmap[count] = rocks.mMe.getBitmap(Resources.ID_lives_f01 +
						count);
			}

			mBitmapsReady = true;
		}
	}

	void freeBitmaps()
	{
		int count;

		mIntroBitmap     = null;
		mPlayfield		 = null;
		mAnnounce		 = null;

		for (count = 0; count < 4; count++)
		{
			mCorners[count]			 = null;
			mHealthBitmap[count]     = null;
		}

		for (count = 0; count < 6; count++)
		{
			mLivesBitmap[count] = null;
		}

		mBitmapsReady = false;
	}

	final void BuildWorld()
	{
		int rockCount;

		mObjectsReady = false;

		RockImage.setupRockImages();

		int ex    = mBounds.getWidth();
		int ey = mBounds.getHeight();
		rockCount = INITIAL_ROCKS + (mLevel / 3);

		if (rockCount > MAX_ROCKS)
		{
			rockCount = MAX_ROCKS;
		}

		for (int count = 0; count < rockCount; count++)
		{
			int angle = rocks.mRandom.nextInt(360);

			if (((angle / 90) * 90) == angle)
			{
				angle = angle + 3; // don't allow 90 degrees
			}

			mRocksList.add(new RockObject((ex + rocks.mRandom.nextInt(21)) -
					10, (ey + rocks.mRandom.nextInt(21)) - 10, angle,
					(Fixed.fromInt(1) + rocks.mRandom.nextInt(0x7001)) -
					0x1000, mBounds,
					RockImage.getRockImage(RockImage.ROCK_LARGE)));
		}

		mObjectsReady = true;
	}

	void ClearMissiles()
	{
		for (int count = 0; count < MAX_MISSILES; count++)
		{
			mMissiles[count] = null;
		}

		mCurrentMissle = 0;
	}

	public void adjustActionMenuState()
	{
		adjustActionMenuState(getActionMenu());
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param menu DOCUMENT ME!
	 */
	public void adjustActionMenuState(Menu menu)
	{
		menu.removeAllItems();

		if (mGameState != INTRO_SCREEN)
		{
			menu.addItem(RockStrings.kStr_ResumeGame, rocks.kCmd_ResumeGame, 0,
				null, rocks.mMe);

			if (RockAudio.isSoundtrackEnabled())
			{
				menu.addItem(RockStrings.kStr_SoundtrackOff,
					rocks.kCmd_SoundtrackOff, 0, null, rocks.mMe);
			}
			else
			{
				menu.addItem(RockStrings.kStr_SoundtrackOn,
					rocks.kCmd_SoundtrackOn, 0, null, rocks.mMe);
			}

			menu.addDivider();

			menu.addItem(RockStrings.kStr_EndGame, rocks.kCmd_EndGame, 0, null, rocks.mMe);
		}
	}

	//*	--------------------	Paint
	public void Update()
	{
		mHero.update(this);

		if (mAntagonist != null)
		{
			mAntagonist.update(this);
		}
	}

	/*
	public void InvalidateThisRect(Rect r)
	{
	//        Invalidate(r);
	}
	*/
	private void DrawInformationText(Pen inPen)
	{
		int size;

		inPen.setFont(mFontOutline);

		// draw score
		inPen.drawText(10, 15,
			StringFormat.withFormat(RockStrings.kScore, String.valueOf(mScore)));

		switch (mGameState)
		{
			case INTRO_SCREEN:
				inPen.drawText(10, 15 + mFontOutlineLineHeight,
					StringFormat.withFormat(RockStrings.kHighScoreText,
						String.valueOf(rocks.mDS.GetHighScore())));

				break;

			case IN_GAME_SCREEN:

				if (mHero.isActive() == true)
				{
					inPen.drawBitmap(mWidth - 95, 8,
						mHealthBitmap[mHero.mDamage / 25]);
				}

				if (mLives != 0)
				{
					inPen.drawBitmap(mWidth - 52, 8, mLivesBitmap[mLives - 1]);
				}

				/*        if (rocks.mDEBUG == true)
				        {
				                inPen.DrawText(160, 35, "a " + mTimeBetweenShots + " " + mLastShot);
				        }
				*/
				break;
		}
	}

	/**
	 * DOCUMENT ME!
	 */
	public void show()
	{
		loadBitmaps();
		super.show();
	}

	/**
	 * DOCUMENT ME!
	 */
	public void hide()
	{
		super.hide();
		freeBitmaps();
	}

	/**
	 * DOCUMENT ME!
	 */
	public void resume()
	{
	}

	/**
	 * DOCUMENT ME!
	 */
	public void pause()
	{
		mHero.stopThrust();
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param inPen DOCUMENT ME!
	 */
	public void paint(Pen inPen)
	{
		int y;
		int textline;
		int x;
		int screenHeight = mHeight;

		if (mBitmapsReady == true)
		{
			inPen.setColor(Color.BLACK);
			inPen.setTextOutlineColor(mStyle.getColor(
					Style.SPLASH_SCREEN_TEXT_OUTLINE_COLOR));

			switch (mGameState)
			{
				case INTRO_SCREEN:

					inPen.setColor(Color.BLACK);
					inPen.fillRect(getBounds());
					String[] message;
					Bitmap   b = (Bitmap) mIntroBitmap.get();

					if (b == null)
					{
						loadIntroBitmap();
						b = (Bitmap) mIntroBitmap.get();
					}
					screenHeight = b.getHeight();
					inPen.drawBitmap(0, 0, b);

					inPen.setFont(mFontOutline);

					if (mShowCredits == false)
					{
						message = RockStrings.sInstructions;
					}
					else
					{
						message = RockStrings.sCredits;
					}

					y = mFontOutlineLineHeight * 4;

					for (textline = 0; message[textline] != null; textline++)
					{
						inPen.drawText(10, y, message[textline]);
						y += mFontOutlineLineHeight;
					}

					DrawInformationText(inPen);

					break;

				case BUILDING_SCREEN:
					DrawInformationText(inPen);

					break;

				case IN_GAME_SCREEN:
					inPen.setFont(mFont);

					if ((rocks.sIsColor == true) && (mPlayfield != null))
					{
						inPen.drawBitmap(0, 0, mPlayfield);
					}
					else
					{
						clear(inPen);
					}

					if (mObjectsReady)
					{
						int			 count;
						ListIterator iterator;
						RockObject   rock;

						synchronized ( mRocksList ) {
							iterator = mRocksList.listIterator();

							while ( iterator.hasNext() )
							{
								rock = (RockObject) iterator.next();
								if ( rock.draw(inPen) )
									iterator.remove();
							}
						}
						
						for (count = 0; count < MAX_MISSILES; count++)
						{
							if (mMissiles[count] != null)
							{
								if (mMissiles[count].mOrigin == mHero)
								{
									mMissiles[count].draw(inPen, 1);
								}
								else
								{
									mMissiles[count].draw(inPen, 0);
								}
							}
						}

						mHero.draw(inPen);

						if (mAntagonist != null)
						{
							mAntagonist.draw(inPen);
						}
					}

					DrawInformationText(inPen);

					if (mAnnouncer > 0)
					{
						inPen.setFont(mFont);
						inPen.drawBitmap(mAnnounceX, 0, mAnnounce);
						inPen.drawText(mAnnounceX + 55, 18, mAnnounceString);

						if (mAnnouncer < ANNOUNCE_DELTA_MID)
						{
							if (mAnnounceWait > 0)
							{
								mAnnounceWait--;
							}
							else
							{
								mAnnouncer--;
								mAnnounceX += 32;
							}
						}
						else
						{
							mAnnouncer--;
							mAnnounceX += 32;
						}
					}

					break;
			}

			if (rocks.isGamePaused() == true)
			{
				int w = mBounds.getWidth();
				inPen.setFont(mFontOutline);
				y     = (mHeight / 2) - mFontOutlineLineHeight;
				x     = (w - mFontOutline.getWidth(RockStrings.kPaused)) / 2;
				inPen.drawText(x, y, RockStrings.kPaused);

				x = (w - mFontOutline.getWidth(RockStrings.kPressBack)) / 2;
				y += mFontOutlineLineHeight;
				inPen.drawText(x, y, RockStrings.kPressBack);
			}

			// draw corners
			inPen.drawBitmap(0, 0, mCorners[0]);
			inPen.drawBitmap(mWidth - 9, 0, mCorners[1]);
			inPen.drawBitmap(mWidth - 9, screenHeight - 9, mCorners[2]);
			inPen.drawBitmap(0, screenHeight - 9, mCorners[3]);
		}
	}

	void SetScore(int score)
	{
		mScore		   = score;
		mExtraLife     = rocks.EXTRA_LIFE_AT - (mScore % rocks.EXTRA_LIFE_AT);
		mAntogonistAltScore = rocks.ALT_AT - (mScore % rocks.ALT_AT);
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param amount DOCUMENT ME!
	 */
	public void AddToScore(int amount)
	{
		mScore += amount;

		if (rocks.mDS.GetHighScore() < mScore)
		{
			rocks.mDS.SetHighScore(mScore);
		}

		// Add a life if we hit multiple of 30k
		mExtraLife -= amount;

		if (mExtraLife < 0)
		{
			mExtraLife = rocks.EXTRA_LIFE_AT;
			mLives++;

			if (mLives > rocks.MAX_LIVES)
			{
				mLives = rocks.MAX_LIVES;
			}
			else
			{
				RockAudio.extraLife();
			}
		}

		mAntogonistAltScore -= amount;

		if (mAntogonistAltScore < 0)
		{
			mAntogonistAltScore     = rocks.ALT_AT;
			mAltLives			    = 2;
		}
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param announceMe DOCUMENT ME!
	 */
	public void StartAnnouncer(String announceMe)
	{
		mAnnouncer		    = ANNOUNCE_DELTA;
		mAnnounceX		    = -190;
		mAnnounceWait	    = ANNOUNCE_WAIT_TIME;
		mAnnounceString     = announceMe;
	}

	/**
	 * DOCUMENT ME!
	 */
	public void StartAnnouncer()
	{
		mAnnouncer		    = ANNOUNCE_DELTA;
		mAnnounceX		    = -190;
		mAnnounceWait	    = ANNOUNCE_WAIT_TIME;
		mAnnounceString     = RockStrings.sComplete[mAnnounceCount];

		mAnnounceCount++;

		if (RockStrings.sComplete[mAnnounceCount] == null)
		{
			mAnnounceCount = 0;
		}
	}

	/**
	 * DOCUMENT ME!
	 */
	public void StopAnnouncer()
	{
		mAnnouncer = 0;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean IsAntagonistDead()
	{
		if (mAntagonist == null)
		{
			return true;
		}

		return mAntagonist.isDead();
	}

	/**
	 * DOCUMENT ME!
	 */
	public void NewAntagonist()
	{
		if (mAntagonist == null)
		{
			mAntagonist = new AntagonistObject(mBounds);
		}

		if (mAltLives > 0)
		{
			mAltLives--;
			mAntagonist.newLife(true);
		}
		else
		{
			mAntagonist.newLife(false);
		}

		mAntagonistLastTimeOnScreen = WAIT_TIME_ANTAGONIST;
	}

	/**
	 * DOCUMENT ME!
	 */
	public void HitHero()
	{
		if (mHero.hit() == true)
		{
			RockAudio.hitHero();

			if (mLives == 0)
			{
				mHero.kill();
				mResetGameTimer = 60;
				StartAnnouncer(RockStrings.kGameOverMan);
			}
			else
			{
				mHero.newLife();
				mLives--;
			}
		}
	}

	void AntagonistLaunchMissile()
	{
		if (mAntagonist != null)
		{
			if (mAntagonist.isActive())
			{
				RockAudio.fireMissle();

				if (mMissiles[mCurrentMissle] == null)
				{
					mMissiles[mCurrentMissle] = new MissileObject(mBounds);
				}

				// now reset the missile location, angle, and offset by ship size
				// so that it comes out of something graphical. :)
				int cframe = mAntagonist.mMotion.getCurrentFrame();
				int ox = 12;
				int oy = 12;
				mMissiles[mCurrentMissle].create(mAntagonist,
					mAntagonist.mMotion.getX() + ox,
					mAntagonist.mMotion.getY() + oy);

				//		mMissiles[mCurrentMissle].SetAngle(mAntagonist.mMotion.GetAngleFromFrame());
				mMissiles[mCurrentMissle].setAngle(rocks.mRandom.nextInt(360));

				mMissiles[mCurrentMissle].mMotion.setSpeedFromVector(mAntagonist.mMotion);
				mMissiles[mCurrentMissle].mMotion.addSpeed(Fixed.fromInt(7));
				mCurrentMissle = (mCurrentMissle + 1) % MAX_HERO_MISSILES;
			}
		}
	}

	void LaunchMissile()
	{
		if (mHero.isActive())
		{
			RockAudio.fireMissle();

			if (mMissiles[mCurrentMissle] == null)
			{
				mMissiles[mCurrentMissle] = new MissileObject(mBounds);
			}

			// now reset the missile location, angle, and offset by ship size
			// so that it comes out of something graphical. :)
			int cframe = mHero.mMotion.getCurrentFrame();
			int ox = HeroImage.mHeroMissileOffsetX[cframe];
			int oy = HeroImage.mHeroMissileOffsetY[cframe];
			mMissiles[mCurrentMissle].create(mHero, mHero.mMotion.getX() + ox,
				mHero.mMotion.getY() + oy);
			mMissiles[mCurrentMissle].setAngle(mHero.mMotion.getAngleFromFrame());

			mMissiles[mCurrentMissle].mMotion.setSpeedFromVector(mHero.mMotion);
			mMissiles[mCurrentMissle].mMotion.addSpeed(Fixed.fromInt(7));
			mCurrentMissle     = (mCurrentMissle + 1) % MAX_HERO_MISSILES;

			mLastShot = rocks.mGameFrame;
		}
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param inWhichWidget DOCUMENT ME!
	 * @param event DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean eventWidgetHeld(int inWhichWidget, Event event)
	{
		switch (inWhichWidget)
		{
			case Event.DEVICE_WHEEL_BUTTON:
				mAutoFire = true;
				mAutoFireTimer = 0;

				return true;
		}

		return super.eventWidgetHeld(inWhichWidget, event);
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param inWhichWidget DOCUMENT ME!
	 * @param event DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean eventWidgetUp(int inWhichWidget, Event event)
	{
		switch (mGameState)
		{
			case IN_GAME_SCREEN:

				if (mObjectsReady && (rocks.isGamePaused() == false))
				{
					if (mHero.isDead() == false)
					{
						switch (inWhichWidget)
						{
							case Event.DEVICE_BUTTON_LEFT_SHOULDER:
							case Event.DEVICE_BUTTON_RIGHT_SHOULDER:
							case Event.DEVICE_WHEEL_PAGE_DOWN:
							case Event.DEVICE_WHEEL_PAGE_UP:
								return true;

							case Event.DEVICE_WHEEL: // wheel scroll up
								mHero.rotate(mWheelRotationDirection);

								return true;

							case Event.DEVICE_BUTTON_BACK:
								rocks.pauseGame();
								rocks.mMe.returnToLauncher();

								return true;

							case Event.DEVICE_WHEEL_BUTTON:
								mAutoFire = false;
								mAutoFireTimer = 0;

								return true;

							case Event.DEVICE_ARROW_UP_LEFT:
							case Event.DEVICE_ARROW_DOWN_LEFT:
							case Event.DEVICE_ARROW_UP_RIGHT:
							case Event.DEVICE_ARROW_DOWN_RIGHT:
								mHero.stopRotate();
								mHero.stopThrust();

								return true;

							case Event.DEVICE_ARROW_RIGHT:
							case Event.DEVICE_ARROW_LEFT:
								mHero.stopRotate();

								return true;

							case Event.DEVICE_ARROW_DOWN:
							case Event.DEVICE_ARROW_UP:
								mHero.stopThrust();

								return true;
						}
					}
				}
				else
				{
					switch (inWhichWidget)
					{
						case Event.DEVICE_BUTTON_BACK:
						case Event.DEVICE_BUTTON_CANCEL:
							rocks.pauseGame();
							rocks.mMe.returnToLauncher();

							return true;
					}
				}

				break;

			case INTRO_SCREEN:

				switch (inWhichWidget)
				{
					case Event.DEVICE_BUTTON_CANCEL:
					case Event.DEVICE_BUTTON_BACK:
						rocks.mMe.returnToLauncher();

						return true;

					case Event.DEVICE_WHEEL_BUTTON:
						Meta.play(Meta.BEEP_COMMAND_ACCEPTED);
						rocks.mMe.newGame();

						return true;
				}

				break;
		}

		return super.eventWidgetUp(inWhichWidget, event);
	}

	//*	--------------------	eventWidgetDown
	public boolean eventWidgetDown(int inWhichWidget, Event event)
	{
		switch (mGameState)
		{
			case IN_GAME_SCREEN:

				if (mObjectsReady && (rocks.isGamePaused() == false))
				{
					if (mHero.isDead() == false)
					{
						switch (inWhichWidget)
						{
							// trackball events only come as a down
							case -32: //Event.DEVICE_NAVIGATION:

								byte v = (byte) (event.data & 0xff);
								byte h = (byte) ((event.data >> 8) & 0xff);
								mHero.rotate(h - v);

								return true;

							case Event.DEVICE_BUTTON_LEFT_SHOULDER:
							case Event.DEVICE_BUTTON_RIGHT_SHOULDER:
							case Event.DEVICE_WHEEL_PAGE_DOWN:
							case Event.DEVICE_WHEEL_PAGE_UP:
								return true;

							case Event.DEVICE_ARROW_UP_LEFT:
							case Event.DEVICE_ARROW_DOWN_LEFT:
								mHero.startRotate(-1); // left
								mHero.startThrust();

								return true;

							case Event.DEVICE_ARROW_UP_RIGHT:
							case Event.DEVICE_ARROW_DOWN_RIGHT:
								mHero.startRotate(1); // right
								mHero.startThrust();

								return true;

							case Event.DEVICE_ARROW_LEFT:
								mHero.startRotate(-1); // left

								return true;

							case Event.DEVICE_ARROW_RIGHT:
								mHero.startRotate(1); // right

								return true;

							case Event.DEVICE_WHEEL_BUTTON:
								LaunchMissile();

								return true;

							case Event.DEVICE_ARROW_DOWN:
							case Event.DEVICE_ARROW_UP:
								mHero.startThrust();

								return true;

							case Event.DEVICE_WHEEL: // wheel scroll down
								mHero.rotate(mWheelRotationDirection * -1);

								return true;
						}
					}
				}

				break;
		}

		return super.eventWidgetDown(inWhichWidget, event);
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param inKey DOCUMENT ME!
	 * @param event DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean eventKeyDown(char inKey, Event event)
	{
		RockAudio.handleKeys(inKey);
		DebugKeys(inKey);

		if (mObjectsReady && (mHero.isDead() == false))
		{
			switch (inKey)
			{
				case 'i':
					mWheelRotationDirection *= -1;
					Meta.play(Meta.BEEP_COMMAND_ACCEPTED);

					return true;
			}
		}
		else
		{
			switch (inKey)
			{
				case 'a':
					mShowCredits = (mShowCredits) ? false : true;
					Meta.play(Meta.BEEP_COMMAND_ACCEPTED);
					rocks.mWindow.invalidate();

					return true;
			}
		}

		return super.eventKeyDown(inKey, event);
	}

	private void DebugKeys(char inKey)
	{
		if (rocks.mDEBUG == true)
		{
			switch (inKey)
			{
				case 'l':
					SetScore(rocks.EXTRA_LIFE_AT - 200);

					break;

				case 'k':
					HitHero();

					break;

				case 'x':
					SetScore(rocks.ALT_AT - 200);

					break;

				case 's':
					mHero.mShield = 1000;

					break;

				case 'f':
					StartAnnouncer();

					break;

				case 'n':
					NewPlayfield();

					break;

				case 'g':
					rocks.mGOD = (rocks.mGOD == false) ? true : false;
					Meta.play(Meta.BEEP_COMMAND_ACCEPTED);

					break;

				case '1':
					mHero.mHeroImage.mHeroMissileOffsetX[mHero.mMotion.getCurrentFrame()]--;

					break;

				case '2':
					mHero.mHeroImage.mHeroMissileOffsetX[mHero.mMotion.getCurrentFrame()]++;

					break;

				case '3':
					mHero.mHeroImage.mHeroMissileOffsetY[mHero.mMotion.getCurrentFrame()]--;

					break;

				case '4':
					mHero.mHeroImage.mHeroMissileOffsetY[mHero.mMotion.getCurrentFrame()]++;

					break;

				case '5':

					for (int count = 0; count < HeroImage.TOTAL_HERO_FRAMES;
						count++)
					{
						DEBUG.p(count + " " +
							mHero.mHeroImage.mHeroMissileOffsetX[count] + " " +
							mHero.mHeroImage.mHeroMissileOffsetY[count]);
					}

					break;
			}
		}

		switch (inKey)
		{
			case 'd':

				if (rocks.mDEBUG == true)
				{
					rocks.mDEBUG = false;
				}
				else
				{
					rocks.mDEBUG = true;
				}

				Meta.play(Meta.BEEP_COMMAND_ACCEPTED);

				break;
		}
	}
}


class RockUtils
{
	//~ Methods ----------------------------------------------------------------

	/**
	 * DOCUMENT ME!
	 *
	 * @param number DOCUMENT ME!
	 * @param result DOCUMENT ME!
	 * @param startOffset DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public static int ConvertNumberToBytes(int number, byte[] result,
		int startOffset)
	{
		int  r     = 0;
		int  q     = 0;
		int  nn    = number;
		int  count = startOffset;
		byte v;

		do
		{
			r				    = nn % 10;
			nn				    = nn / 10;
			result[count++]     = (byte) (48 + r);
		}
		while (nn > 0);

		result[count] = 0;

		for (nn = 0; nn < (count / 2); nn++)
		{
			v						   = result[nn];
			result[nn]				   = result[count - nn - 1];
			result[count - nn - 1]     = v;
		}

		return count;
	}
}
