using RioJoy.Core.Calibration;

namespace RioJoy.Core.Mapping;

/// <summary>
/// An <see cref="IInputSink"/> that forwards to an inner sink only while
/// <see cref="Enabled"/> is set, and swallows output otherwise. Lets the editor put
/// real keyboard/mouse output behind a toggle (off by default, so editing the RIO
/// never injects input until the user opts in).
/// </summary>
public sealed class GatedInputSink : IInputSink
{
    private readonly IInputSink _inner;

    public GatedInputSink(IInputSink inner) =>
        _inner = inner ?? throw new ArgumentNullException(nameof(inner));

    /// <summary>When false, all output is dropped.</summary>
    public bool Enabled { get; set; }

    public void KeyDown(byte virtualKey, bool extended) { if (Enabled) _inner.KeyDown(virtualKey, extended); }

    public void KeyUp(byte virtualKey, bool extended) { if (Enabled) _inner.KeyUp(virtualKey, extended); }

    public void MouseMove(int dx, int dy) { if (Enabled) _inner.MouseMove(dx, dy); }

    public void MouseButton(MouseButton button, bool down) { if (Enabled) _inner.MouseButton(button, down); }
}

/// <summary>
/// An <see cref="IJoystickSink"/> that forwards to an inner sink only while
/// <see cref="Enabled"/> is set. The editor's output toggle gates the virtual
/// joystick the same way as the keyboard/mouse.
/// </summary>
public sealed class GatedJoystickSink : IJoystickSink
{
    private readonly IJoystickSink _inner;

    public GatedJoystickSink(IJoystickSink inner) =>
        _inner = inner ?? throw new ArgumentNullException(nameof(inner));

    /// <summary>When false, all output is dropped.</summary>
    public bool Enabled { get; set; }

    public void SetButton(int button, bool pressed) { if (Enabled) _inner.SetButton(button, pressed); }

    public void SetHat(RioHat position) { if (Enabled) _inner.SetHat(position); }

    public void SetAxis(JoyAxis axis, int value) { if (Enabled) _inner.SetAxis(axis, value); }
}
