﻿using UnityEngine;

namespace SimplifyXR
{
    /// <summary>
    /// This adapter is the main interface for Simplify to VisionLib
    /// </summary>
    public class VisionLibAdapter : SimplifyXRTargetAdapter
    {
        #region Public Fields
        /// <summary>
        /// If true, the camera will start tracking this target when the target is active in the scene. If false, use the StartTrackingTarget Action to track this target.
        /// </summary>
#if UNITY_EDITOR
        [Tooltip("If true, the camera will start tracking this target when the target is active in the scene. If false, use the StartTrackingTarget Action to track this target.")]
#endif
        public bool StartTrackingImmediately = true;
#if UNITY_WSA
		public bool AutoLock = true;
#else
        [HideInInspector]
        public bool AutoLock = false;
#endif
        /// <summary>
        /// The name of the tracker file that this adapter will monitor
        /// </summary>
#if UNITY_EDITOR
        [Tooltip("The name of the tracker file that this adapter will monitor")]
#endif
        public string FileNameOfTracker = "";
        #endregion

#if USING_VISIONLIB
        #region Private Fields
        //Reference to the VLWorker. Stored for starting the tracking in the Start method
        protected VLWorkerBehaviour vLWorker;
        //Limitation of VL. Only one target with the name "TrackedObject" is returned by the tool
        string TrackedObjectName = "TrackedObject";
        //Stores the previous state of the VLTrackingState so that it can be compared against
        string previousState;
        //A reference to the lock object
        GameObject lockObject;
        public GameObject LockObject { get { return lockObject; } set { lockObject = value; } }

        GameObject anchor;
        public GameObject contentHolder;
        #endregion

        #region Monobehaviours
        //Set the target manager behavior
        protected void Awake()
        {
            SimplifyXRTargetManager.Instance.SetBehavior(new VisionLibImageTargetManagerBehaviour());
            TrackingManager.Instance.SetTrackingManagerBehavior(new BaseTrackingCameraBehavior());
        }
        //Initial behavior set
        public void Start()
        {
            //Initialize the tracking behaviors and grab references
            vLWorker = GameObject.FindObjectOfType<VLWorkerBehaviour>();
            if (vLWorker == null)
            {
                SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorError, "[TARGET] The VisionLibAdapter {0} must be placed in a scene with a VLWorkerBehaviour. Please add a VLWorkerBehaviour to this scene.", SimplifyXRDebug.Args(GetTargetName()));
                return;
            }
            if (contentHolder == null)
            {
                SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorError, "[TARGET] The VisionLibAdapter {0} must have a content holder assigned to it.", SimplifyXRDebug.Args(GetTargetName()));
                return;
            }

            SimplifyXRTargetManager.Instance.TrackPreloadedObject(this);

            SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorDebug, "[TARGET] New target {0} being tracked", SimplifyXRDebug.Args(GetTargetName()));

            //Determine if the user would like to start tracking immediately or not
            if (StartTrackingImmediately)
            {
                StartTracking();
            }
        }
        //Event subscription
        protected void OnEnable()
        {
            VLWorkerBehaviour.OnTrackingStates += HandleTrackingStates;

            //HACK this method is terrible
            anchor = GameObject.Find("VLHoloLensWorldAnchor");

        }
        //Unsubscribe from events
        protected void OnDisable()
        {
            VLWorkerBehaviour.OnTrackingStates -= HandleTrackingStates;
        }
        //Stop tracking this object
        protected void OnDestroy()
        {
            SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorDebug, "[TARGET] Target {0} destroyed", SimplifyXRDebug.Args(GetTargetName()));

            if (contentHolder != null)
                GameObject.Destroy(contentHolder);
            if (anchor != null)
                GameObject.Destroy(anchor);

            SimplifyXRTargetManager.Instance.RemoveObject(GetTargetName());
            vLWorker.ResetTrackingHard();
        }
        #endregion

        #region Public methods
        /// <summary>
        /// Get the target name for this TrackableBehaviour
        /// </summary>
        public override string GetTargetName()
        {
            return FileNameOfTracker;
        }
        /// <summary>
        /// Starts the tracking on this object
        /// </summary>
        public void StartTracking()
        {
            if (!string.IsNullOrEmpty(FileNameOfTracker))
                vLWorker.StartTracking(FileNameOfTracker);
            else
                SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorError, "[TARGET] The File name on the VisionLibAdapter, {0}, is empty. Please specify which object to start tracking.", SimplifyXRDebug.Args(GetTargetName()));
        }
        /// <summary>
        /// Stops the tracking on any tracked object
        /// </summary>
        public void StopTracking()
        {
            vLWorker.StopTracking();
        }
        #endregion

        #region Private Methods
        //Manage the states of the tracking
        void HandleTrackingStates(VLTrackingState state)
        {
            for (int i = 0; i < state.objects.Length; ++i)
            {
                VLTrackingState.TrackingObject obj = state.objects[i];

                if (obj.name == TrackedObjectName)
                {
                    if (obj.state == "tracked")
                    {
                        if (this.previousState != obj.state)
                        {
                            CallPoseFound();
                            this.previousState = obj.state;
                            if (AutoLock)
                                LockTarget();
                        }
                    }
                    else if (obj.state == "lost")
                    {
                        if (this.previousState != obj.state)
                        {
                            CallPoseLost();
                            this.previousState = obj.state;
                        }
                    }
                    break;
                }
            }
        }

        private void LockTarget()
        {
            StopTracking();
        }
        #endregion
#else
        #region Public Not Implemented methods
        /// <summary>
        /// Starts the tracking on this object
        /// </summary>
        public void StartTracking()
        {
            SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorError, "Not implemented since VisionLib Unity package is not imported.");
        }
        /// <summary>
        /// Stops the tracking on any tracked object
        /// </summary>
        public void StopTracking()
        {
            SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorError, "Not implemented since VisionLib Unity package is not imported.");
        }
        #endregion
#endif
    }
}