using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace SpaceWinnie
{
	public enum CameraType { LandObject, AirCraft }

	public class Camera
	{
		CameraType _cameraType;
		Vector3 _right;
		Vector3 _up;
		Vector3 _look;
		Vector3 _pos;
		Matrix projectionMatrix;

		public CameraType CameraType
		{
			get { return _cameraType; }
			set { _cameraType = value; }
		}

		public Vector3 Position
		{
			get { return _pos; }
			set { _pos = value; }
		}

		public Vector3 Right { get { return _right; } }
		public Vector3 Up { get { return _up; } }
		public Vector3 Look { get { return _look; } }

		public Camera ( Game game, CameraType cameraType )
		{
			_cameraType = cameraType;

			float aspectRatio = ( float ) game.GraphicsDevice.Viewport.Width / game.GraphicsDevice.Viewport.Height;
			projectionMatrix = Matrix.CreatePerspectiveFieldOfView ( MathHelper.PiOver4, aspectRatio, 0.0001f, 1000.0f );

			_pos = new Vector3 ( 0, 0, 0 );
			_right = new Vector3 ( 1, 0, 0 );
			_up = new Vector3 ( 0, 1, 0 );
			_look = new Vector3 ( 0, 0, 1 );
		}

		public void Strafe ( float units )
		{
			if ( CameraType == CameraType.LandObject )
				_pos += new Vector3 ( _right.X, 0, _right.Z ) * units;
			else
				_pos += _right * units;
		}

		public void Fly ( float units )
		{
			if ( CameraType == CameraType.LandObject )
				_pos.Y += units;
			else
				_pos += _up * units;
		}

		public void Walk ( float units )
		{
			if ( CameraType == CameraType.LandObject )
			{
				Vector3 dir = Vector3.Cross ( _right, new Vector3 ( 0, 1, 0 ) );
				_pos += new Vector3 ( dir.X, 0, dir.Z ) * units;
			}
			else
				_pos += _look * units;
		}

		public void Pitch ( float angle )
		{
			Matrix T = Matrix.CreateFromAxisAngle ( _right, angle );

			_up = Vector3.Transform ( _up, T );
			_look = Vector3.Transform ( _look, T );
		}

		public void Yaw ( float angle )
		{
			Matrix T;

			if ( CameraType == CameraType.LandObject )
				T = Matrix.CreateRotationY ( angle );
			else
				T = Matrix.CreateFromAxisAngle ( _up, angle );

			_right = Vector3.Transform ( _right, T );
			_look = Vector3.Transform ( _look, T );
		}

		public void Roll ( float angle )
		{
			if ( CameraType == CameraType.AirCraft )
			{
				Matrix T = Matrix.CreateFromAxisAngle ( _look, angle );

				_right = Vector3.Transform ( _right, T );
				_up = Vector3.Transform ( _up, T );
			}
		}

		public Matrix ViewMatrix
		{
			get
			{
				_look = Vector3.Normalize ( _look );

				_up = Vector3.Cross ( _look, _right );
				_up = Vector3.Normalize ( _up );

				_right = Vector3.Cross ( _up, _look );
				_right = Vector3.Normalize ( _right );

				float x = -Vector3.Dot ( _right, _pos );
				float y = -Vector3.Dot ( _up, _pos );
				float z = -Vector3.Dot ( _look, _pos );

				Matrix V = new Matrix ();
				V.M11 = _right.X; V.M12 = _up.X; V.M13 = _look.X; V.M14 = 0;
				V.M21 = _right.Y; V.M22 = _up.Y; V.M23 = _look.Y; V.M24 = 0;
				V.M31 = _right.Z; V.M32 = _up.Z; V.M33 = _look.Z; V.M34 = 0;
				V.M41 = x; V.M42 = y; V.M43 = z; V.M44 = 1.0f;

				return V;
			}
		}

		public Matrix ProjectionMatrix { get { return projectionMatrix; } }
	}
}
