/*============================================================================== 
 * Copyright (c) 2012-2014 Qualcomm Connected Experiences, Inc. All Rights Reserved. 
 * ==============================================================================*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// UI Event Handler class that handles events generated by user-tap actions
/// over the UI Options Menu
/// </summary>
public class UDTUIEventHandler : ISampleAppUIEventHandler { 
    
    #region PUBLIC_MEMBER_VARIABLES
    public override event System.Action CloseView;
    public override event System.Action GoToAboutPage;
    #endregion PUBLIC_MEMBER_VARIABLES
    
    #region PRIVATE_MEMBER_VARIABLES
    private static bool sExtendedTrackingIsEnabled;
    private UDTUIView mView;
    private bool mCameraFacingFront;
    #endregion PRIVATE_MEMBER_VARIABLES
    
    #region PUBLIC_MEMBER_PROPERTIES
    public UDTUIView View
    {
        get {
            if(mView == null){
                mView = new UDTUIView();
                mView.LoadView();
            }
            return mView;
        }
    }

    /// <summary>
    /// Currently, there is no mechanism to query the SDK to know whether or not extended tracking is enabled/disabled.
    /// Therefore, it needs to be handled at the app layer.
    /// </value>
    public static bool ExtendedTrackingIsEnabled
    {
        get {
            return sExtendedTrackingIsEnabled;
        }
    }

    #endregion PUBLIC_MEMBER_PROPERTIES
    
    #region PUBLIC_METHODS
    public override void UpdateView (bool tf)
    {
        this.View.UpdateUI(tf);
    }

    public override  void Bind()
    {
        this.View.mExtendedTracking.TappedOn    += OnTappedToTurnOnTraking;
        this.View.mCameraFlashSettings.TappedOn += OnTappedToTurnOnFlash;
        this.View.mAutoFocusSetting.TappedOn    += OnTappedToTurnOnAutoFocus;
        this.View.mCameraFacing.TappedOnOption  += OnTappedToTurnCameraFacing;
        this.View.mCloseButton.TappedOn         += OnTappedOnCloseButton;
        this.View.mAboutLabel.TappedOn          += OnTappedOnAboutButton;
        EnableContinuousAutoFocus();
    }
    
    public override  void UnBind()
    { 
        this.View.mExtendedTracking.TappedOn    -= OnTappedToTurnOnTraking;
        this.View.mCameraFlashSettings.TappedOn -= OnTappedToTurnOnFlash;
        this.View.mAutoFocusSetting.TappedOn    -= OnTappedToTurnOnAutoFocus;
        this.View.mCameraFacing.TappedOnOption  -= OnTappedToTurnCameraFacing;
        this.View.mCloseButton.TappedOn         -= OnTappedOnCloseButton;
        this.View.mAboutLabel.TappedOn          -= OnTappedOnAboutButton;
        sExtendedTrackingIsEnabled = false;
        this.View.UnLoadView();
    }
    
    //SingleTap Gestures are captured by AppManager and calls this method for TapToFocus
    public override  void TriggerAutoFocus()
    {
        StartCoroutine(TriggerAutoFocusAndEnableContinuousFocusIfSet());
    }
    
    public override  void SetToDefault(bool tf)
    {
        this.View.mCameraFlashSettings.Enable(tf);
    }
    #endregion PUBLIC_METHODS
    
    #region PRIVATE_METHODS
    
    
    /// <summary>
    /// Activating trigger autofocus mode unsets continuous focus mode (if was previously enabled from the UI Options Menu)
    /// So, we wait for a second and turn continuous focus back on (if options menu shows as enabled)
    /// </returns>
    private IEnumerator TriggerAutoFocusAndEnableContinuousFocusIfSet()
    {
        //triggers a single autofocus operation 
        if (CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_TRIGGERAUTO)) {
            this.View.FocusMode = CameraDevice.FocusMode.FOCUS_MODE_TRIGGERAUTO;
        }
        
        yield return new WaitForSeconds(1.0f);
        
        //continuous focus mode is turned back on if it was previously enabled from the options menu
        if(this.View.mAutoFocusSetting.IsEnabled)
        {
            if (CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO)) {
                this.View.FocusMode = CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO;
            }
        }
        
        Debug.Log (this.View.FocusMode);
        
    }
    
    private void OnTappedOnAboutButton(bool tf)
    {
        if(this.GoToAboutPage != null)
        {
            this.GoToAboutPage();
        }
    }
    
    //We want autofocus to be enabled when the app starts
    private void EnableContinuousAutoFocus()
    {
        if (CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO))
        {
            this.View.FocusMode = CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO;
            this.View.mAutoFocusSetting.Enable(true);
        }
    }

    private void OnTappedToTurnOnTraking(bool tf)
    {
        sExtendedTrackingIsEnabled = tf;
        if(!ExtendedTracking(tf))
        {
            sExtendedTrackingIsEnabled = false;
            this.View.mExtendedTracking.Enable(false);
        }
        else
        {
            this.View.mExtendedTracking.Enable(tf);
        }
        OnTappedToClose();
    }
    
    private void OnTappedToTurnOnFlash(bool tf)
    {
        if(tf)
        {
            if(!CameraDevice.Instance.SetFlashTorchMode(true) || mCameraFacingFront)
            {
                this.View.mCameraFlashSettings.Enable(false);
            }
        }
        else 
        {
            CameraDevice.Instance.SetFlashTorchMode(false);
        }
        
            Debug.Log ("CameraFacingFront = " + mCameraFacingFront);
        OnTappedToClose();
    }
    
    private void OnTappedToTurnOnAutoFocus(bool tf)
    {
        if(tf)
        {
            if (CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO))
            {
                this.View.FocusMode = CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO;
            }
            else 
            {
                this.View.mAutoFocusSetting.Enable(false);
            }
        }
        else 
        {
            if (CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_NORMAL))
            {
                this.View.FocusMode = CameraDevice.FocusMode.FOCUS_MODE_NORMAL;
            }
        }
        
        OnTappedToClose();
    }
    
    private void OnTappedToTurnCameraFacing(int val)
    {
        if (val == 0)
        {
            //internally, flash is always turned off everytime it tries to switch to front camera
            //so updating the UI options to reflect that.
            this.View.mCameraFlashSettings.Enable(false);

            if (ChangeCameraDirection(CameraDevice.CameraDirection.CAMERA_FRONT))
            {
                mCameraFacingFront = true;
            }
            else
            {
                ChangeCameraDirection(CameraDevice.CameraDirection.CAMERA_BACK);
                mCameraFacingFront = false;
                this.View.mCameraFacing.EnableIndex(1);
            }
        }
        else
        {
            ChangeCameraDirection(CameraDevice.CameraDirection.CAMERA_BACK);
            mCameraFacingFront = false;
        }

        OnTappedToClose();
    }
    
    private void ResetCameraFacingToBack()
    {
        CameraDevice.Instance.Stop();
        CameraDevice.Instance.Init(CameraDevice.CameraDirection.CAMERA_BACK);
        CameraDevice.Instance.Start();
        mCameraFacingFront = false;
    }

    private bool ChangeCameraDirection(CameraDevice.CameraDirection direction)
    {
        bool directionSupported = false;
        CameraDevice.Instance.Stop();
        CameraDevice.Instance.Deinit();
        if (CameraDevice.Instance.Init(direction))
        {
            directionSupported = true;
        }
        CameraDevice.Instance.Start();

        return directionSupported;
    }
    
    private void OnTappedToClose()
    {
        if(this.CloseView != null)
        {
            this.CloseView();
        }
    }
    
    private void OnTappedOnCloseButton()
    {
        OnTappedToClose();
    }
    
    /// <summary>
    /// This method turns extended tracking on or off for all currently available targets.
    /// Extended tracking allows to track targets when they are not in view.
    /// Returns true of extended tracking is supported; false otherwise
    /// </summary>
    private bool ExtendedTracking(bool tf)
    {
        // the StateManager gives access to all available TrackableBehavours
        StateManager stateManager = TrackerManager.Instance.GetStateManager();

        // We iterate over all TrackableBehaviours to start or stop extended tracking for the targets they represent.
        foreach(var behaviour in stateManager.GetTrackableBehaviours())
        {
            var imageBehaviour = behaviour as ImageTargetBehaviour;
            if(imageBehaviour != null)
            {
                imageBehaviour.ImageTarget.StopExtendedTracking();
            }
        }

        //As of now, UserDefinedTargets can handle Enable/Disable ExtendedTracking on only one TrackableBehaviour.
        //So, we find the latest TrackableBehaviour from the set of user-defined targets and start/stop extended tracking on it.
        List<TrackableBehaviour> list =  stateManager.GetTrackableBehaviours().ToList();

        if (list.Count > 0)
        {
            ImageTargetBehaviour bhvr = list[list.Count - 1] as ImageTargetBehaviour;
            Debug.Log("ImageTargetBehaviour " + bhvr.gameObject.name);
            if (bhvr != null)
            {
                if (tf)
                {
                    if (bhvr.ImageTarget.StartExtendedTracking())
                    {
                        return true;
                    }
                    else
                    {
                        Debug.LogWarning("Extended Tracking is not supported on this device");
                        return false;
                    }
                }
                else
                {
                    if (bhvr.ImageTarget.StopExtendedTracking())
                    {
                        return true;
                    }
                    else
                    {
                        Debug.LogWarning("Extended Tracking is not supported on this device");
                        return false;
                    }
                }
            }
        }
        else
        {
            return tf;
        }

        return tf;
    }
    
    #endregion PRIVATE_METHODS

}

