/** Represents a solid sphere. */
public class Sphere extends Surface {
	private class MyIntersection extends AbstractIntersection {
		private Vector norm = null;

		private MyIntersection(Ray incident, double dist) {
			super(incident, dist);
		}

		public Vector getNormal() {
			if(norm == null) norm = getHitPoint().subtract(center);
			return norm.scale(1.0 / radius);
		}

		public Material getMaterial() {
			return material;
		}
	}

	private Material material;
	private Point center;
	private double radius;

	public Sphere(Point center, double radius, Material material) {
		this.center = center;
		this.radius = radius;
		this.material = material;
	}

	public Sphere(Point center, double radius) {
		this(center, radius, Material.WHITE_PLASTIC);
	}

	public Intersection getIntersection(Ray query) {
		Point qp = query.getOrigin();
		double x = qp.getX() - center.getX();
		double y = qp.getY() - center.getY();
		double z = qp.getZ() - center.getZ();

		Vector d = query.getDirection();
		double dx = d.getX();
		double dy = d.getY();
		double dz = d.getZ();

		double a = dx * dx  +  dy * dy  +  dz * dz;
		double b = 2 * (x * dx  +  y * dy  +  z * dz);
		double c = x * x  +  y * y  +  z * z  -  radius * radius;

		double disc = b * b - 4 * a * c;
		if(disc < 0.0) return Intersection.NONE;

		double sqrtDisc = Math.sqrt(disc);
		double smaller = (-b - sqrtDisc) / (2.0 * a);
		if(smaller >= 1.0) return new MyIntersection(query, smaller);
		double larger  = (-b + sqrtDisc) / (2.0 * a);
		if(larger  >= 1.0) return new MyIntersection(query, larger);
		return Intersection.NONE;
	}
}
