/*
 * BounceInterpolator.java
 * Created on Feb 11, 2005
 */

package ball;

import java.awt.Color;
import java.util.Random;

import javax.media.j3d.Alpha;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransformInterpolator;
import javax.vecmath.Color3f;
import javax.vecmath.Vector3d;

/**
 * @author gdennis
 *
 * Will bounce an object in three dimensions.
 */
public final class BounceInterpolator extends TransformInterpolator {

	private static final Random RANDOM = new Random();

	private final float radius;
	private final Color3f color1, color2;
	private final ColoringAttributes coloring;
	
	// field that change
	private boolean useColor1;
	private final Vector3d velocity = new Vector3d();
	private final Vector3d location = new Vector3d(0, 0, 0);
	
	public BounceInterpolator(float radius, double speed, ColoringAttributes coloring,
			Color color1, Color color2, TransformGroup target) {
		super(new Alpha(), target);
		this.radius = radius;
		this.color1 = new Color3f(color1);
		this.color2 = new Color3f(color2);
		this.useColor1 = true;
		this.coloring = coloring;
		coloring.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE);
		
		// pick random x, y, and z velocities st x^2 + y^2 + z^2 = s^2
		velocity.set(randomFloat(), randomFloat(), randomFloat());
		double s = Math.sqrt(speed * speed / velocity.lengthSquared());
		velocity.scale(s);
	}
	
	/* return random float from -1 to 1 */
	private static float randomFloat() { return 2 * RANDOM.nextFloat() - 1; }
	
	public void computeTransform(float alpha, Transform3D target) {
		location.add(velocity);
		boolean bounced = false;
		
		if (location.x + radius > 1) {
			location.x = 2 * (1 - radius) - location.x;
			velocity.x *= -1;
			bounced = true;
		} else if (location.x - radius < -1) {
			location.x = -2 * (1 - radius) - location.x;
			velocity.x *= -1;
			bounced = true;
		}
		
		if (location.y + radius > 1) {
			location.y = 2 * (1 - radius) - location.y;
			velocity.y *= -1;
			bounced = true;
		} else if (location.y - radius < -1) {
			location.y = -2 * (1 - radius) - location.y;
			velocity.y *= -1;
			bounced = true;
		}
		
		if (location.z + radius > 1) {
			location.z = 2 * (1 - radius) - location.z;
			velocity.z *= -1;
			bounced = true;
		} else if (location.z - radius < -1) {
			location.z = -2 * (1 - radius) - location.z;
			velocity.z *= -1;
			bounced = true;
		}
		
		// change the color on a bounce
		if (bounced) {
			useColor1 = !useColor1;
			coloring.setColor(useColor1 ? color1 : color2);
		}
		
		target.set(location);
	}
	
}
