using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Samples.StarterAssets;
namespace UnityEngine.XR.Content.Interaction
{
    /// 
    /// Use this class as a central manager to configure locomotion control schemes and configuration preferences.
    /// 
    public class LocomotionManager : MonoBehaviour
    {
        const ContinuousMoveProviderBase.GravityApplicationMode k_DefaultGravityApplicationMode =
            ContinuousMoveProviderBase.GravityApplicationMode.AttemptingMove;
        const ConstrainedMoveProvider.GravityApplicationMode k_DefaultGravityMode =
            ConstrainedMoveProvider.GravityApplicationMode.AttemptingMove;
        /// 
        /// Sets which movement control scheme to use.
        /// 
        /// 
        /// 
        public enum LocomotionType
        {
            /// 
            /// Use smooth (continuous) movement control scheme.
            /// 
            MoveAndStrafe,
            /// 
            /// Use teleport movement control scheme.
            /// 
            TeleportAndTurn,
        }
        /// 
        /// Sets which turn style of locomotion to use.
        /// 
        /// 
        /// 
        public enum TurnStyle
        {
            /// 
            /// Use snap turning to rotate the direction you are facing by snapping by a specified angle.
            /// 
            Snap,
            /// 
            /// Use continuous turning to smoothly rotate the direction you are facing by a specified speed.
            /// 
            Smooth,
        }
        [SerializeField]
        [Tooltip("Stores the locomotion provider for smooth (continuous) movement.")]
        DynamicMoveProvider m_DynamicMoveProvider;
        /// 
        /// Stores the locomotion provider for smooth (continuous) movement.
        /// 
        /// 
        public DynamicMoveProvider dynamicMoveProvider
        {
            get => m_DynamicMoveProvider;
            set => m_DynamicMoveProvider = value;
        }
        [SerializeField]
        [Tooltip("Stores the locomotion provider for smooth (continuous) turning.")]
        ContinuousTurnProviderBase m_SmoothTurnProvider;
        /// 
        /// Stores the locomotion provider for smooth (continuous) turning.
        /// 
        /// 
        public ContinuousTurnProviderBase smoothTurnProvider
        {
            get => m_SmoothTurnProvider;
            set => m_SmoothTurnProvider = value;
        }
        [SerializeField]
        [Tooltip("Stores the locomotion provider for snap turning.")]
        SnapTurnProviderBase m_SnapTurnProvider;
        /// 
        /// Stores the locomotion provider for snap turning.
        /// 
        /// 
        public SnapTurnProviderBase snapTurnProvider
        {
            get => m_SnapTurnProvider;
            set => m_SnapTurnProvider = value;
        }
        [SerializeField]
        [Tooltip("Stores the locomotion provider for two-handed grab movement.")]
        TwoHandedGrabMoveProvider m_TwoHandedGrabMoveProvider;
        /// 
        /// Stores the locomotion provider for two-handed grab movement.
        /// 
        /// 
        public TwoHandedGrabMoveProvider twoHandedGrabMoveProvider
        {
            get => m_TwoHandedGrabMoveProvider;
            set => m_TwoHandedGrabMoveProvider = value;
        }
        [SerializeField]
        [Tooltip("Reference to the manager that mediates the left-hand controllers.")]
        ActionBasedControllerManager m_LeftHandManager;
        [SerializeField]
        [Tooltip("Reference to the manager that mediates the right-hand controllers.")]
        ActionBasedControllerManager m_RightHandManager;
        [SerializeField]
        [Tooltip("Controls which movement control scheme to use for the left hand.")]
        LocomotionType m_LeftHandLocomotionType;
        /// 
        /// Controls which movement control scheme to use for the left hand.
        /// 
        /// 
        public LocomotionType leftHandLocomotionType
        {
            get => m_LeftHandLocomotionType;
            set
            {
                SetMoveScheme(value, true);
                m_LeftHandLocomotionType = value;
            }
        }
        [SerializeField]
        [Tooltip("Controls which movement control scheme to use for the right hand.")]
        LocomotionType m_RightHandLocomotionType;
        /// 
        /// Controls which movement control scheme to use for the left hand.
        /// 
        /// 
        public LocomotionType rightHandLocomotionType
        {
            get => m_RightHandLocomotionType;
            set
            {
                SetMoveScheme(value, false);
                m_RightHandLocomotionType = value;
            }
        }
        [SerializeField]
        [Tooltip("Controls which turn style of locomotion to use for the left hand.")]
        TurnStyle m_LeftHandTurnStyle;
        /// 
        /// Controls which turn style of locomotion to use for the left hand.
        /// 
        /// 
        public TurnStyle leftHandTurnStyle
        {
            get => m_LeftHandTurnStyle;
            set
            {
                SetTurnStyle(value, true);
                m_LeftHandTurnStyle = value;
            }
        }
        [SerializeField]
        [Tooltip("Controls which turn style of locomotion to use for the right hand.")]
        TurnStyle m_RightHandTurnStyle;
        /// 
        /// Controls which turn style of locomotion to use for the left hand.
        /// 
        /// 
        public TurnStyle rightHandTurnStyle
        {
            get => m_RightHandTurnStyle;
            set
            {
                SetTurnStyle(value, false);
                m_RightHandTurnStyle = value;
            }
        }
        [SerializeField]
        [Tooltip("Whether to enable the comfort mode that applies the tunneling vignette effect to smooth movement and turn.")]
        bool m_EnableComfortMode;
        public bool enableComfortMode
        {
            get => m_EnableComfortMode;
            set
            {
                m_EnableComfortMode = value;
                if (m_ComfortMode != null)
                    m_ComfortMode.SetActive(m_EnableComfortMode);
            }
        }
        [SerializeField]
        [Tooltip("Stores the GameObject for the comfort mode.")]
        GameObject m_ComfortMode;
        [SerializeField]
        [Tooltip("Whether gravity affects continuous and grab movement when flying is disabled.")]
        bool m_UseGravity;
        /// 
        /// Whether gravity affects continuous and grab movement when flying is disabled.
        /// 
        public bool useGravity
        {
            get => m_UseGravity;
            set
            {
                m_UseGravity = value;
                m_DynamicMoveProvider.useGravity = value;
                m_TwoHandedGrabMoveProvider.useGravity = value;
                m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.useGravity = value;
                m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.useGravity = value;
                if (value)
                {
                    m_DynamicMoveProvider.gravityApplicationMode = k_DefaultGravityApplicationMode;
                    m_TwoHandedGrabMoveProvider.gravityMode = k_DefaultGravityMode;
                    m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.gravityMode = k_DefaultGravityMode;
                    m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.gravityMode = k_DefaultGravityMode;
                }
            }
        }
        [SerializeField]
        [Tooltip("Whether to enable flying for continuous and grab movement. This overrides the use of gravity.")]
        bool m_EnableFly;
        /// 
        /// Whether to enable flying for continuous and grab movement. This overrides the use of gravity.
        /// 
        public bool enableFly
        {
            get => m_EnableFly;
            set
            {
                m_EnableFly = value;
                m_DynamicMoveProvider.enableFly = value;
                m_TwoHandedGrabMoveProvider.enableFreeYMovement = value;
                m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.enableFreeYMovement = value;
                m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.enableFreeYMovement = value;
            }
        }
        [SerializeField]
        [Tooltip("Whether to enable grab movement.")]
        bool m_EnableGrabMovement;
        /// 
        /// Whether to enable grab movement.
        /// 
        public bool enableGrabMovement
        {
            get => m_EnableGrabMovement;
            set
            {
                m_EnableGrabMovement = value;
                m_TwoHandedGrabMoveProvider.enabled = value;
                m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.enabled = value;
                m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.enabled = value;
            }
        }
        void OnEnable()
        {
            SetMoveScheme(m_LeftHandLocomotionType, true);
            SetMoveScheme(m_RightHandLocomotionType, false);
            SetTurnStyle(m_LeftHandTurnStyle, true);
            SetTurnStyle(m_RightHandTurnStyle, false);
            if (m_ComfortMode != null)
                m_ComfortMode.SetActive(m_EnableComfortMode);
            m_DynamicMoveProvider.useGravity = m_UseGravity;
            m_TwoHandedGrabMoveProvider.useGravity = m_UseGravity;
            m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.useGravity = m_UseGravity;
            m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.useGravity = m_UseGravity;
            if (m_UseGravity)
            {
                m_DynamicMoveProvider.gravityApplicationMode = k_DefaultGravityApplicationMode;
                m_TwoHandedGrabMoveProvider.gravityMode = k_DefaultGravityMode;
                m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.gravityMode = k_DefaultGravityMode;
                m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.gravityMode = k_DefaultGravityMode;
            }
            m_DynamicMoveProvider.enableFly = m_EnableFly;
            m_TwoHandedGrabMoveProvider.enableFreeYMovement = m_EnableFly;
            m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.enableFreeYMovement = m_EnableFly;
            m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.enableFreeYMovement = m_EnableFly;
            m_TwoHandedGrabMoveProvider.enabled = m_EnableGrabMovement;
            m_TwoHandedGrabMoveProvider.leftGrabMoveProvider.enabled = m_EnableGrabMovement;
            m_TwoHandedGrabMoveProvider.rightGrabMoveProvider.enabled = m_EnableGrabMovement;
        }
        void SetMoveScheme(LocomotionType scheme, bool leftHand)
        {
            var targetHand = leftHand ? m_LeftHandManager : m_RightHandManager;
            targetHand.smoothMotionEnabled = (scheme == LocomotionType.MoveAndStrafe);
        }
        void SetTurnStyle(TurnStyle style, bool leftHand)
        {
            var targetHand = leftHand ? m_LeftHandManager : m_RightHandManager;
            targetHand.smoothTurnEnabled = (style == TurnStyle.Smooth);
        }
    }
}