﻿// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved.

using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
	[ActionCategory(ActionCategory.Transform)]
	[Tooltip("Action version of Unity's Smooth Follow script.")]
	public class SmoothFollowAction : FsmStateAction
	{
		[RequiredField]
		[Tooltip("The game object to control. E.g. The camera.")]
		public FsmOwnerDefault gameObject;

		[Tooltip("The GameObject to follow.")]
		public FsmGameObject targetObject;

		[RequiredField]
		[Tooltip("The distance in the x-z plane to the target.")]
		public FsmFloat distance;

		[RequiredField]
		[Tooltip("The height we want the camera to be above the target")]
		public FsmFloat height;

		[RequiredField]
		[Tooltip("How much to dampen height movement.")]
		public FsmFloat heightDamping;

		[RequiredField]
		[Tooltip("How much to dampen rotation changes.")]
		public FsmFloat rotationDamping;

		// Cache for performance
		private GameObject cachedObject;
		private Transform myTransform;
		
		private GameObject cachedTarget;
		private Transform targetTransform;

		public override void Reset()
		{
			gameObject = null;
			targetObject = null;
			distance = 10f;
			height = 5f;
			heightDamping = 2f;
			rotationDamping = 3f;
		}

        public override void OnPreprocess()
        {
            Fsm.HandleLateUpdate = true;
        }

		public override void OnLateUpdate()
		{
			if (targetObject.Value == null)
			{
				return;
			}

			var go = Fsm.GetOwnerDefaultTarget(gameObject);
			if (go == null)
			{
				return;
			}
			
			if (cachedObject != go)
			{
				cachedObject = go;
				myTransform = go.transform;
			}
			
			if (cachedTarget != targetObject.Value)
			{
				cachedTarget = targetObject.Value;
				targetTransform = cachedTarget.transform;
			}
			
			
			// Calculate the current rotation angles
			var wantedRotationAngle = targetTransform.eulerAngles.y;
			var wantedHeight = targetTransform.position.y + height.Value;

			var currentRotationAngle = myTransform.eulerAngles.y;
			var currentHeight = myTransform.position.y;

			// Damp the rotation around the y-axis
			currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping.Value * Time.deltaTime);

			// Damp the height
			currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping.Value * Time.deltaTime);

			// Convert the angle into a rotation
			var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);

			// Set the position of the camera on the x-z plane to:
			// distance meters behind the target
			myTransform.position = targetTransform.position;
			myTransform.position -= currentRotation * Vector3.forward * distance.Value;

			// Set the height of the camera
			myTransform.position = new Vector3(myTransform.position.x, currentHeight, myTransform.position.z);

			// Always look at the target
			myTransform.LookAt(targetTransform);
		}

	}
}