using System;

namespace Wizard;

public class CustomEasing
{
	public enum eType
	{
		linear,
		inQuad,
		outQuad,
		inOutQuad,
		inCubic,
		outCubic,
		inOutCubic,
		inQuart,
		outQuart,
		inOutQuart,
		inSine,
		outSine,
		inOutSine,
		inExpo,
		outExpo,
		inOutExpo,
		inCirc,
		outCirc,
		inOutCirc,
		inElastic,
		outElastic,
		inOutElastic,
		inBack,
		outBack,
		inOutBack,
		inBounce,
		outBounce,
		inOutBounce
	}

	private delegate float easingFunc(float curTime);

	private float beginVal;

	private float endVal;

	private float changeVal;

	private float duration;

	private float curTime;

	private easingFunc func;

	public bool IsMoving { get; private set; }

	public CustomEasing(eType type, float beginValue, float endValue, float durationTime)
	{
		switch (type)
		{
		case eType.linear:
			func = linear;
			break;
		case eType.inQuad:
			func = inQuad;
			break;
		case eType.outQuad:
			func = outQuad;
			break;
		case eType.inOutQuad:
			func = inOutQuad;
			break;
		case eType.inCubic:
			func = inCubic;
			break;
		case eType.outCubic:
			func = outCubic;
			break;
		case eType.inOutCubic:
			func = inOutCubic;
			break;
		case eType.inQuart:
			func = inQuart;
			break;
		case eType.outQuart:
			func = outQuart;
			break;
		case eType.inOutQuart:
			func = inOutQuart;
			break;
		case eType.inSine:
			func = inSine;
			break;
		case eType.outSine:
			func = outSine;
			break;
		case eType.inOutSine:
			func = inOutSine;
			break;
		case eType.inExpo:
			func = inExpo;
			break;
		case eType.outExpo:
			func = outExpo;
			break;
		case eType.inOutExpo:
			func = inOutExpo;
			break;
		case eType.inCirc:
			func = inCirc;
			break;
		case eType.outCirc:
			func = outCirc;
			break;
		case eType.inOutCirc:
			func = inOutCirc;
			break;
		case eType.inElastic:
			func = inElastic;
			break;
		case eType.outElastic:
			func = outElastic;
			break;
		case eType.inOutElastic:
			func = inOutElastic;
			break;
		case eType.inBack:
			func = inBack;
			break;
		case eType.outBack:
			func = outBack;
			break;
		case eType.inOutBack:
			func = inOutBack;
			break;
		case eType.inBounce:
			func = inBounce;
			break;
		case eType.outBounce:
			func = outBounce;
			break;
		case eType.inOutBounce:
			func = inOutBounce;
			break;
		}
		beginVal = beginValue;
		endVal = endValue;
		duration = durationTime;
		curTime = 0f;
		changeVal = endValue - beginValue;
		IsMoving = true;
	}

	public float GetCurVal(float deltaTime, bool canOver = false)
	{
		curTime += deltaTime;
		if (curTime >= duration && !canOver)
		{
			IsMoving = false;
			return endVal;
		}
		return func(curTime) + beginVal;
	}

	private float linear(float t)
	{
		return changeVal * t / duration;
	}

	private float inQuad(float t)
	{
		float num = t / duration;
		return changeVal * num * num;
	}

	private float outQuad(float t)
	{
		float num = t / duration;
		return (0f - changeVal) * num * (num - 2f);
	}

	private float inOutQuad(float t)
	{
		float num = t * 2f / duration;
		if (num < 1f)
		{
			return changeVal / 2f * num * num;
		}
		return (0f - changeVal) / 2f * ((num - 1f) * (num - 3f) - 1f);
	}

	private float inCubic(float t)
	{
		float num = t / duration;
		return changeVal * num * num * num;
	}

	private float outCubic(float t)
	{
		float num = t / duration - 1f;
		return changeVal * (num * num * num + 1f);
	}

	private float inOutCubic(float t)
	{
		float num = t * 2f / duration;
		if (num < 1f)
		{
			return changeVal / 2f * num * num * num;
		}
		num -= 2f;
		return changeVal / 2f * (num * num * num + 2f);
	}

	private float inQuart(float t)
	{
		float num = t / duration;
		return changeVal * num * num * num * num;
	}

	private float outQuart(float t)
	{
		float num = t / duration - 1f;
		return (0f - changeVal) * (num * num * num * num - 1f);
	}

	private float inOutQuart(float t)
	{
		float num = t * 2f / duration;
		if (num < 1f)
		{
			return changeVal / 2f * num * num * num * num;
		}
		num -= 2f;
		return (0f - changeVal) / 2f * (num * num * num * num - 2f);
	}

	private float inSine(float t)
	{
		return (0f - changeVal) * (float)Math.Cos((double)(t / duration) * (Math.PI / 2.0)) + changeVal;
	}

	private float outSine(float t)
	{
		return changeVal * (float)Math.Sin((double)(t / duration) * (Math.PI / 2.0));
	}

	private float inOutSine(float t)
	{
		return (0f - changeVal) / 2f * ((float)Math.Cos((double)(t / duration) * Math.PI) - 1f);
	}

	private float inExpo(float t)
	{
		if (t == 0f)
		{
			return 0f;
		}
		return changeVal * (float)Math.Pow(2.0, 10f * (t / duration - 1f));
	}

	private float outExpo(float t)
	{
		return changeVal * (0f - (float)Math.Pow(2.0, -10f * t / duration) + 1f);
	}

	private float inOutExpo(float t)
	{
		if (t == 0f)
		{
			return 0f;
		}
		float num = t * 2f / duration;
		if (num < 1f)
		{
			return changeVal / 2f * (float)Math.Pow(2.0, 10f * (num - 1f));
		}
		return changeVal / 2f * (0f - (float)Math.Pow(2.0, -10f * (num - 1f)) + 2f);
	}

	private float inCirc(float t)
	{
		float num = t / duration;
		return (0f - changeVal) * ((float)Math.Sqrt(1f - num * num) - 1f);
	}

	private float outCirc(float t)
	{
		float num = t / duration - 1f;
		return changeVal * (float)Math.Sqrt(1f - num * num);
	}

	private float inOutCirc(float t)
	{
		float num = t * 2f / duration;
		if (num < 1f)
		{
			return (0f - changeVal) / 2f * ((float)Math.Sqrt(1f - num * num) - 1f);
		}
		num -= 2f;
		return changeVal / 2f * ((float)Math.Sqrt(1f - num * num) + 1f);
	}

	private float inElastic(float t)
	{
		float num = t / duration;
		float num2 = 1.70158f;
		float num3 = changeVal;
		if (num == 0f)
		{
			return 0f;
		}
		float num4 = duration * 0.3f;
		num2 = ((!(num3 < Math.Abs(changeVal))) ? (num4 / ((float)Math.PI * 2f) * (float)Math.Asin(changeVal / num3)) : (num4 / 4f));
		num -= 1f;
		return 0f - num3 * (float)Math.Pow(2.0, 10f * num) * (float)Math.Sin((num * duration - num2) * ((float)Math.PI * 2f) / num4);
	}

	private float outElastic(float t)
	{
		float num = t / duration;
		float num2 = 1.70158f;
		float num3 = changeVal;
		if (num == 0f)
		{
			return 0f;
		}
		float num4 = duration * 0.3f;
		num2 = ((!(num3 < Math.Abs(changeVal))) ? (num4 / ((float)Math.PI * 2f) * (float)Math.Asin(changeVal / num3)) : (num4 / 4f));
		return num3 * (float)Math.Pow(2.0, -10f * num) * (float)Math.Sin((num * duration - num2) * ((float)Math.PI * 2f) / num4) + changeVal;
	}

	private float inOutElastic(float t)
	{
		float num = t * 2f / duration;
		float num2 = 1.70158f;
		float num3 = changeVal;
		if (num == 0f)
		{
			return 0f;
		}
		float num4 = duration * 0.45f;
		num2 = ((!(num3 < Math.Abs(changeVal))) ? (num4 / ((float)Math.PI * 2f) * (float)Math.Asin(changeVal / num3)) : (num4 / 4f));
		if (num < 1f)
		{
			num -= 1f;
			return -0.5f * (num3 * (float)Math.Pow(2.0, 10f * num) * (float)Math.Sin((num * duration - num2) * ((float)Math.PI * 2f) / num4));
		}
		num -= 1f;
		return num3 * (float)Math.Pow(2.0, -10f * num) * (float)Math.Sin((num * duration - num2) * ((float)Math.PI * 2f / num4)) * 0.5f + changeVal;
	}

	private float inBack(float t)
	{
		float num = t / duration;
		float num2 = 1.70158f;
		return changeVal * num * num * ((num2 + 1f) * num - num2);
	}

	private float outBack(float t)
	{
		float num = t / duration - 1f;
		float num2 = 1.70158f;
		return changeVal * (num * num * ((num2 + 1f) * num + num2) + 1f);
	}

	private float inOutBack(float t)
	{
		float num = t * 2f / duration;
		float num2 = 2.5949094f;
		if (num < 1f)
		{
			return changeVal / 2f * num * num * ((num2 + 1f) * num - num2);
		}
		num -= 2f;
		return changeVal / 2f * (num * num * ((num2 + 1f) * num + num2) + 2f);
	}

	private float inBounce(float t)
	{
		return changeVal - outBounce(duration - t);
	}

	private float outBounce(float t)
	{
		float num = t / duration;
		if (num < 0.36363637f)
		{
			return changeVal * (7.5625f * num * num);
		}
		if (num < 0.72727275f)
		{
			num -= 0.54545456f;
			return changeVal * (7.5625f * num * num + 0.75f);
		}
		if (num < 0.90909094f)
		{
			num -= 0.8181818f;
			return changeVal * (7.5625f * num * num + 0.9375f);
		}
		num -= 21f / 22f;
		return changeVal * (7.5625f * num * num + 63f / 64f);
	}

	private float inOutBounce(float t)
	{
		if (t * 2f < duration)
		{
			return inBounce(t * 2f) * 0.5f;
		}
		return 0.5f * outBounce(t * 2f - duration) + changeVal * 0.5f;
	}
}
