package random3DHangingFrameworkSphere;

import processing.core.PApplet;

public class Camera {
	/**
	 * USAGE 1. create a camera object with initial distance Camera myCam = new
	 * Camera( 300 ); or with smooth camera movement new Camera( 300, true);
	 * 
	 * 2. set the target myCam.setTarget( x, y, z );
	 * 
	 * 3. in the beginning of your draw() method apply the current camera
	 * settings myCam.use();
	 * 
	 * 4. in your preferred mouse method ( e.g. mouseDragged() ) apply changes
	 * myCam.mouseOrbit(); myCam.mouseZoom(); myCam.mousePan(); or use default
	 * keys
	 **/

	float rotationSpeed = 0.01f; // speed of rotation

	float angleX, angleY, angleZ;
	float currAngleX, currAngleY, currAngleZ;

	float distance;
	float currDistance;

	float transX, transY, transZ;
	float currTransX, currTransY, currTransZ;

	boolean smoothOrbit = false;

	public PApplet myApplet;

	float panx = 0;
	float pany = 0;

	// CONSTRUCTORS
	public Camera(float distance) {
		setDistance(distance);
		System.err.println("Camera notice:");
		System.err
				.println("Choose or switch camera mode.keys: '1' - '2' - '3'. Use your mouse and press left mouse to start camera.");
	}

	public Camera(float distance, boolean smoothMovement) {
		this(distance);
		smooth();
	}

	// ** MOUSE METHODS ***********************************************

	public void mouseOrbit() {
		float dx = myApplet.mouseX - myApplet.pmouseX;
		float dy = myApplet.mouseY - myApplet.pmouseY;
		setOrbit(dx, dy);
	}

	public void mouseZoom() {
		float dy = myApplet.mouseY - myApplet.pmouseY;
		this.setDistance(this.distance - dy);
	}

	public void mousePan() {
		float dx = myApplet.mouseX - myApplet.pmouseX;
		float dy = myApplet.mouseY - myApplet.pmouseY;
		setPan(dx, dy);
	}

	// ** SETTER METHODS ********************************************

	public void setPan(float dx, float dy) {
		panx = dx;
		pany = dy;
		this.transX += dx * myApplet.cos(currAngleZ);// +dx*sin(currAngleX);
		this.transY += -dx * myApplet.sin(currAngleZ) + dy
				* myApplet.cos(currAngleX);
		this.transZ += -dy * myApplet.sin(currAngleX);
	}

	public void setOrbit(float dx, float dy) {
		this.rotCamZ(-dx * rotationSpeed);
		this.rotCamX(-dy * rotationSpeed);
	}

	public void setStaticOrbit(float x, float y) {
		this.rotCamZstatic(-x * rotationSpeed);
		this.rotCamXstatic(-y * rotationSpeed);
	}

	public void setTarget(float x, float y, float z) {
		transX = -x;
		transY = -y;
		transZ = -z;
	}

	public void setDistance(float distance) {
		this.distance = distance;
	}

	public void rotCamX(float angle) {
		angleX += angle;
	}

	public void rotCamY(float angle) {
		angleY += angle;
	}

	public void rotCamZ(float angle) {
		angleZ += angle;
	}

	public void rotCamXstatic(float angle) {
		angleX = angle;
	}

	public void rotCamYstatic(float angle) {
		angleY = angle;
	}

	public void rotCamZstatic(float angle) {
		angleZ = angle;
	}

	// GETTER METHODS *********************************************

	public float getDistance() {
		return distance;
	}

	public float getOrbitZ() {
		return angleZ;
	}

	public float getOrbitX() {
		return angleX;
	}

	public float getCamPosX() {
		return transX;
	}

	public float getCamPosY() {
		return transY;
	}

	public float getCamPosZ() {
		return transX;
	}

	public float getAngleX() {
		return currAngleX;
	}

	public float getAngleY() {
		return currAngleY;
	}

	public float getAngleZ() {
		return currAngleZ;
	}

	public float getPanX() {
		return panx;
	}

	public float getPanY() {
		return pany;
	}

	// ** SYSTEM METHODS
	public void smooth() {
		smoothOrbit = true;
	}

	public void noSmooth() {
		smoothOrbit = false;
	}

	/**
	 * applies the current camera settings call it in your draw method before
	 * any paint job
	 **/
	public void useCam() {
//		if (smoothOrbit) {
//			if (myApplet.abs(currAngleX - angleX) > 0.01)
//				currAngleX += (angleX - currAngleX) / 10.0;
//			if (myApplet.abs(currAngleY - angleY) > 0.01)
//				currAngleY += (angleY - currAngleY) / 10.0;
//			if (myApplet.abs(currAngleZ - angleZ) > 0.01)
//				currAngleZ += (angleZ - currAngleZ) / 10.0;
//
//			if (myApplet.abs(currTransX - transX) > 0.01)
//				currTransX += (transX - currTransX) / 10.0;
//			if (myApplet.abs(currTransY - transY) > 0.01)
//				currTransY += (transY - currTransY) / 10.0;
//			if (myApplet.abs(currTransZ - transZ) > 0.01)
//				currTransZ += (transZ - currTransZ) / 10.0;
//
//			if (myApplet.abs(currDistance - distance) > 0.01)
//				currDistance += (distance - currDistance) / 10.0;
//		} else {
			currAngleX = angleX;
			currAngleY = angleY;
			currAngleZ = angleZ;

			currTransX = transX;
			currTransY = transY;
			currTransZ = transZ;

			currDistance = distance;
//		}

		myApplet.camera(0, 0, this.currDistance, 0, 0, 0, 0, 1, 0);

		myApplet.rotateX(currAngleX);
		myApplet.rotateY(currAngleY);
		myApplet.rotateZ(currAngleZ);

		myApplet.translate(currTransX, currTransY, currTransZ);
	}

	public void traceCamera() {
		System.err.print("Absolute Cam Pos X:" + (-transX) + " Y:" + (-transY)
				+ " Z: " + (-transZ));
		System.err.print("Pan X:" + (getPanX()) + " Y:" + getPanY());
		// System.err.print("Orbit X:" + (-(getOrbitZ() * 100)) + " Y: "
		// + (-(myCam.getOrbitX() * 100)));
		System.err.println("Distance: " + getDistance());
	}
}
