using System;

#if XNA
using Microsoft.Xna.Framework;
#endif

namespace XELF.Framework {

#if XNA
	public static partial class QuaternionHelper {
#else
	public partial struct Quaternion {
#endif
		/// <summary>
		/// 対数
		/// </summary>
		/// <param name="a"></param>
		/// <param name="result"></param>
		public static void Log(ref Quaternion a, out Quaternion result) {
			if (Math.Abs(a.W) < 1 - float.Epsilon) {
				var s = (float)Math.Acos(a.W) * MathHelper.Rsqrt(1 - a.W * a.W);
				result = new Quaternion(a.X * s, a.Y * s, a.Z * s, 0);
			} else {
				result = new Quaternion(a.X, a.Y, a.Z, 0);
			}
		}

		/// <summary>
		/// 指数
		/// </summary>
		/// <param name="a"></param>
		/// <param name="result"></param>
		public static void Exp(ref Quaternion a, out Quaternion result) {
			var alpha = a.X * a.X + a.Y * a.Y + a.Z * a.Z;
			if (alpha > float.Epsilon) {
				alpha *= MathHelper.Rsqrt(alpha);
				var s = (float)Math.Sin(alpha) / alpha;
				result = new Quaternion(a.X * s, a.Y * s, a.Z * s, (float)Math.Cos(alpha));
			} else {
				result = new Quaternion(a.X, a.Y, a.Z, 1);
			}
		}

		/// <summary>
		/// べき乗
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="result"></param>
		public static void Pow(ref Quaternion a, float b, out Quaternion result) {
			Log(ref a, out result);
			Quaternion.Multiply(ref result, b, out result);
			Exp(ref result, out result);
		}

		/// <summary>
		/// べき乗
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static Quaternion Pow(Quaternion a, float b) {
			Quaternion result;
			Pow(ref a, b, out result);
			return result;
		}

	}
}
