//======= Copyright (c) Valve Corporation, All rights reserved. ===============
using UnityEngine;
using System.Collections;
using System;
using Valve.VR;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace Valve.VR
{
    [Serializable]
    /// 
    /// In actions are all input type actions. Boolean, Single, Vector2, Vector3, Skeleton, and Pose.
    /// 
    public abstract class SteamVR_Action_In : SteamVR_Action, ISteamVR_Action_In
        where SourceMap : SteamVR_Action_In_Source_Map, new()
        where SourceElement : SteamVR_Action_In_Source, new()
    {
        /// [Shortcut to: SteamVR_Input_Sources.Any] Returns true if the action has been changed since the previous update
        public bool changed { get { return sourceMap[SteamVR_Input_Sources.Any].changed; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] Returns true if the action was changed for the previous update cycle
        public bool lastChanged { get { return sourceMap[SteamVR_Input_Sources.Any].changed; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The time the action was changed (Time.realtimeSinceStartup)
        public float changedTime { get { return sourceMap[SteamVR_Input_Sources.Any].changedTime; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The time the action was updated (Time.realtimeSinceStartup)
        public float updateTime { get { return sourceMap[SteamVR_Input_Sources.Any].updateTime; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The handle to the component that triggered the action to be changed
        public ulong activeOrigin { get { return sourceMap[SteamVR_Input_Sources.Any].activeOrigin; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The handle to the component that triggered the action to be changed in the previous update
        public ulong lastActiveOrigin { get { return sourceMap[SteamVR_Input_Sources.Any].lastActiveOrigin; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The input source that triggered the action to be changed
        public SteamVR_Input_Sources activeDevice { get { return sourceMap[SteamVR_Input_Sources.Any].activeDevice; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The device index (used by Render Models) used by the device that triggered the action to be changed
        public uint trackedDeviceIndex { get { return sourceMap[SteamVR_Input_Sources.Any].trackedDeviceIndex; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The name of the component on the render model that caused the action to be changed (not localized)
        public string renderModelComponentName { get { return sourceMap[SteamVR_Input_Sources.Any].renderModelComponentName; } }
        /// [Shortcut to: SteamVR_Input_Sources.Any] The full localized name for the component, controller, and hand that caused the action to be changed
        public string localizedOriginName { get { return sourceMap[SteamVR_Input_Sources.Any].localizedOriginName; } }
        /// 
        /// [Should not be called by user code]
        /// Updates the data for all the input sources the system has detected need to be updated.
        /// 
        public virtual void UpdateValues()
        {
            sourceMap.UpdateValues();
        }
        /// 
        /// The name of the component on the render model that caused the action to be updated (not localized)
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public virtual string GetRenderModelComponentName(SteamVR_Input_Sources inputSource)
        {
            return sourceMap[inputSource].renderModelComponentName;
        }
        /// 
        /// The input source that triggered the action to be updated last
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public virtual SteamVR_Input_Sources GetActiveDevice(SteamVR_Input_Sources inputSource)
        {
            return sourceMap[inputSource].activeDevice;
        }
        /// 
        /// Gets the device index for the controller this action is bound to. This can be used for render models or the pose tracking system.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public virtual uint GetDeviceIndex(SteamVR_Input_Sources inputSource)
        {
            return sourceMap[inputSource].trackedDeviceIndex;
        }
        /// 
        /// Indicates whether or not the data for this action and specified input source has changed since the last update. Determined by SteamVR or 'changeTolerance'.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public virtual bool GetChanged(SteamVR_Input_Sources inputSource)
        {
            return sourceMap[inputSource].changed;
        }
        /// 
        /// The time the action was changed (Time.realtimeSinceStartup)
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public override float GetTimeLastChanged(SteamVR_Input_Sources inputSource)
        {
            return sourceMap[inputSource].changedTime;
        }
        /// 
        /// Gets the localized name of the device that the action corresponds to. Include as many EVRInputStringBits as you want to add to the localized string
        /// 
        /// 
        /// 
        /// 
        /// - VRInputString_Hand - Which hand the origin is in. ex: "Left Hand". 
 
        /// - VRInputString_ControllerType - What kind of controller the user has in that hand. ex: "Vive Controller". 
 
        /// - VRInputString_InputSource - What part of that controller is the origin. ex: "Trackpad". 
 
        /// - VRInputString_All - All of the above. ex: "Left Hand Vive Controller Trackpad". 
 
        /// 
        /// 
        public string GetLocalizedOriginPart(SteamVR_Input_Sources inputSource, params EVRInputStringBits[] localizedParts)
        {
            return sourceMap[inputSource].GetLocalizedOriginPart(localizedParts);
        }
        /// 
        /// Gets the localized full name of the device that the action was updated by. ex: "Left Hand Vive Controller Trackpad"
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public string GetLocalizedOrigin(SteamVR_Input_Sources inputSource)
        {
            return sourceMap[inputSource].GetLocalizedOrigin();
        }
        /// 
        /// [Should not be called by user code]
        /// Returns whether the system has determined this source should be updated (based on code calls)
        /// Should only be used if you've set SteamVR_Action.startUpdatingSourceOnAccess to false.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public override bool IsUpdating(SteamVR_Input_Sources inputSource)
        {
            return sourceMap.IsUpdating(inputSource);
        }
        /// 
        /// [Should not be called by user code]
        /// Forces the system to start updating the data for this action and the specified input source.
        /// Should only be used if you've set SteamVR_Action.startUpdatingSourceOnAccess to false.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public void ForceAddSourceToUpdateList(SteamVR_Input_Sources inputSource)
        {
            sourceMap.ForceAddSourceToUpdateList(inputSource);
        }
        /// 
        /// Returns a string for the type of controller that was being used the last time the action was triggered. Common types: 
        /// vive_controller, oculus_touch, knuckles, vive_cosmos_controller, logitech_stylus
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public string GetControllerType(SteamVR_Input_Sources inputSource)
        {
            return SteamVR.instance.GetStringProperty(ETrackedDeviceProperty.Prop_ControllerType_String, GetDeviceIndex(inputSource));
        }
    }
    public class SteamVR_Action_In_Source_Map : SteamVR_Action_Source_Map
        where SourceElement : SteamVR_Action_In_Source, new()
    {
        protected List updatingSources = new List();
        /// 
        /// [Should not be called by user code]
        /// Returns whether the system has determined this source should be updated (based on code calls)
        /// Should only be used if you've set SteamVR_Action.startUpdatingSourceOnAccess to false.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public bool IsUpdating(SteamVR_Input_Sources inputSource)
        {
            int isUpdatingSourceIndex = (int)inputSource;
            for (int sourceIndex = 0; sourceIndex < updatingSources.Count; sourceIndex++)
            {
                if (isUpdatingSourceIndex == updatingSources[sourceIndex])
                    return true;
            }
            return false;
        }
        protected override void OnAccessSource(SteamVR_Input_Sources inputSource)
        {
            if (SteamVR_Action.startUpdatingSourceOnAccess)
            {
                ForceAddSourceToUpdateList(inputSource);
            }
        }
        /// 
        /// [Should not be called by user code]
        /// Forces the system to start updating the data for this action and the specified input source.
        /// Should only be used if you've set SteamVR_Action.startUpdatingSourceOnAccess to false.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        public void ForceAddSourceToUpdateList(SteamVR_Input_Sources inputSource)
        {
            int sourceIndex = (int)inputSource;
            if (sources[sourceIndex] == null)
            {
                sources[sourceIndex] = new SourceElement();
            }
            if (sources[sourceIndex].isUpdating == false)
            {
                updatingSources.Add(sourceIndex);
                sources[sourceIndex].isUpdating = true;
                if (SteamVR_Input.isStartupFrame == false)
                    sources[sourceIndex].UpdateValue();
            }
        }
        /// 
        /// [Should not be called by user code]
        /// Updates the data for all the input sources the system has detected need to be updated.
        /// 
        public void UpdateValues()
        {
            for (int sourceIndex = 0; sourceIndex < updatingSources.Count; sourceIndex++)
            {
                sources[updatingSources[sourceIndex]].UpdateValue();
            }
        }
    }
    /// 
    /// In actions are all input type actions. Boolean, Single, Vector2, Vector3, Skeleton, and Pose.
    /// This class fires onChange and onUpdate events.
    /// 
    public abstract class SteamVR_Action_In_Source : SteamVR_Action_Source, ISteamVR_Action_In_Source
    {
        protected static uint inputOriginInfo_size = 0;
        /// 
        /// [Should not be called by user code]
        /// Forces the system to start updating the data for this action and the specified input source.
        /// Should only be used if you've set SteamVR_Action.startUpdatingSourceOnAccess to false.
        /// 
        public bool isUpdating { get; set; }
        /// The time the action was updated (Time.realtimeSinceStartup)
        public float updateTime { get; protected set; }
        /// The handle to the component that triggered the action to be changed
        public abstract ulong activeOrigin { get; }
        /// The handle to the component that triggered the action to be changed in the previous update
        public abstract ulong lastActiveOrigin { get; }
        /// Returns true if the action has been changed since the previous update
        public abstract bool changed { get; protected set; }
        /// Returns true if the action was changed for the previous update cycle
        public abstract bool lastChanged { get; protected set; }
        /// The input source that triggered the action to be updated
        public SteamVR_Input_Sources activeDevice { get { UpdateOriginTrackedDeviceInfo();  return SteamVR_Input_Source.GetSource(inputOriginInfo.devicePath); } }
        /// The device index (used by Render Models) used by the device that triggered the action to be updated
        public uint trackedDeviceIndex { get { UpdateOriginTrackedDeviceInfo(); return inputOriginInfo.trackedDeviceIndex; } }
        /// The name of the component on the render model that caused the action to be updated (not localized)
        public string renderModelComponentName { get { UpdateOriginTrackedDeviceInfo(); return inputOriginInfo.rchRenderModelComponentName; } }
        /// 
        /// Gets the localized full name of the device that the action was updated by. ex: "Left Hand Vive Controller Trackpad"
        /// 
        public string localizedOriginName { get { UpdateOriginTrackedDeviceInfo(); return GetLocalizedOrigin(); } }
        /// The Time.realtimeSinceStartup that this action was last changed.
        public float changedTime { get; protected set; }
        protected int lastOriginGetFrame { get; set; }
        protected InputOriginInfo_t inputOriginInfo = new InputOriginInfo_t();
        protected InputOriginInfo_t lastInputOriginInfo = new InputOriginInfo_t();
        /// [Should not be called by user code] Updates the data for this action and this input source
        public abstract void UpdateValue();
        /// 
        /// [Should not be called by user code] Initializes the handle for the action, the size of the InputOriginInfo struct, and any other related SteamVR data.
        /// 
        public override void Initialize()
        {
            base.Initialize();
            if (inputOriginInfo_size == 0)
                inputOriginInfo_size = (uint)Marshal.SizeOf(typeof(InputOriginInfo_t));
        }
        protected void UpdateOriginTrackedDeviceInfo()
        {
            if (lastOriginGetFrame != Time.frameCount) //only get once per frame
            {
                EVRInputError err = OpenVR.Input.GetOriginTrackedDeviceInfo(activeOrigin, ref inputOriginInfo, inputOriginInfo_size);
                if (err != EVRInputError.None)
                    Debug.LogError("[SteamVR] GetOriginTrackedDeviceInfo error (" + fullPath + "): " + err.ToString() + " handle: " + handle.ToString() + " activeOrigin: " + activeOrigin.ToString() + " active: " + active);
                lastInputOriginInfo = inputOriginInfo;
                lastOriginGetFrame = Time.frameCount;
            }
        }
        /// 
        /// Gets the localized name of the device that the action corresponds to. Include as many EVRInputStringBits as you want to add to the localized string
        /// 
        /// 
        /// 
        /// 
        /// - VRInputString_Hand - Which hand the origin is in. ex: "Left Hand". 
 
        /// - VRInputString_ControllerType - What kind of controller the user has in that hand. ex: "Vive Controller". 
 
        /// - VRInputString_InputSource - What part of that controller is the origin. ex: "Trackpad". 
 
        /// - VRInputString_All - All of the above. ex: "Left Hand Vive Controller Trackpad". 
 
        /// 
        /// 
        public string GetLocalizedOriginPart(params EVRInputStringBits[] localizedParts)
        {
            UpdateOriginTrackedDeviceInfo();
            if (active)
            {
                return SteamVR_Input.GetLocalizedName(activeOrigin, localizedParts);
            }
            return null;
        }
        /// 
        /// Gets the localized full name of the device that the action was updated by. ex: "Left Hand Vive Controller Trackpad"
        /// 
        public string GetLocalizedOrigin()
        {
            UpdateOriginTrackedDeviceInfo();
            if (active)
            {
                return SteamVR_Input.GetLocalizedName(activeOrigin, EVRInputStringBits.VRInputString_All);
            }
            return null;
        }
    }
    public interface ISteamVR_Action_In : ISteamVR_Action, ISteamVR_Action_In_Source
    {
        /// 
        /// [Should not be called by user code]
        /// Updates the data for all the input sources the system has detected need to be updated.
        /// 
        void UpdateValues();
        /// 
        /// The name of the component on the render model that caused the action to be updated (not localized)
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        string GetRenderModelComponentName(SteamVR_Input_Sources inputSource);
        /// 
        /// The input source that triggered the action to be updated last
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        SteamVR_Input_Sources GetActiveDevice(SteamVR_Input_Sources inputSource);
        /// 
        /// Gets the device index for the controller this action is bound to. This can be used for render models or the pose tracking system.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        uint GetDeviceIndex(SteamVR_Input_Sources inputSource);
        /// 
        /// Indicates whether or not the data for this action and specified input source has changed since the last update. Determined by SteamVR or 'changeTolerance'.
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        bool GetChanged(SteamVR_Input_Sources inputSource);
        /// 
        /// Gets the localized name of the device that the action corresponds to. Include as many EVRInputStringBits as you want to add to the localized string
        /// 
        /// 
        /// 
        /// 
        /// - VRInputString_Hand - Which hand the origin is in. ex: "Left Hand". 
 
        /// - VRInputString_ControllerType - What kind of controller the user has in that hand. ex: "Vive Controller". 
 
        /// - VRInputString_InputSource - What part of that controller is the origin. ex: "Trackpad". 
 
        /// - VRInputString_All - All of the above. ex: "Left Hand Vive Controller Trackpad". 
 
        /// 
        /// 
        string GetLocalizedOriginPart(SteamVR_Input_Sources inputSource, params EVRInputStringBits[] localizedParts);
        /// 
        /// Gets the localized full name of the device that the action was updated by. ex: "Left Hand Vive Controller Trackpad"
        /// 
        /// The device you would like to get data from. Any if the action is not device specific.
        string GetLocalizedOrigin(SteamVR_Input_Sources inputSource);
    }
    public interface ISteamVR_Action_In_Source : ISteamVR_Action_Source
    {
        /// Returns true if the action has been changed in the most recent update
        bool changed { get; }
        /// Returns true if the action was changed for the previous update cycle
        bool lastChanged { get; }
        /// The Time.realtimeSinceStartup that this action was last changed.
        float changedTime { get; }
        /// The time the action was updated (Time.realtimeSinceStartup)
        float updateTime { get; }
        /// The handle to the component that triggered the action to be changed
        ulong activeOrigin { get; }
        /// The handle to the component that triggered the action to be changed in the previous update
        ulong lastActiveOrigin { get; }
        /// The input source that triggered the action to be updated
        SteamVR_Input_Sources activeDevice { get; }
        /// The device index (used by Render Models) used by the device that triggered the action to be updated
        uint trackedDeviceIndex { get; }
        /// The name of the component on the render model that caused the action to be updated (not localized)
        string renderModelComponentName { get; }
        /// Gets the localized full name of the device that the action was updated by. ex: "Left Hand Vive Controller Trackpad"
        string localizedOriginName { get; }
    }
}