using System; using System.Collections.Generic; using System.Linq; using SabreTools.Library.Filtering; using Newtonsoft.Json; namespace SabreTools.Library.DatItems { /// /// Represents the information specific to a set/game/machine /// public class Machine : ICloneable { #region Fields #region Common Fields /// /// Name of the machine /// [JsonProperty("name")] public string Name { get; set; } = null; /// /// Additional notes /// [JsonProperty("comment")] public string Comment { get; set; } = null; /// /// Extended description /// [JsonProperty("description")] public string Description { get; set; } = null; /// /// Year(s) of release/manufacture /// [JsonProperty("year")] public string Year { get; set; } = null; /// /// Manufacturer, if available /// [JsonProperty("manufacturer")] public string Manufacturer { get; set; } = null; /// /// Publisher, if available /// [JsonProperty("publisher")] public string Publisher { get; set; } = null; /// /// Category, if available /// [JsonProperty("category")] public string Category { get; set; } = null; /// /// fomof parent /// [JsonProperty("romof")] public string RomOf { get; set; } = null; /// /// cloneof parent /// [JsonProperty("cloneof")] public string CloneOf { get; set; } = null; /// /// sampleof parent /// [JsonProperty("sampleof")] public string SampleOf { get; set; } = null; #endregion #region AttractMode Fields /// /// Player count /// [JsonProperty("players")] public string Players { get; set; } = null; /// /// Screen rotation /// [JsonProperty("rotation")] public string Rotation { get; set; } = null; /// /// Control method /// [JsonProperty("control")] public string Control { get; set; } = null; /// /// Support status /// [JsonProperty("status")] public string Status { get; set; } = null; /// /// Display count /// [JsonProperty("displaycount")] public string DisplayCount { get; set; } = null; /// /// Display type /// [JsonProperty("displaytype")] public string DisplayType { get; set; } = null; /// /// Number of input buttons /// [JsonProperty("buttons")] public string Buttons { get; set; } = null; #endregion #region ListXML Fields /// /// Emulator source file related to the machine /// [JsonProperty("sourcefile")] public string SourceFile { get; set; } = null; /// /// Machine runnable status /// /// yes = true, partial = null, no = false [JsonProperty("runnable")] public bool? Runnable { get; set; } = null; /// /// List of associated device names /// [JsonProperty("devices")] public List Devices { get; set; } = null; /// /// List of slot options /// [JsonProperty("slotoptions")] public List SlotOptions { get; set; } = null; /// /// List of info items /// [JsonProperty("infos")] public List> Infos { get; set; } = null; /// /// Type of the machine /// [JsonProperty("type")] public MachineType MachineType { get; set; } = MachineType.NULL; #endregion #region Logiqx Fields /// /// Machine board name /// [JsonProperty("board")] public string Board { get; set; } = null; /// /// Rebuild location if different than machine name /// [JsonProperty("rebuildto")] public string RebuildTo { get; set; } = null; #endregion #region SoftwareList Fields /// /// Support status /// /// yes = true, partial = null, no = false [JsonProperty("supported")] public bool? Supported { get; set; } = true; #endregion #endregion #region Accessors /// /// Get the value of that field as a string, if possible /// public string GetField(Field field, List excludeFields) { // If the field is to be excluded, return empty string if (excludeFields.Contains(field)) return string.Empty; string fieldValue = null; switch (field) { // Common case Field.MachineName: fieldValue = Name; break; case Field.Comment: fieldValue = Comment; break; case Field.Description: fieldValue = Description; break; case Field.Year: fieldValue = Year; break; case Field.Manufacturer: fieldValue = Manufacturer; break; case Field.Publisher: fieldValue = Publisher; break; case Field.Category: fieldValue = Category; break; case Field.RomOf: fieldValue = RomOf; break; case Field.CloneOf: fieldValue = CloneOf; break; case Field.SampleOf: fieldValue = SampleOf; break; // AttractMode case Field.Players: fieldValue = Players; break; case Field.Rotation: fieldValue = Rotation; break; case Field.Control: fieldValue = Control; break; case Field.SupportStatus: fieldValue = Status; break; case Field.DisplayCount: fieldValue = DisplayCount; break; case Field.DisplayType: fieldValue = DisplayType; break; case Field.Buttons: fieldValue = Buttons; break; // ListXML case Field.SourceFile: fieldValue = SourceFile; break; case Field.Runnable: fieldValue = Runnable?.ToString(); break; case Field.Devices: fieldValue = string.Join(";", Devices ?? new List()); break; case Field.SlotOptions: fieldValue = string.Join(";", SlotOptions ?? new List()); break; case Field.Infos: fieldValue = string.Join(";", (Infos ?? new List>()).Select(i => $"{i.Key}={i.Value}")); break; case Field.MachineType: fieldValue = MachineType.ToString(); break; // Logiqx case Field.Board: fieldValue = Board; break; case Field.RebuildTo: fieldValue = RebuildTo; break; // SoftwareList case Field.Supported: fieldValue = Supported?.ToString(); break; default: return null; } // Make sure we don't return null if (string.IsNullOrEmpty(fieldValue)) fieldValue = string.Empty; return fieldValue; } #endregion #region Constructors /// /// Create a new Machine object /// public Machine() { } /// /// Create a new Machine object with the included information /// /// Name of the machine /// Description of the machine public Machine(string name, string description) { Name = name; Comment = null; Description = description; Year = null; Manufacturer = null; Publisher = null; Category = null; RomOf = null; CloneOf = null; SampleOf = null; Supported = true; SourceFile = null; Runnable = null; Board = null; RebuildTo = null; Devices = null; SlotOptions = null; Infos = null; MachineType = MachineType.NULL; } #endregion #region Cloning methods /// /// Create a clone of the current machine /// /// New machine with the same values as the current one public object Clone() { return new Machine() { // Common Name = this.Name, Comment = this.Comment, Description = this.Description, Year = this.Year, Manufacturer = this.Manufacturer, Publisher = this.Publisher, Category = this.Category, RomOf = this.RomOf, CloneOf = this.CloneOf, SampleOf = this.SampleOf, // AttractMode Players = this.Players, Rotation = this.Rotation, Control = this.Control, Status = this.Status, DisplayCount = this.DisplayCount, DisplayType = this.DisplayType, Buttons = this.Buttons, // ListXML SourceFile = this.SourceFile, Runnable = this.Runnable, Devices = this.Devices, SlotOptions = this.SlotOptions, Infos = this.Infos, MachineType = this.MachineType, // Logiqx Board = this.Board, RebuildTo = this.RebuildTo, // SoftwareList Supported = this.Supported, }; } #endregion #region Filtering /// /// Check to see if a Machine passes the filter /// /// Filter to check against /// True if the item passed the filter, false otherwise public bool PassesFilter(Filter filter) { #region Common // Filter on machine name bool? machineNameFound = filter.MachineName.MatchesPositiveSet(Name); if (filter.IncludeOfInGame) { machineNameFound |= (filter.MachineName.MatchesPositiveSet(CloneOf) == true); machineNameFound |= (filter.MachineName.MatchesPositiveSet(RomOf) == true); } if (machineNameFound == false) return false; machineNameFound = filter.MachineName.MatchesNegativeSet(Name); if (filter.IncludeOfInGame) { machineNameFound |= (filter.MachineName.MatchesNegativeSet(CloneOf) == true); machineNameFound |= (filter.MachineName.MatchesNegativeSet(RomOf) == true); } if (machineNameFound == false) return false; // Filter on comment if (filter.Comment.MatchesPositiveSet(Comment) == false) return false; if (filter.Comment.MatchesNegativeSet(Comment) == true) return false; // Filter on machine description if (filter.MachineDescription.MatchesPositiveSet(Description) == false) return false; if (filter.MachineDescription.MatchesNegativeSet(Description) == true) return false; // Filter on year if (filter.Year.MatchesPositiveSet(Year) == false) return false; if (filter.Year.MatchesNegativeSet(Year) == true) return false; // Filter on manufacturer if (filter.Manufacturer.MatchesPositiveSet(Manufacturer) == false) return false; if (filter.Manufacturer.MatchesNegativeSet(Manufacturer) == true) return false; // Filter on publisher if (filter.Publisher.MatchesPositiveSet(Publisher) == false) return false; if (filter.Publisher.MatchesNegativeSet(Publisher) == true) return false; // Filter on category if (filter.Category.MatchesPositiveSet(Category) == false) return false; if (filter.Category.MatchesNegativeSet(Category) == true) return false; // Filter on romof if (filter.RomOf.MatchesPositiveSet(RomOf) == false) return false; if (filter.RomOf.MatchesNegativeSet(RomOf) == true) return false; // Filter on cloneof if (filter.CloneOf.MatchesPositiveSet(CloneOf) == false) return false; if (filter.CloneOf.MatchesNegativeSet(CloneOf) == true) return false; // Filter on sampleof if (filter.SampleOf.MatchesPositiveSet(SampleOf) == false) return false; if (filter.SampleOf.MatchesNegativeSet(SampleOf) == true) return false; #endregion #region AttractMode // Filter on players if (filter.Players.MatchesPositiveSet(Players) == false) return false; if (filter.Players.MatchesNegativeSet(Players) == true) return false; // Filter on rotation if (filter.Rotation.MatchesPositiveSet(Rotation) == false) return false; if (filter.Rotation.MatchesNegativeSet(Rotation) == true) return false; // Filter on control if (filter.Control.MatchesPositiveSet(Control) == false) return false; if (filter.Control.MatchesNegativeSet(Control) == true) return false; // Filter on support status if (filter.SupportStatus.MatchesPositiveSet(Status) == false) return false; if (filter.SupportStatus.MatchesNegativeSet(Status) == true) return false; // Filter on display count if (filter.DisplayCount.MatchesPositiveSet(DisplayCount) == false) return false; if (filter.DisplayCount.MatchesNegativeSet(DisplayCount) == true) return false; // Filter on display type if (filter.DisplayType.MatchesPositiveSet(DisplayType) == false) return false; if (filter.DisplayType.MatchesNegativeSet(DisplayType) == true) return false; // Filter on buttons if (filter.Buttons.MatchesPositiveSet(Buttons) == false) return false; if (filter.Buttons.MatchesNegativeSet(Buttons) == true) return false; #endregion #region ListXML // Filter on source file if (filter.SourceFile.MatchesPositiveSet(SourceFile) == false) return false; if (filter.SourceFile.MatchesNegativeSet(SourceFile) == true) return false; // Filter on runnable if (filter.Runnable.MatchesNeutral(null, Runnable) == false) return false; // Filter on devices if (Devices != null && Devices.Any()) { bool anyPositiveDevice = false; bool anyNegativeDevice = false; foreach (string device in Devices) { anyPositiveDevice |= filter.Devices.MatchesPositiveSet(device) != false; anyNegativeDevice |= filter.Devices.MatchesNegativeSet(device) == false; } if (!anyPositiveDevice || anyNegativeDevice) return false; } // Filter on slot options if (SlotOptions != null && SlotOptions.Any()) { bool anyPositiveSlotOption = false; bool anyNegativeSlotOption = false; foreach (string slotOption in SlotOptions) { anyPositiveSlotOption |= filter.SlotOptions.MatchesPositiveSet(slotOption) != false; anyNegativeSlotOption |= filter.SlotOptions.MatchesNegativeSet(slotOption) == false; } if (!anyPositiveSlotOption || anyNegativeSlotOption) return false; } // Filter on machine type if (filter.MachineTypes.MatchesPositive(MachineType.NULL, MachineType) == false) return false; if (filter.MachineTypes.MatchesNegative(MachineType.NULL, MachineType) == true) return false; #endregion #region Logiqx // Filter on board if (filter.Board.MatchesPositiveSet(Board) == false) return false; if (filter.Board.MatchesNegativeSet(Board) == true) return false; // Filter on rebuildto if (filter.RebuildTo.MatchesPositiveSet(RebuildTo) == false) return false; if (filter.RebuildTo.MatchesNegativeSet(RebuildTo) == true) return false; #endregion #region SoftwareList // Filter on supported if (filter.Supported.MatchesNeutral(null, Supported) == false) return false; #endregion return true; } /// /// Remove fields from the Machine /// /// List of Fields to remove public void RemoveFields(List fields) { #region Common if (fields.Contains(Field.MachineName)) Name = null; if (fields.Contains(Field.Comment)) Comment = null; if (fields.Contains(Field.Description)) Description = null; if (fields.Contains(Field.Year)) Year = null; if (fields.Contains(Field.Manufacturer)) Manufacturer = null; if (fields.Contains(Field.Publisher)) Publisher = null; if (fields.Contains(Field.Category)) Category = null; if (fields.Contains(Field.RomOf)) RomOf = null; if (fields.Contains(Field.CloneOf)) CloneOf = null; if (fields.Contains(Field.SampleOf)) SampleOf = null; #endregion #region AttractMode if (fields.Contains(Field.Players)) Players = null; if (fields.Contains(Field.Rotation)) Rotation = null; if (fields.Contains(Field.Control)) Control = null; if (fields.Contains(Field.SupportStatus)) Status = null; if (fields.Contains(Field.DisplayCount)) DisplayCount = null; if (fields.Contains(Field.DisplayType)) DisplayType = null; if (fields.Contains(Field.Buttons)) Buttons = null; #endregion #region ListXML if (fields.Contains(Field.SourceFile)) SourceFile = null; if (fields.Contains(Field.Runnable)) Runnable = null; if (fields.Contains(Field.Devices)) Devices = null; if (fields.Contains(Field.SlotOptions)) SlotOptions = null; if (fields.Contains(Field.Infos)) Infos = null; if (fields.Contains(Field.MachineType)) MachineType = MachineType.NULL; #endregion #region Logiqx if (fields.Contains(Field.Board)) Board = null; if (fields.Contains(Field.RebuildTo)) RebuildTo = null; #endregion #region SoftwareList if (fields.Contains(Field.Supported)) Supported = null; #endregion } #endregion #region Sorting and Merging /// /// Replace machine fields from another item /// /// DatItem to pull new information from /// List of Fields representing what should be updated /// True if descriptions should only be replaced if the game name is the same, false otherwise public void ReplaceFields(Machine machine, List fields, bool onlySame) { #region Common if (fields.Contains(Field.MachineName)) Name = machine.Name; if (fields.Contains(Field.Comment)) Comment = machine.Comment; if (fields.Contains(Field.Description)) { if (!onlySame || (onlySame && Name == Description)) Description = machine.Description; } if (fields.Contains(Field.Year)) Year = machine.Year; if (fields.Contains(Field.Manufacturer)) Manufacturer = machine.Manufacturer; if (fields.Contains(Field.Publisher)) Publisher = machine.Publisher; if (fields.Contains(Field.Category)) Category = machine.Category; if (fields.Contains(Field.RomOf)) RomOf = machine.RomOf; if (fields.Contains(Field.CloneOf)) CloneOf = machine.CloneOf; if (fields.Contains(Field.SampleOf)) SampleOf = machine.SampleOf; #endregion #region AttractMode if (fields.Contains(Field.Players)) Players = machine.Players; if (fields.Contains(Field.Rotation)) Rotation = machine.Rotation; if (fields.Contains(Field.Control)) Control = machine.Control; if (fields.Contains(Field.SupportStatus)) Status = machine.Status; if (fields.Contains(Field.DisplayCount)) DisplayCount = machine.DisplayCount; if (fields.Contains(Field.DisplayType)) DisplayType = machine.DisplayType; if (fields.Contains(Field.Buttons)) Buttons = machine.Buttons; #endregion #region ListXML if (fields.Contains(Field.SourceFile)) SourceFile = machine.SourceFile; if (fields.Contains(Field.Runnable)) Runnable = machine.Runnable; if (fields.Contains(Field.Devices)) Devices = machine.Devices; if (fields.Contains(Field.SlotOptions)) SlotOptions = machine.SlotOptions; if (fields.Contains(Field.Infos)) Infos = machine.Infos; if (fields.Contains(Field.MachineType)) MachineType = machine.MachineType; #endregion #region Logiqx if (fields.Contains(Field.Board)) Board = machine.Board; if (fields.Contains(Field.RebuildTo)) RebuildTo = machine.RebuildTo; #endregion #region SoftwareList if (fields.Contains(Field.Supported)) Supported = machine.Supported; #endregion } #endregion } }