package world;

import devUtil.Vector3;

public class Camera {
	
	private double xPosition, yPosition, zPosition;
	private double xView, yView, zView;
	private double xAngle, yAngle, zAngle;
	
	private double horizontalRotation, verticalRotation;
	private double twist;
	
	private double fov;
	private double drawDistance;
	
	public Camera() {
		
		zView = 1;
		yAngle = 1;
		
		horizontalRotation = Math.PI / 2;
		
		fov = 60;
		drawDistance = 5000000;
	}
	
	// setters
	
	public void setPosition(double xPosition, double yPosition, double zPosition) {
		setXPosition(xPosition);
		setYPosition(yPosition);
		setZPosition(zPosition);
	}
	
	public void setPosition(Vector3 position) {
		setXPosition(position.getX());
		setYPosition(position.getY());
		setZPosition(position.getZ());
	}
	
	public void setView(double xView, double yView, double zView) {
		setXView(xView);
		setYView(yView);
		setZView(zView);
	}
	
	public void setView(Vector3 view) {
		
		view = view.getUnitVector();
		
		setXView(view.getX());
		setYView(view.getY());
		setZView(view.getZ());
	}
	
	public void setAngle(double xAngle, double yAngle, double zAngle) {
		setXAngle(xAngle);
		setYAngle(yAngle);
		setZAngle(zAngle);
	}
	
	public void setAngle(Vector3 angle) {
		setXAngle(angle.getX());
		setYAngle(angle.getY());
		setZAngle(angle.getZ());
	}
	
	// position
	
	public void setXPosition(double xPosition) {
		this.xPosition = xPosition;
	}
	
	public void setYPosition(double yPosition) {
		this.yPosition = yPosition;
	}
	
	public void setZPosition(double zPosition) {
		this.zPosition = zPosition;
	}
	
	// view
	
	public void setXView(double xView) {
		this.xView = xView;
	}
	
	public void setYView(double yView) {
		this.yView = yView;
	}
	
	public void setZView(double zView) {
		this.zView = zView;
	}
	
	// angle
	
	public void setXAngle(double xAngle) {
		this.xAngle = xAngle;
	}
	
	public void setYAngle(double yAngle) {
		this.yAngle = yAngle;
	}
	
	public void setZAngle(double zAngle) {
		this.zAngle = zAngle;
	}
	
	// fov
	
	public void setFOV(double fov) {
		this.fov = fov;
	}
	
	// getters
	
	// position
	
	public double getXPosition() {
		return xPosition;
	}
	
	public double getYPosition() {
		return yPosition;
	}
	
	public double getZPosition() {
		return zPosition;
	}
	
	public Vector3 getPosition() {
		return new Vector3(xPosition, yPosition, zPosition);
	}
	
	// view
	
	public double getXView() {
		return xView;
	}
	
	public double getYView() {
		return yView;
	}
	
	public double getZView() {
		return zView;
	}
	
	// angle
	
	public Vector3 getView() {
		return new Vector3(xView, yView, zView);
	}
	
	public double getXAngle() {
		return xAngle;
	}
	
	public double getYAngle() {
		return yAngle;
	}
	
	public double getZAngle() {
		return zAngle;
	}
	
	public Vector3 getAngle() {
		return new Vector3(xAngle, yAngle, zAngle);
	}
	
	// misc
	
	public double getFOV() {
		return fov;
	}
	
	public double getDrawDistance() {
		return drawDistance;
	}
	
	// control
	
	public void rotate(double x, double y) {
		
		horizontalRotation += x;
		horizontalRotation = (horizontalRotation + (2 * Math.PI)) % (2 * Math.PI);
		
		verticalRotation += y;
		verticalRotation = (verticalRotation + (2 * Math.PI)) % (2 * Math.PI);
		
		xView = Math.cos(horizontalRotation) * Math.cos(verticalRotation);
		yView = Math.sin(verticalRotation);
		zView = Math.sin(horizontalRotation) * Math.cos(verticalRotation);
		
		if (verticalRotation > Math.PI / 2 && verticalRotation < 3 * (Math.PI / 2)) {
			//xAngle = 0;
			yAngle = -Math.abs(yAngle);
			//zAngle = 0;
		}
		
		else {
			//xAngle = 0;
			yAngle = Math.abs(yAngle);
			//zAngle = 0;
		}
	}
	
	public void twist(double twist) {
		
		this.twist += twist;
		
		xAngle = Math.sin(this.twist);
		yAngle = Math.cos(this.twist);
	}
	
	public void move(double move) {
		xPosition += move * xView * (1 - yView);
		yPosition += move * yView;
		zPosition += move * zView * (1 - yView);
	}
	
	public void moveXZ(double move) {
		
		Vector3 view = new Vector3(xView, 0, zView);
		view = view.getUnitVector();
		
		xPosition += move * view.getX();
		zPosition += move * view.getZ();
	}
	
	public void pan(double x, double y) {
		strafeHorizontal(x);
		strafeVertical(y);
	}
	
	public void strafeHorizontal(double x) {
		
		double rx = (horizontalRotation + (Math.PI / 2)) % (2 * Math.PI);
		
		double xs = Math.cos(rx);
		double zs = Math.sin(rx);
		
		xPosition += x * xs;
		zPosition += x * zs;
	}
	
	public void strafeVertical(double y) {
		
		double ry = ((verticalRotation - (Math.PI / 2)) % (2 * Math.PI));
		
		double xs = Math.cos(horizontalRotation) * Math.cos(ry);
		double ys = Math.sin(ry);
		double zs = Math.sin(horizontalRotation) * Math.cos(ry);
		
		xPosition += y * xs * (1 - ys);
		yPosition += y * ys;
		zPosition += y * zs * (1 - ys);
	}
}