/*
* Author: Jasper Slaff
* Date: 4/21/17
*/

package demo;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.ArrayList;

public abstract class DemoObj {

	protected double[] center;
	protected ArrayList<double[]> vertices;
	protected Shape border;
	private double rotation;

	protected DemoObj() {
		setCenter();
		vertices = null;// this will be defined by the setVertices method.
		border = null;// this will be defined by the get outline method.
		rotation = 0;
	}

	protected double calcSize() {
		return Math.sqrt(Math.pow(vertices.get(vertices.size() / 2)[0] - vertices.get(0)[0], 2)
				- Math.pow(vertices.get(vertices.size() / 2)[1] - vertices.get(0)[1], 2));
	}

	private void setCenter() {
		center = new double[3];
		center[0] = Constants.XSIZE / 2.25;
		center[1] = Constants.YSIZE / 2;
		center[2] = 1;
	}

	/**
	 * vertices are set a default distance from the origin. they are then scaled
	 * based on the given parameter a specific distance from the origin.
	 */
	protected abstract void setVertices(double scale);

	/**
	 * Adjusts the rotation so it is between 0 and 2 Pi
	 */
	private static double normalize(double angle) {
		while (angle < 0) {
			angle += 2 * Math.PI;
		}
		while (angle > 0) {
			angle -= 2 * Math.PI;
		}
		return angle;
	}

	/**
	 * rotates you around the implied z-axis that isn't thought about in 2d by
	 * delta using linear algebra concepts and matrix multiplication
	 * 
	 * @throws InvalidOperationException
	 */
	public void rotate(double delta) {
		rotation = normalize(rotation + delta);
		Shape original = getOutline();
		AffineTransform trans = AffineTransform.getRotateInstance(rotation, center[0], center[1]);
		border = trans.createTransformedShape(original);
	}

	public void scale(double direction) {
		Shape original = getOutline();
		AffineTransform trans = null;
		
		double scalar = 1;
		if (direction < 0) {
			scalar = .995;
		} else {
			scalar = 1.005;
		}
		
		trans = AffineTransform.getScaleInstance(scalar, scalar);
		recenter(scalar, trans, center);
		for(int i = 0; i < vertices.size(); i++){
			vertices.get(i)[0] += vertices.get(i)[0] - vertices.get(i)[0] * scalar;
			vertices.get(i)[1] += vertices.get(i)[1] - vertices.get(i)[1] * scalar;
		}
		
		border = trans.createTransformedShape(original);
	}

	private void recenter(double scale, AffineTransform trans, double[] center) {
		trans.translate(center[0] - center[0] * scale, center[1] - center[1] * scale);
	}

	/**
	 * moves you the specified distance along the specified axis using linear
	 * algebra concepts and matrix multiplication.
	 * 
	 * @throws InvalidOperationException
	 */
	public void translate(String axis, double distance) {
		Shape original = getOutline();
		AffineTransform trans = null;
		if (axis.toLowerCase().equals("x")) {
			for (int i = 0; i < vertices.size(); i++) {
				vertices.get(i)[0] += distance;
			}
			center[0] += distance;
			trans = AffineTransform.getTranslateInstance(distance, 0);
		} else if (axis.toLowerCase().equals("y")) {
			for (int i = 0; i < vertices.size(); i++) {
				vertices.get(i)[1] += distance;
			}
			center[1] += distance;
			trans = AffineTransform.getTranslateInstance(0, distance);
		} else {
			return;
		}
		border = trans.createTransformedShape(original);
	}

	public double[] getCenter() {
		return center;
	}

	public ArrayList<double[]> getVertices() {
		return vertices;
	}

	/**
	 * this will follow the vertices locations
	 * 
	 * @return
	 */
	protected abstract Shape getOutline();

	public void draw(Graphics2D g) {
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		if (border == null) {
			border = getOutline();
		}
		g.draw(border);
	}
}
