using System;
using CodeImp.DoomBuilder.Rendering;

namespace CodeImp.DoomBuilder.Geometry
{
	public static class InterpolationTools
	{
		public enum Mode
		{
			LINEAR,
			EASE_IN_OUT_SINE,
			EASE_IN_SINE,
			EASE_OUT_SINE,
		}

		public static double Interpolate(double val1, double val2, double delta, Mode mode)
		{
			switch(mode)
			{
				case Mode.LINEAR: return Linear(val1, val2, delta);
				case Mode.EASE_IN_SINE: return EaseInSine(val1, val2, delta);
				case Mode.EASE_OUT_SINE: return EaseOutSine(val1, val2, delta);
				case Mode.EASE_IN_OUT_SINE: return EaseInOutSine(val1, val2, delta);
				default: throw new NotImplementedException("InterpolationTools.Interpolate: \"" + mode + "\" mode is not supported!");
			}
		}
		
		//Based on Robert Penner's original easing equations (http://www.robertpenner.com/easing/)
		public static float Linear(float val1, float val2, float delta)
		{
			return delta * val2 + (1.0f - delta) * val1;
		}

		//Based on Robert Penner's original easing equations (http://www.robertpenner.com/easing/)
		public static double Linear(double val1, double val2, double delta)
		{
			return delta * val2 + (1.0f - delta) * val1;
		}

		/**
		 * Easing equation function for a sinusoidal (sin(t)) easing in: accelerating from zero velocity.
		 */
		public static double EaseInSine(double val1, double val2, double delta) 
		{
			double f_val1 = val1;
			double f_val2 = val2 - f_val1;
			return -f_val2 * Math.Cos(delta * Angle2D.PIHALF) + f_val2 + f_val1;
		}

		/**
		 * Easing equation function for a sinusoidal (sin(t)) easing out: decelerating from zero velocity.
		 */
		public static double EaseOutSine(double val1, double val2, double delta) 
		{
			return (val2 - val1) * Math.Sin(delta * Angle2D.PIHALF) + val1;
		}

		/**
		 * Easing equation function for a sinusoidal (sin(t)) easing in/out: acceleration until halfway, then deceleration.
		 */
		public static double EaseInOutSine(double val1, double val2, double delta)
		{
			return -(val2 - val1) / 2 * (Math.Cos(Angle2D.PI * delta) - 1) + val1;
		}

		//mxd
		public static PixelColor InterpolateColor(PixelColor c1, PixelColor c2, double delta)
		{
			double invdelta = 1.0f - delta;
			byte a = (byte)(c1.a * invdelta + c2.a * delta);
			byte r = (byte)(c1.r * invdelta + c2.r * delta);
			byte g = (byte)(c1.g * invdelta + c2.g * delta);
			byte b = (byte)(c1.b * invdelta + c2.b * delta);
			return new PixelColor(a, r, g, b);
		}

		//mxd
		public static PixelColor InterpolateColor(PixelColor c1, PixelColor c2, double delta, Mode mode)
		{
			byte a = (byte)Math.Round(Interpolate(c1.a, c2.a, delta, mode));
			byte r = (byte)Math.Round(Interpolate(c1.r, c2.r, delta, mode));
			byte g = (byte)Math.Round(Interpolate(c1.g, c2.g, delta, mode));
			byte b = (byte)Math.Round(Interpolate(c1.b, c2.b, delta, mode));
			return new PixelColor(a, r, g, b);
		}
	}
}
