// 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.ui.*;
import danger.audio.*;
import danger.util.*;

public class MotionObject
{
	public	MotionObject(int x, int y, int angle, int fspeed, Rect bounds,
						int maxFrames, int maxFrameRate, int objectSizeX, int objectSizeY)
	{
		mBounds = bounds;

		// set frames
		mCurrentFrame = 0;
		mMaxFrames = maxFrames;

		// get size, postion properties
		mX = Fixed.fromInt(x);
		mY = Fixed.fromInt(y);
		mSizeX = Fixed.fromInt(objectSizeX);
		mSizeY = Fixed.fromInt(objectSizeY);
		mMaxY = Fixed.fromInt(mBounds.getHeight());
		mMaxX = Fixed.fromInt(mBounds.getWidth());

		// set vector of motion
		setAngle(angle);
		setSpeed(fspeed);

		mUseFrameTimer = true;
		mFrameRateMax = maxFrameRate;
		mFrameTimerCount = 0;
		if (maxFrameRate == 0)
		{
			mUseFrameTimer = false;
		}
	}


	public void setCurrentFrame(int frame)
	{
		mCurrentFrame = frame % mMaxFrames;
	}

	public int getMaxFrames()
	{
		return mMaxFrames;
	}
	public int getCurrentFrame()
	{
		return mCurrentFrame;
	}

	public void setX(int x)
	{
		mX = Fixed.fromInt(x);
	}
	public void setY(int y)
	{
		mY = Fixed.fromInt(y);
	}
	public int getX()
	{
		return Fixed.toInt(mX);
	}
	public int getY()
	{
		return Fixed.toInt(mY);
	}

	// return raw angle
	public int getAngle()
	{
		return mAngle;
	}

	public int getFrameFromAngle()
	{
		int frame = 0;

		if (mMaxFrames != 0)
		{
			int pi = 360 / mMaxFrames;

			if (pi != 0)
			{
				frame = mAngle / pi;
			}
		}
		return frame;
	}

	// return angle, but quantized by number of frames
	public int getAngleFromFrame()
	{
		int newAngle = 0;

		if (mMaxFrames != 0)
		{
			int pi = 360 / mMaxFrames;

			if (pi != 0)
			{
				newAngle = (mAngle / pi) * pi;
			}
		}
		return newAngle;
	}

	public void setAngle(int newAngle)
	{
		mAngle = newAngle % 360;
		if (mAngle < 0)
		{
			mAngle += 360;
		}
		setCurrentFrame(getFrameFromAngle());
	}

	public void addAngle(int newAngle)
	{
		mAngle = (mAngle + newAngle) % 360;
		if (mAngle < 0)
		{
			mAngle += 360;
		}
		setAngle(mAngle);
	}

	public int getSpeed()
	{
		int mx = 0;
		int my = 0;

		// m = v / sin(a)
		int a = Fixed.sin(mAngle);
		if (a != 0)
		{
			mx = Fixed.divide(mVectorX, a);
		}

		a = -Fixed.cos(mAngle);
		if (a != 0)
		{
			my = Fixed.divide(mVectorY, a);
		}
		return mx + my;
	}

	private void boundSpeed()
	{
		int max = Fixed.fromInt(10);

		if (mVectorX > max)
		{
			mVectorX = max;
		}
		if (mVectorY > max)
		{
			mVectorY = max;
		}

		if (mVectorX < -max)
		{
			mVectorX = -max;
		}
		if (mVectorY < -max)
		{
			mVectorY = -max;
		}
	}

	public void addSpeedFromVector(MotionObject obj, int multipler)
	{
		mVectorX += Fixed.multiply(obj.mVectorX, multipler);
		mVectorY += Fixed.multiply(obj.mVectorY, multipler);
		boundSpeed();
	}

	public void addSpeedFromVector(MotionObject obj)
	{
		mVectorX += obj.mVectorX;
		mVectorY += obj.mVectorY;
		boundSpeed();
	}
	public void setSpeedFromVector(MotionObject obj)
	{
		mVectorX = obj.mVectorX;
		mVectorY = obj.mVectorY;
		boundSpeed();
	}
	public void setSpeed(int newSpeed)
	{
		mVectorX = Fixed.multiply(Fixed.sin(mAngle), newSpeed);
		mVectorY = Fixed.multiply(-Fixed.cos(mAngle), newSpeed);
		boundSpeed();
	}

	public void addSpeed(int newSpeed)
	{
		mVectorX += Fixed.multiply(Fixed.sin(mAngle), newSpeed);
		mVectorY += Fixed.multiply(-Fixed.cos(mAngle), newSpeed);
		boundSpeed();
	}


	// update motion object. Return true if object wrapped bounds
	public boolean Update()
	{
		boolean	wrap = false;

		mX += mVectorX;
		mY += mVectorY;

		// bound x
		if (mX < -mSizeX)
		{
			mX += mMaxX + mSizeX;
			wrap = true;
		}
		if (mX > mMaxX)
		{
			mX -= mMaxX + mSizeX;
			wrap = true;
		}
		// bound y
		if (mY < -mSizeY)
		{
			mY += mMaxY + mSizeY;
			wrap = true;
		}
		if (mY > mMaxY)
		{
			mY -= mMaxY + mSizeY;
			wrap = true;
		}
		if (mUseFrameTimer)
		{
			if (mFrameTimerCount < mFrameRateMax)
			{
				mFrameTimerCount++;
			}
			else
			{
				mFrameTimerCount = 0;
				mCurrentFrame = (mCurrentFrame + 1) % mMaxFrames;
			}
		}
		return wrap;
	}

	// data
	private int			mCurrentFrame, mMaxFrames;

	private boolean		mUseFrameTimer;
	private int			mFrameRateMax, mFrameTimerCount;
	private Rect		mBounds;

	// all values are fixed point (16.16)
	private int			mX, mY;		// position
	private int			mVectorX, mVectorY;
	private int			mAngle;
	private int			mMaxX, mMaxY;
	private int			mSizeX;
	private int			mSizeY;
}


