/*
 * +================================================================================+
 *      __  ___  ______________  __  __  ______________   ____
 *     / / / / |/ /  _/_  __/\ \/ / / / / /_  __/  _/ /  / __/
 *    / /_/ /    // /  / /    \  / / /_/ / / / _/ // /___\ \
 *    \____/_/|_/___/ /_/     /_/  \____/ /_/ /___/____/___/
 *
 * +================================================================================+
 *
 *    "THE BEER-WARE LICENSE"
 *    -----------------------
 *
 *    As long as you retain this notice you can do whatever you want with this
 *    stuff. However it is expressly forbidden to sell or commercially distribute
 *    Unity Utils or parts of it apart from your games.
 *    If you meet any of the authors some day, and you think this stuff is
 *    worth it, you can buy them a beer in return.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *    THE SOFTWARE.
 *
 * +================================================================================+
 *
 *    Authors:
 *    David Krummenacher (dave@timbookedtwo.com)
 *
 */

using UnityEngine;

namespace Utils.Helpers {

	/// <summary>
	/// Helper methods for Quaternions.
	/// </summary>
	public abstract class QuaternionHelper {
	
		/// <summary>
		/// Lerps from a start rotation to a look at rotation.
		/// </summary>
		/// <returns>The lerped look at quaternion.</returns>
		/// <param name="rotation">The start rotation.</param>
		/// <param name="from">Point from where to look.</param>
		/// <param name="to">Point where to look at.</param>
		/// <param name="amount">Amount (0.0 = start rotation / 1.0 = look at rotation).</param>
		public static Quaternion LookAtLerp (Quaternion rotation, Vector3 from, Vector3 to, float amount) {
			return Quaternion.Lerp(rotation, Quaternion.LookRotation(to - from), amount);
		}
	
		/// <summary>
		/// Slerps from a start rotation to a look at rotation.
		/// </summary>
		/// <returns>The slerped look at quaternion.</returns>
		/// <param name="rotation">The start rotation.</param>
		/// <param name="from">Point from where to look.</param>
		/// <param name="to">Point where to look at.</param>
		/// <param name="amount">Amount (0.0 = start rotation / 1.0 = look at rotation).</param>
		public static Quaternion LookAtSlerp (Quaternion rotation, Vector3 from, Vector3 to, float amount) {
			return Quaternion.Slerp(rotation, Quaternion.LookRotation(to - from), amount);
		}

		/// <summary>
		/// Lerps a quaternion with overshoot.
		/// </summary>
		/// <returns>The quaternion.</returns>
		/// <param name="from">From.</param>
		/// <param name="to">To.</param>
		/// <param name="t">T.</param>
		public static Quaternion LerpWithOvershoot(Quaternion from, Quaternion to, float t) {
			// If t is too large, subtract 1.0 from it recursively
			if (t > 1f) {
				Quaternion temp = LerpWithOvershoot(from, to, t - 1f);
				return temp * Quaternion.Inverse(from) * to;
			}
			
			// It’s easier to handle negative t this way
			if (t < 0f) return LerpWithOvershoot(to, from, 1f - t);
			
			return Quaternion.Lerp(from, to, t);
		}

		/// <summary>
		/// Slerps a quaternion with overshoot.
		/// </summary>
		/// <returns>The quaternion.</returns>
		/// <param name="from">From.</param>
		/// <param name="to">To.</param>
		/// <param name="t">T.</param>
		public static Quaternion SlerpWithOvershoot(Quaternion from, Quaternion to, float t) {
			// If t is too large, divide it by two recursively
			if (t > 1f) {
				Quaternion temp = SlerpWithOvershoot(from, to, t / 2f);
				return temp * Quaternion.Inverse(from) * temp;
			}
			
			// It’s easier to handle negative t this way
			if (t < 0f) return SlerpWithOvershoot(to, from, 1f - t);
			
			return Quaternion.Slerp(from, to, t);
		}
	}
}
