namespace RioJoy.Core.Mapping;

/// <summary>
/// The per-profile <c>iRIO</c> table: 112 entries indexed by RIO address
/// (<c>0x00..0x6F</c>), each a <see cref="RioMapEntry"/>. Replaces the legacy
/// hard-coded <c>iRIO[]</c> array; a profile supplies the values (the legacy
/// defaults / <c>RIO.ini</c> become one importable profile in Phase 5/7).
/// </summary>
public sealed class RioInputMap
{
    private readonly ushort[] _entries = new ushort[RioAddress.TableSize];

    /// <summary>Create an empty map (all entries unmapped).</summary>
    public RioInputMap() { }

    /// <summary>Create a map from raw 16-bit words indexed by address.</summary>
    public RioInputMap(IDictionary<int, ushort> entries)
    {
        if (entries is null) throw new ArgumentNullException(nameof(entries));
        foreach ((int address, ushort raw) in entries)
            this[address] = new RioMapEntry(raw);
    }

    /// <summary>Number of addressable slots (<see cref="RioAddress.TableSize"/>).</summary>
    public int Count => _entries.Length;

    /// <summary>Get or set the entry at a RIO address (0x00..0x6F).</summary>
    public RioMapEntry this[int address]
    {
        get
        {
            ValidateAddress(address);
            return new RioMapEntry(_entries[address]);
        }
        set
        {
            ValidateAddress(address);
            _entries[address] = value.Raw;
        }
    }

    private static void ValidateAddress(int address)
    {
        if (address < 0 || address >= RioAddress.TableSize)
            throw new ArgumentOutOfRangeException(
                nameof(address), $"Address must be 0..0x{RioAddress.MaxAddress:X2}.");
    }
}
