package mcfall.raytracer.objects;

import java.util.ArrayList;
import java.util.List;

import mcfall.math.ColumnVector;
import mcfall.math.IncompatibleMatrixException;
import mcfall.math.Matrix;
import mcfall.math.Point;
import mcfall.math.Ray;
import mcfall.math.Vector;
/**
 * The GenericPlane class represents the xy-plane (e.g., the plane where z=0).
 * @author mcfall
 *
 */
public class GenericPlane extends MathematicalObject {

	 
	protected static final Vector genericNormalVector;
	static final double rad = 180d/Math.PI;//save computing this in forcePlaneToPoint
	static {
		genericNormalVector = new ColumnVector(4, new double[] {0, 0, 1, 0});
	}
	public GenericPlane () {
		super ();
	}
	
	/**
	 * Constructs a GenericPlane object with the given name
	 * @param name the name to associate with this object
	 */
	public GenericPlane (String name) {
		super(name);
	}
	public GenericPlane(GenericPlane gs) {
		gs.currentTransformation = Matrix.createIdentityMatrix(4);
		transform(this.getTransform());
		gs.setMaterial(this.getMaterial());
		gs.setReflectionCoefficient(this.getReflectionCoefficient());
		gs.setRefractionIndex(this.getRefractionIndex());
		gs.setTransparency(this.getTransparency());
	}
	/**
	 * Force plane to point normal form given a Point p and normal.  This was initially rolled into another class but it simplified inheretence to put it here
	 * 
	 * @param p the p
	 * @param normal the normal
	 */
	// TODO Should this be a factory method or in a factory class?
	public void forcePlaneToPointNormal(Point p, Vector normal) {
		try {
			normal = normal.normalize();
			double angle = Math.acos(normal.dot(genericNormalVector));
			if(angle!=0) {
				angle = angle*rad;
				Vector axis = normal.cross(genericNormalVector).normalize();
				Matrix r = Matrix.createRotationMatrix(angle, axis);
				Matrix t = Matrix.createTranslationMatrix(p.getX(),p.getY(), p.getZ());
				Matrix tInverse =  t.invert();				
				this.transform(this.getTransform().postmultiply(tInverse.postmultiply(r).postmultiply(t)));
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
	@Override
	protected List<HitRecord> genericHitTime(Ray ray) {
		Point start = ray.getStart();
		Vector direction = ray.getDirection();
		ArrayList<HitRecord> results = new java.util.ArrayList<HitRecord> ();
		
		double cz = start.getZ();
		double dz= direction.getValueAt(3);
		
		
		if (dz != 0) {
			double thit = -cz / dz;
			HitRecord record = new HitRecord(thit, getTransformedVector(genericNormalVector), this);
			results.add(record);			
		}
		
		return results;
		
		
				
	}

	@Override
	protected String getObjectType() {
		return ("Generic Plane");
	}

}
