using System;

using Saserdote.GamingServices;
using Saserdote.Mathematics;

namespace Saserdote.Animation
{
	public class Tween
	{
		#region --- Field Variables ---
		
		// Variables
		public float	original;
		public float	distance;
		private float	current;
		private float	totalT;
		public float	totalDuration;
		private bool	pFinished;
		private TweenFunc	tweenFunc;
		
		#endregion // Field Variables
		
		#region --- Constructors ---
		
		public Tween(float tStart, float tEnd, float tDur, TweenFunc func)
		{
			distance=	tEnd-tStart;
			original=	tStart;
			current=	tStart;
			totalDuration=	tDur;
			tweenFunc=	func;
			totalT=	0;
			pFinished=	false;
		}
		public Tween(float tStart, float tEnd, float tDur):this(tStart, tEnd, tDur, Tween.linear)	{}
		
		#endregion // Constructors
		
		#region --- Properties ---
		
		// Gets the value of the tween
		public float value
		{
			get	{	return current;	}
		}
		
		// Gets if the tween is finished
		public bool bFinished
		{
			get	{	return pFinished;	}
		}
		
		#endregion // Properties
		
		#region --- Static Methods ---
		
		// Gets a linear representation of a tween
		public static float linear(float t, float tStart, float distance, float duration)
		{
			return distance*t/duration+tStart;
		}
		
		// Gets an ease in exponential representation of a tween
		public static float easeInExpo(float t, float tStart, float distance, float duration)
		{
			if(t== 0)
				return tStart;
			
			return distance*(float)(Math.Pow(2, 10*(t/duration-1)))+tStart;
		}
		
		// Gets an ease out exponential representation of a tween
		public static float easeOutExpo(float t, float tStart, float distance, float duration)
		{
			if(t== duration)
				return tStart+distance;
			
			return distance*(float)(-Math.Pow(2, -10*t/duration)+1)+tStart;
		}
		
		// Gets an ease in and out exponential representation of a tween
		public static float easeInOutExpo(float t, float tStart, float distance, float duration)
		{
			if(t== 0)
				return tStart;
			if(t== duration)
				return tStart+distance;
			
			t/=	duration/2f;
			if(t< 1)
				return ((distance/2f)*(float)(Math.Pow(2, 10*(t-1)))+tStart);
			
			return ((distance/2f)*(float)(-Math.Pow(2, -10*(--t)))+2+tStart);
		}
		
		// Gets an ease in circular representation of a tween
		public static float easeInCirc(float t, float tStart, float distance, float duration)
		{
			t=	t/duration;
			return -distance*(float)(Math.Sqrt(1-t*t)-1)+tStart;
		}
		
		// Gets an ease out circular representation of a twen
		public static float easeOutCirc(float t, float tStart, float distance, float duration)
		{
			t/=	duration-1;
			return distance*(float)(Math.Sqrt(1-t*t))+tStart;
		}
		
		// Gets an ease in and out circular representation of a tween
		public static float easeInOutCirc(float t, float tStart, float distance, float duration)
		{
			t/=	duration/2f;
			
			if(t< 1)
				return ((-distance/2f)*(float)(Math.Sqrt(1-t*t)-1)+tStart);
			
			t-=	2;
			return ((distance/2f)*(float)(Math.Sqrt(1-t)*t)+1)+tStart;
		}
		
		// Gets an ease in quadratic representation of a tween
		public static float easeInQuad(float t, float tStart, float distance, float duration)
		{
			t/=	duration;
			
			return distance*(t*t)+tStart;
		}
		
		#endregion // Static Methods
		
		#region --- Methods ---
		
		// Updates the tween
		public void update(GameTime time)
		{
			if(pFinished)
				return;
			
			totalT+=	time.totalMilliseconds;
			current=	tweenFunc(totalT, original, distance, totalDuration);
			if(totalT> totalDuration)
			{
				current=	original+distance;
				pFinished=	true;
			}
		}
		
		// Finishes the tween function
		public void finish()
		{
			current=	original+distance;
			totalT=	0;
			pFinished=	true;
		}
		
		// Resets the tween function to the given parameters
		public void reset(float tStart, float tEnd, float tDur, TweenFunc func)
		{
			distance=	tEnd-tStart;
			original=	tStart;
			current=	tStart;
			totalDuration=	tDur;
			tweenFunc=	func;
			totalT=	0;
			pFinished=	false;
		}
		public void reset()	{	reset(original, original+distance, totalDuration, tweenFunc);	}
		
		#endregion // Methods
	}
}

// End of File