using System;
using Tao.OpenGl;
using Tao.Platform.Windows;
using QCGM.Geometry;

namespace QCGM
{
	/// <summary>
	/// Summary description for Camera.
	/// </summary>
	
	 class Interpolation
	{
		public const string Linear = "linear";
		public const string Sine = "sine";
		public const string Cos = "cosine";
		
		public static float LinearInterpolation(float alpha, float a, float b)
		{
			return (1-alpha) * a + alpha * b;
		}

		public static float SineInterpolation(float p, float a, float b)
		{
			return (float)System.Math.Sin(p) * (b-a);
		}

		public static float CosineInterpolation(float p, float a, float b)
		{
			return (float)System.Math.Sin(p) * (b-a);
		}
	}

	public class CameraSettings
	{
		public Point3Df Eye = new Point3Df();	// Where the eye is
		public Point3Df At = new Point3Df();	// Where we are looking
		public Point3Df Up = new Point3Df();	// Up Vector

		public void Clone(CameraSettings B)
		{
			this.Eye.Clone(B.Eye);
			this.At.Clone(B.At);
			this.Up.Clone(B.Up);
		}
	}

	public class Camera
	{
		public bool isMoving;
		
		public CameraSettings Source;	// Where the camera was
		public CameraSettings Pos;		// Where it is
		public CameraSettings Dest;		// Where it is going

		public float Alpha;				// Coefficient for interpolation. 0.0f = Source, 1.0f = Dest

		public CameraSettings [] paths;
		public bool followPath;
		public bool pathLoops;

		public bool Moving = false;

		public Camera(float eyex, float eyey, float eyez, float atx, float aty, float atz, float upx, float upy, float upz)
		{
			Source = new CameraSettings();
			Pos = new CameraSettings();
			Dest = new CameraSettings();

			Source.Eye.X = eyex;
			Source.Eye.Y = eyey;
			Source.Eye.Z = eyez;
			Source.At.X = atx;
			Source.At.Y = aty;
			Source.At.Z = atz;
			Source.Up.X = upx;
			Source.Up.Y = upy;
			Source.Up.Z = upz;

			Dest.Eye.X = eyex;
			Dest.Eye.Y = eyey;
			Dest.Eye.Z = eyez;
			Dest.At.X = atx;
			Dest.At.Y = aty;
			Dest.At.Z = atz;
			Dest.Up.X = upx;
			Dest.Up.Y = upy;
			Dest.Up.Z = upz;

			Pos.Eye.X = eyex;
			Pos.Eye.Y = eyey;
			Pos.Eye.Z = eyez;
			Pos.At.X = atx;
			Pos.At.Y = aty;
			Pos.At.Z = atz;
			Pos.Up.X = upx;
			Pos.Up.Y = upy;
			Pos.Up.Z = upz;

			Alpha = 0.0f;

		}

		public void MoveTo(float eyex, float eyey, float eyez)
		{
			Dest.Eye.X = eyex;
			Dest.Eye.Y = eyey;
			Dest.Eye.Z = eyez;
			Alpha = 0.0f;
			Moving = true;
		}
		
		public void MoveTo(float eyex, float eyey, float eyez, float atx, float aty, float atz, float upx, float upy, float upz)
		{
			Source.Clone(Pos);

			Dest.Eye.X = eyex;
			Dest.Eye.Y = eyey;
			Dest.Eye.Z = eyez;
			Dest.At.X = atx;
			Dest.At.Y = aty;
			Dest.At.Z = atz;
			Dest.Up.X = upx;
			Dest.Up.Y = upy;
			Dest.Up.Z = upz;

			Alpha = 0.0f;

			Moving = true;
		}

		/// <summary>
		/// Moves this camera towards its destination point.
		/// </summary>
		/// <param name="factor">Fraction to ADD to the current coefficient.</param>
		public bool MoveTowardDestination(float factor)
		{
			if(Moving)
			{
				Alpha += factor;
				if(Alpha >= 1.0f)
				{
					Moving = false;
				}

				float t = Alpha;
				Pos.Eye.X = (1.0f - t) * Source.Eye.X + t * Dest.Eye.X;
				Pos.Eye.Y = (1.0f - t) * Source.Eye.Y + t * Dest.Eye.Y;
				Pos.Eye.Z = (1.0f - t) * Source.Eye.Z + t * Dest.Eye.Z;

				Pos.At.X = (1.0f - t) * Source.At.X + t * Dest.At.X;
				Pos.At.Y = (1.0f - t) * Source.At.Y + t * Dest.At.Y;
				Pos.At.Z = (1.0f - t) * Source.At.Z + t * Dest.At.Z;

				Pos.Up.X = (1.0f - t) * Source.Up.X + t * Dest.Up.X;
				Pos.Up.Y = (1.0f - t) * Source.Up.Y + t * Dest.Up.Y;
				Pos.Up.Z = (1.0f - t) * Source.Up.Z + t * Dest.Up.Z;
				return true;
			}
			else
			{
				return false;
			}
		}
	}
}
