package mcfall.raytracer.objects;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import mcfall.math.IncompatibleMatrixException;
import mcfall.math.Matrix;
import mcfall.math.NotInvertibleException;
import mcfall.math.Point;
import mcfall.math.Ray;
import mcfall.raytracer.Camera;

public class GenericSquare extends GenericPlane implements ProjectedExtent{
	AbstractRectangleExtent rectExtent = null;//TODO fixme
	Camera camera = null;
	public GenericSquare () {
		super ();
	}
	
	public GenericSquare (String name) {
		super(name);
	}
	@Override
	protected List<HitRecord> genericHitTime(Ray ray) {	
		List<HitRecord> hits = super.genericHitTime(ray);
		
		if (hits.size() == 0) {
			return hits;
		}
		
		HitRecord superHit = hits.get(0);
		Point hitPoint = ray.pointAt(superHit.hitTime);
		
		double hitX = hitPoint.getX();
		double hitY = hitPoint.getY();
		
		if (hitX >= -1 && hitX <= 1 && hitY >= -1 && hitY <= 1) {
			return hits;
		}
		
		return new ArrayList<HitRecord> ();
		
	}
	@Override
	protected String getObjectType() {
		return "Generic Square";
	}

	public boolean hits(int row, int column) {
		if(rectExtent!=null) {
			return rectExtent.hits(row, column);
		}else {
			throw new RuntimeException("Plane must be setup first");
		}
	}
	
	@Override
	public void transform(Matrix transform) {
		super.transform(transform);
		if(rectExtent!=null) {
			rectExtent.transform(transform);
		}
	}

	public void setUp(Camera camera) {
		this.camera = camera;
		HashSet<Point> critPoints = new HashSet<Point>();
		for(double x = -1;x<=1;x+=2d*Math.abs(x)) {
			for(double y = -1;y<=1;y+=2d*Math.abs(y)) {
				try {
					critPoints.add(Point.fromColumnMatrix(new Point(x,y,0).premultiply(getTransform())));
				} catch (IncompatibleMatrixException e) {
					e.printStackTrace();
				}
			}
		}
		rectExtent = AbstractRectangleExtent.createRectangleExtent(camera,critPoints);
		
	}
	protected void setUp() {
		if(camera!=null) {
			setUp(camera);
		}
	}
	

}
