using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace EVE.EVECameras {
	public class EVECamera {
		private Vector3 myPosition;
		private Quaternion myRotation;

		private Matrix myWorld;
		private Matrix myView;
		private Matrix myProjection;
		private Viewport myViewport;

        public Vector3 Position { get { return myPosition; } set { myPosition = value;} }
		public Quaternion Rotation { get { return myRotation; } }

		public Matrix World { get { return myWorld; } }
		public Matrix View { get { return myView; } }
		public Matrix Projection { get { return myProjection; } }
		public Viewport Viewport { get { return myViewport; } }

		public EVECamera(Viewport newViewport) {
			myPosition = new Vector3(0, 0, 1);
			myRotation = new Quaternion(0, 0, 0, 1);

			SetViewport(newViewport);
		}

		public void Rotate(Vector3 axis, float angle) {
			axis = Vector3.Transform(axis, Matrix.CreateFromQuaternion(myRotation));
			myRotation = Quaternion.Normalize(Quaternion.CreateFromAxisAngle(axis, angle) * myRotation);

			Update();
		}

		public void Translate(Vector3 distance) {
			myPosition += Vector3.Transform(distance, Matrix.CreateFromQuaternion(myRotation));

			Update();
		}

		public void Revolve(Vector3 target, Vector3 axis, float angle) {
			Rotate(axis, angle);
			axis = Vector3.Transform(axis, Matrix.CreateFromQuaternion(myRotation));
			Quaternion rotate = Quaternion.CreateFromAxisAngle(axis, angle);
			myPosition = Vector3.Transform(target - myPosition, Matrix.CreateFromQuaternion(rotate));

			Update();
		}

        public void LookAt(Vector3 target)
        {
            Matrix LookAtView = Matrix.CreateLookAt(Position, target, new Vector3(0, 1, 0));
                       
            Quaternion LookAtQuaternion = Quaternion.CreateFromRotationMatrix(LookAtView);
            myRotation = Quaternion.Normalize(LookAtQuaternion);

            Update();
            myWorld = Matrix.Identity;
        }


		public void SetViewport(Viewport newViewport) {
			myViewport = newViewport;

			myViewport.MinDepth = 1.0f;
			myViewport.MaxDepth = 1000.0f;
		}

        public void SetView(Matrix view)
        {
            myView = view;
        }

		public void Update() {
			myWorld = Matrix.Identity;

			myView = Matrix.Invert(
				Matrix.CreateFromQuaternion(myRotation) *
				Matrix.CreateTranslation(myPosition)
			);

			myProjection = Matrix.CreatePerspectiveFieldOfView(
				MathHelper.Pi / 3.0f, (float)myViewport.Width / (float)myViewport.Height,
				myViewport.MinDepth, myViewport.MaxDepth
			);
		}
	}
}