// 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.rocks;

import danger.app.*;
import danger.audio.*;
import danger.system.*;
import danger.ui.*;
import java.util.Random;


/**
 * DOCUMENT ME!
 *
 * @author $author$
 * @version $Revision$
 */
public class AntagonistObject
{
	//~ Static fields/initializers ---------------------------------------------

	private static int LED_TIMER = 15;

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

	// text messages
	private int SPEAK_OFFSET_X = 11;
	private int SPEAK_OFFSET_Y = 2;
	private int mSpeakMsg   = -1;
	private int mSpeakTimer = 0;
	int		    mLEDTimer = LED_TIMER;

	// data
	int			    mAltTimer;
	int			    mDamage;
	int			    mShield;
	int			    mFrameCount;
	Random		    mRandom    = new Random();
	boolean		    mDead;
	int			    mDrawMode;
	int			    mModeTimer = 0;
	int			    mStartX;
	int			    mStartY;
	int			    mStartSpeed;
	int			    mStartAngle;
	int			    mAreaWidth;
	int			    mAreaHeight;
	AntagonistImage mAntagonistImage = null;
	MotionObject    mMotion			 = null;
	Signal		    mMovement		 = null;
	Rect		    mImageRect		 = new Rect();
	Rect		    mBoundRect		 = new Rect();

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

	/**
	 * Creates a new AntagonistObject object.
	 *
	 * @param bounds DOCUMENT ME!
	 */
	public AntagonistObject(Rect bounds)
	{
		int x;
		int y;

		mAntagonistImage     = new AntagonistImage();
		mAreaWidth			 = bounds.getWidth();
		mAreaHeight			 = bounds.getHeight();
		mDrawMode			 = drawmode.DEAD;
		mModeTimer			 = 20;
		newPosition();
		mMotion = new MotionObject(mStartX, mStartY, mStartAngle, mStartSpeed,
				bounds, AntagonistImage.TOTAL_FRAMES, 0,
				mAntagonistImage.getSizeX(), mAntagonistImage.getSizeY());
	}

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

	/**
	 * DOCUMENT ME!
	 *
	 * @param alt DOCUMENT ME!
	 */
	public void newLife(boolean alt)
	{
		if (alt)
		{
			mAntagonistImage.setAlt(true);
		}
		else
		{
			mAntagonistImage.setAlt(false);
		}

		reset();
		RockAudio.Antagonist(true);
		mDrawMode = drawmode.NORMAL;
	}

	/**
	 * DOCUMENT ME!
	 */
	public void kill()
	{
		mDead		  = true;
		mDrawMode     = drawmode.DEAD;
		mLEDTimer     = 1;
		RockAudio.Antagonist(false);
	}

	private void newPosition()
	{
		boolean fromLeft = true;

		if (mAntagonistImage.isAltOn() == false)
		{
			fromLeft = (mRandom.nextInt(101) >= 50);
		}

		if (fromLeft)
		{
			mStartX		    = -20; // starts on the left
			mStartAngle     = (90 + mRandom.nextInt(51)) - 25;
		}
		else
		{
			mStartX		    = mAreaWidth; // starts on the right
			mStartAngle     = (270 + mRandom.nextInt(51)) - 25;
		}

		mStartY		    = ((mAreaHeight / 2) + mRandom.nextInt(21)) - 10;
		mStartSpeed     = 0x30000 + mRandom.nextInt(0x10001) + 0x8000;

		mMovement = new Signal(Signal.kSine, mRandom.nextInt(mAreaWidth + 1),
				0, mAreaWidth, 6, 3);
	}

	/**
	 * DOCUMENT ME!
	 */
	public void reset()
	{
		mDamage     = 0;
		mDead	    = false;
		mAntagonistImage.setCrash(false);
		mDrawMode	   = drawmode.INVISIBLE;
		mModeTimer     = 20;

		newPosition();
		mMotion.setAngle(mStartAngle);
		mMotion.setSpeed(mStartSpeed);
		mMotion.setX(mStartX);
		mMotion.setY(mStartY);
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param inPen DOCUMENT ME!
	 */
	public void draw(Pen inPen)
	{
		if (mAntagonistImage != null)
		{
			boolean draw = true;
			Rect    r = getRect();

			switch (mDrawMode)
			{
				case drawmode.NORMAL:
					draw = true;
					RockAudio.Antagonist(true);
					break;

				case drawmode.DEAD:
					draw = false;

					break;

				case drawmode.INVISIBLE:
					draw = false;

					break;

				case drawmode.BLINK:

					if ((mModeTimer & 2) == 0)
					{
						draw = false;
					}

					break;

				case drawmode.SPIN_CRASH:
					break;
			}

			if (draw == true)
			{
				inPen.setColor(Color.BLACK);
				mAntagonistImage.draw(inPen, mMotion.getX(), mMotion.getY(),
					mMotion.getCurrentFrame());

				if (mShield > 0)
				{
					r.inset(-5);

					if (Screen.isColor())
					{
						int rc = (mFrameCount << 4) & 0xff;
						int gc = (~((mFrameCount << 2) & 0xff)) + 255;
						int bc = (mFrameCount << 5) & 0xff;
						inPen.setColor(Color.pack(rc, gc, bc));
						inPen.drawOval(r);
						inPen.setColor(Color.BLACK);
					}
					else
					{
						inPen.drawOval(r);
					}

					mShield--;
				}

				if (mLEDTimer > 0)
				{
					mLEDTimer--;

					if (mLEDTimer < (LED_TIMER / 2))
					{
						Hardware.setLEDHSV(160, 240, 120);
					}
				}
				else
				{
					mLEDTimer = LED_TIMER;
					Hardware.setLEDHSV(0, 0, 0);
				}

				if (mSpeakTimer > 0)
				{
					mSpeakTimer--;

					if (mSpeakMsg != -1)
					{
						inPen.drawText(mMotion.getX() - SPEAK_OFFSET_X,
							mMotion.getY() - SPEAK_OFFSET_Y,
							RockStrings.sAntagonistSpeak[mSpeakMsg]);
					}
				}
			}

			if (rocks.mDEBUG == true)
			{
				if (r.left > r.right)
				{
					int a = r.left;
					r.left	    = r.right;
					r.right     = a;
				}

				if (r.bottom < r.top)
				{
					int a = r.bottom;
					r.bottom     = r.top;
					r.top		 = a;
				}

				inPen.drawRect(r);
			}
		}
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public Rect getRect()
	{
		mBoundRect = mAntagonistImage.getRectForAntagonist(mMotion.getCurrentFrame());
		mBoundRect.inset(3);
		mBoundRect.translate(mMotion.getX(), mMotion.getY());

		return mBoundRect;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public Rect getImageRect()
	{
		mImageRect = mAntagonistImage.getRectForAntagonist(mMotion.getCurrentFrame());
		mImageRect.translate(mMotion.getX(), mMotion.getY());
		mImageRect.inset(-5);

		return mImageRect;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean isDead()
	{
		if ((mDrawMode == drawmode.DEAD) || (mDrawMode == drawmode.SPIN_CRASH))
		{
			return true;
		}

		return false;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean isActive()
	{
		if (mDrawMode == drawmode.NORMAL)
		{
			return true;
		}

		return false;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean sustainDamage()
	{
		mDamage += 25;

		if (mDamage > 99)
		{
			return false;
		}

		mShield = 6;

		return true;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean hit()
	{
		boolean hit = false;

		if (mDrawMode == drawmode.NORMAL)
		{ // only hurt if we're normal
			mDrawMode	   = drawmode.SPIN_CRASH;
			mModeTimer     = 20;
			hit			   = true;
			mAntagonistImage.setCrash(true);
			RockAudio.Antagonist(false);

			mSpeakTimer = 15;
			mSpeakMsg++;

			if (RockStrings.sAntagonistSpeak[mSpeakMsg] == null)
			{
				mSpeakMsg = 0;
			}
		}

		if (hit)
		{
			RockAudio.hitRock();
		}

		return hit;
	}

	private boolean safeMode()
	{
		if (mDrawMode != drawmode.NORMAL)
		{
			if (mModeTimer < 3)
			{
				mModeTimer = 3;
			}

			return false;
		}

		return true;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param missile DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean collidesWith(MissileObject missile)
	{
		Rect rect = getRect();
		int  x = missile.mMotion.getX();
		int  y = missile.mMotion.getY();

		if (missile.mOrigin != this)
		{
			return rect.contains(x, y);
		}

		return false;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param rock DOCUMENT ME!
	 *
	 * @return DOCUMENT ME!
	 */
	public boolean collidesWith(RockObject rock)
	{
		Rect rockrect = rock.getRect();

		Rect me = getRect();
		me.inset(5);

		boolean hit = me.intersects(rockrect);

		if (rock.isCrashed() == true)
		{
			hit = false;
		}

		if (hit)
		{
			return safeMode();
		}

		return false;
	}

	/**
	 * DOCUMENT ME!
	 *
	 * @param w DOCUMENT ME!
	 */
	public void update(RockWindow w)
	{
		boolean wrap = false;

		mFrameCount++;

		// provide some brains
		if (mDead == false)
		{
			// move
			// invalidate old position
			//w.InvalidateThisRect(getImageRect());
			int vv = mMovement.GetIntValue();
			mMotion.setY(mMotion.getY() + vv);
			wrap = mMotion.Update();

			// invalidate new position
			//w.InvalidateThisRect(getImageRect());
			if (wrap)
			{ // if we've hit the edge, kill the guy
				kill();
			}

			switch (mDrawMode)
			{
				case drawmode.NORMAL:
					break;

				case drawmode.INVISIBLE:
					mModeTimer--;

					if (mModeTimer == 0)
					{
						mDrawMode	   = drawmode.BLINK;
						mModeTimer     = 20;
						mAntagonistImage.setCrash(false);
					}

					break;

				case drawmode.BLINK:
					mModeTimer--;

					if (mModeTimer == 0)
					{
						mDrawMode = drawmode.NORMAL;
					}

					break;

				case drawmode.SPIN_CRASH:
					mModeTimer--;

					if (mModeTimer != 0)
					{
						mMotion.setAngle(mMotion.getAngle() + 10);
					}
					else
					{
						mDrawMode = drawmode.DEAD;
					}

					break;
			}
		}
	}

	//~ Inner Interfaces -------------------------------------------------------

	interface drawmode
	{
		//~ Static fields/initializers -----------------------------------------

		public static final int NORMAL     = 0;
		public static final int SPIN_CRASH = 1;
		public static final int BLINK	   = 2;
		public static final int INVISIBLE  = 3;
		public static final int DEAD	   = 4;
	}
}
