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

using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
    [ActionCategory(ActionCategory.Transform)]
    [Tooltip("Smoothly Rotates a Game Object so its forward vector points in the specified Direction. Lets you fire an event when minmagnitude is reached")]
    public class SmoothLookAtDirection : FsmStateAction
    {
        [RequiredField]
        [Tooltip("The GameObject to rotate.")]
        public FsmOwnerDefault gameObject;

        [RequiredField]
        [Tooltip("The direction to smoothly rotate towards.")]
        public FsmVector3 targetDirection;

        [Tooltip("Only rotate if Target Direction Vector length is greater than this threshold.")]
        public FsmFloat minMagnitude;

        [Tooltip("Keep this vector pointing up as the GameObject rotates.")]
        public FsmVector3 upVector;

        [RequiredField]
        [Tooltip("Eliminate any tilt up/down as the GameObject rotates.")]
        public FsmBool keepVertical;

        [RequiredField]
        [HasFloatSlider(0.5f, 15)]
        [Tooltip("How quickly to rotate.")]
        public FsmFloat speed;

        [Tooltip("Perform in LateUpdate. This can help eliminate jitters in some situations.")]
        public bool lateUpdate;

        [Tooltip("Event to send if the direction difference is less than Min Magnitude.")]
        public FsmEvent finishEvent;

        [Tooltip("Stop running the action if the direction difference is less than Min Magnitude.")]
        public FsmBool finish;

        GameObject previousGo; // track game object so we can re-initialize when it changes.
        Quaternion lastRotation;
        Quaternion desiredRotation;

        public override void Reset()
        {
            gameObject = null;
            targetDirection = new FsmVector3 { UseVariable = true };
            minMagnitude = 0.1f;
            upVector = new FsmVector3 { UseVariable = true };
            keepVertical = true;
            speed = 5;
            lateUpdate = true;
            finishEvent = null;
        }

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

        public override void OnEnter()
        {
            previousGo = null;
        }

        public override void OnUpdate()
        {
            if (!lateUpdate)
            {
                DoSmoothLookAtDirection();
            }
        }

        public override void OnLateUpdate()
        {
            if (lateUpdate)
            {
                DoSmoothLookAtDirection();
            }
        }

        void DoSmoothLookAtDirection()
        {
            if (targetDirection.IsNone)
            {
                return;
            }

            var go = Fsm.GetOwnerDefaultTarget(gameObject);
            if (go == null)
            {
                return;
            }

            // re-initialize if game object has changed

            if (previousGo != go)
            {
                lastRotation = go.transform.rotation;
                desiredRotation = lastRotation;
                previousGo = go;
            }

            // desired direction

            var diff = targetDirection.Value;

            if (keepVertical.Value)
            {
                diff.y = 0;
            }

            var reachedTarget = false;
            if (diff.sqrMagnitude > minMagnitude.Value)
            {
                desiredRotation = Quaternion.LookRotation(diff, upVector.IsNone ? Vector3.up : upVector.Value);
            }
            else
            {
                reachedTarget = true;
            }
            
            lastRotation = Quaternion.Slerp(lastRotation, desiredRotation, speed.Value * Time.deltaTime);
            go.transform.rotation = lastRotation;
            
            if (reachedTarget) 
            {
                Fsm.Event(finishEvent);
                if (finish.Value)
                {
                    Finish();
                }
            }
        }
    }
}