using UnityEngine;
using UnityEngine.InputSystem;
#if UNITY_EDITOR
using UnityEditor;
#endif

// Say you want to distinguish a device not only by its type (e.g. "PS4 Controller")
// but also by the way it is used. This is a common scenario for VR controllers, for
// example, where the same type of controller may be used once in the left hand and
// once in the right hand. However, the need for distinguishing devices in a similar
// manner can pop up in a variety of situations. For example, on Switch it is used
// to distinguish the current orientation of the Joy-Con controller ("Horizontal" vs.
// "Vertical") allowing you to take orientation into account when binding actions.
//
// The input system allows you to distinguish devices based on the "usages" assigned
// to them. This is a generic mechanism that can be used to tag devices with arbitrary
// custom usages.
//
// To make this more concrete, let's say we have a game where two players control
// the game together each one using a gamepad but each receiving control over half
// the actions in the game.
//
// NOTE: What we do here is only one way to achieve this kind of setup. We could
//       alternatively go and just create one control scheme for the first player
//       and one control scheme for the second one and then have two PlayerInputs
//       each using one of the two.
//
// So, what we'd like to do is tag one gamepad with "Player1" and one gamepad with
// with "Player2". Then, in the actions we can set up a binding scheme specifically
// for this style of play and bind actions such that are driven either from the
// first player's gamepad or from the second player's gamepad (or from either).
//
// The first bit we need for this is to tell the input system that "Player1" and
// "Player2" are usages that we intend to apply to gamepads. For this, we need
// to modify the "Gamepad" layout. We do so by applying what's called a "layout
// override". This needs to happen during initialization so here we go:
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
public static class InitCustomDeviceUsages
{
    static InitCustomDeviceUsages()
    {
        Initialize();
    }

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    private static void Initialize()
    {
        // Here we register the layout override with the system.
        //
        // The layout override is just a fragment of layout information
        // in JSON format.
        //
        // The key property here is "commonUsages" which tells the system
        // that "Player1" and "Player2" are possible usages applied to devices
        // using the given layout ("Gamepad" in our case).
        InputSystem.RegisterLayoutOverride(@"
            {
                ""name"" : ""GamepadPlayerUsageTags"",
                ""extend"" : ""Gamepad"",
                ""commonUsages"" : [
                    ""Player1"", ""Player2""
                ]
            }
        ");

        // Now that we have done this, you will see that when using the
        // control picker in the action editor, that there is now a
        // "Gamepad (Player1)" and "Gamepad (Player2)" entry underneath
        // "Gamepad". When you select those, you can bind specifically
        // to a gamepad with the respective device usage.
        //
        // Also, you will now be able to *require* a device with the
        // given usage in a control scheme. So, when creating a control
        // scheme representing the shared Player1+Player2 controls,
        // you can add one "Gamepad (Player1)" and one "Gamepad (Player2)"
        // requirement.
        //
        // You can see an example setup for how this would look in an
        // .inputactions file in the TwoPlayerControls.inputactions file
        // that is part of this sample.
    }
}

// However, we are still missing a piece. At runtime, no gamepad will
// receive either the "Player1" or the "Player2" usage assignment yet.
// So none of the bindings will work yet.
//
// To assign the usage tags to the devices, we need to call
// InputSystem.AddDeviceUsage or SetDeviceUsage.
//
// We could set this up any which way. As a demonstration, let's create
// a MonoBehaviour here that simply associates a specific tag with a
// specific gamepad index.
//
// In practice, you would probably want to do the assignment in a place
// where you handle your player setup/joining.
public class CustomDeviceUsages : MonoBehaviour
{
    public int gamepadIndex;
    public string usageTag;

    private Gamepad m_Gamepad;

    protected void OnEnable()
    {
        if (gamepadIndex >= 0 && gamepadIndex < Gamepad.all.Count)
        {
            m_Gamepad = Gamepad.all[gamepadIndex];
            InputSystem.AddDeviceUsage(m_Gamepad, usageTag);
        }
    }

    protected void OnDisable()
    {
        // If we grabbed a gamepad and it's still added to the system,
        // remove the usage tag we added.
        if (m_Gamepad != null && m_Gamepad.added)
            InputSystem.RemoveDeviceUsage(m_Gamepad, usageTag);
        m_Gamepad = null;
    }
}