using Microsoft.VisualBasic.CompilerServices; using Newtonsoft.Json; using RhythmBase.Converters; using System.Numerics; using System.Runtime.CompilerServices; namespace RhythmBase.Components { /// /// Represents a room that can be applied to multiple rooms. /// [JsonConverter(typeof(RoomConverter))] public struct RDRoom : IEqualityOperators, IEquatable { /// /// Indicates if the top room can be applied. /// public bool EnableTop { get; } /// /// Gets or sets whether the specified room is enabled. /// /// The index of the room. /// True if the room is enabled; otherwise, false. [IndexerName("Room")] public bool this[byte Index] { readonly get => _data.HasFlag((RDRoomIndex)(1 << Index)); set { if (!(Index >= 4 && !EnableTop)) _data = value ? (_data | (RDRoomIndex)(1 << (int)Index)) : (_data & (RDRoomIndex)(1 << (int)Index)); } } /// /// Gets the list of enabled rooms. /// public readonly List Rooms { get { RDRoomIndex indexes = _data; return Enumerable .Range(0, 5) .Where(x => indexes.HasFlag((RDRoomIndex)(1 << x))) .Select(x => (byte)x) .ToList(); } } /// public override readonly string ToString() => string.Format("[{0}]", string.Join(",", Rooms)); /// /// Returns an instance with only room 1 enabled. /// /// An instance with only room 1 enabled. public static RDRoom Default() => new(false, []) { _data = RDRoomIndex.Room1 }; /// /// Initializes a new instance of the struct. /// /// Indicates if the top room can be applied. public RDRoom(bool enableTop) => EnableTop = enableTop; /// /// Initializes a new instance of the struct with specified rooms. /// /// Indicates if the top room can be applied. /// The rooms to be enabled. public RDRoom(bool enableTop, params byte[] rooms) { this = default; EnableTop = enableTop; int num = rooms.Length; if (num != 0) if (num != 1) foreach (byte item in rooms) this[item] = true; else this[rooms.Single()] = true; else _data = RDRoomIndex.RoomNotAvaliable; } /// /// Checks if the specified rooms are included. /// /// The rooms to check. /// True if the rooms are included; otherwise, false. public readonly bool Contains(RDRoom rooms) { if (_data == RDRoomIndex.RoomNotAvaliable) return false; else { for (int i = 0; i < 5; i++) { if (this[(byte)i] != rooms[(byte)i]) break; if (i > 4) return true; } return false; } } /// /// Checks if the specified room is included. /// /// The room to check. /// True if the room is included; otherwise, false. public readonly bool Contains(RDRoomIndex room) { return _data.HasFlag(room); } /// public static bool operator ==(RDRoom R1, RDRoom R2) => R1._data == R2._data; /// public static bool operator !=(RDRoom R1, RDRoom R2) => !(R1 == R2); /// /// Implicitly converts a SingleRoom to a Room. /// /// The SingleRoom instance to convert. /// A Room instance. public static implicit operator RDRoom(RDSingleRoom room) => new(room.EnableTop, [0, ((byte)room.Room)]); /// /// Explicitly converts a Room to a SingleRoom. /// /// The Room instance to convert. /// A SingleRoom instance. /// Thrown when the Room contains more than one room. public static explicit operator RDSingleRoom(RDRoom room) => room.Rooms.Count == 1 ? new RDSingleRoom(room.Rooms.Single()) : throw new Exceptions.RhythmBaseException(); /// public override readonly bool Equals(object? obj) => obj is RDRoom e && Equals(e); /// public override readonly int GetHashCode() => HashCode.Combine(_data); /// public readonly bool Equals(RDRoom other) => this == other; private RDRoomIndex _data; } }