using System; using System.Xml.Serialization; using Newtonsoft.Json; using SabreTools.Hashing; using SabreTools.Metadata.DatItems.Formats; using SabreTools.Metadata.Filter; namespace SabreTools.Metadata.DatItems { /// /// Base class for all items included in a set /// [JsonObject("datitem"), XmlRoot("datitem")] [XmlInclude(typeof(Adjuster))] [XmlInclude(typeof(Archive))] [XmlInclude(typeof(BiosSet))] [XmlInclude(typeof(Blank))] [XmlInclude(typeof(Chip))] [XmlInclude(typeof(Configuration))] [XmlInclude(typeof(ConfLocation))] [XmlInclude(typeof(ConfSetting))] [XmlInclude(typeof(Control))] [XmlInclude(typeof(Device))] [XmlInclude(typeof(DeviceRef))] [XmlInclude(typeof(DipLocation))] [XmlInclude(typeof(DipSwitch))] [XmlInclude(typeof(DipValue))] [XmlInclude(typeof(Disk))] [XmlInclude(typeof(Display))] [XmlInclude(typeof(Driver))] [XmlInclude(typeof(Feature))] [XmlInclude(typeof(Info))] [XmlInclude(typeof(Input))] [XmlInclude(typeof(Media))] [XmlInclude(typeof(PartFeature))] [XmlInclude(typeof(Port))] [XmlInclude(typeof(RamOption))] [XmlInclude(typeof(Release))] [XmlInclude(typeof(ReleaseDetails))] [XmlInclude(typeof(Rom))] [XmlInclude(typeof(Sample))] [XmlInclude(typeof(SharedFeat))] [XmlInclude(typeof(Slot))] [XmlInclude(typeof(SlotOption))] [XmlInclude(typeof(SoftwareList))] [XmlInclude(typeof(Sound))] [XmlInclude(typeof(SourceDetails))] public abstract class DatItem : ICloneable, IEquatable { #region Properties /// /// Duplicate type when compared to another item /// public DupeType DupeType { get; set; } = 0x00; /// /// Item type for the object /// public abstract Data.Models.Metadata.ItemType ItemType { get; } /// /// Get the machine for a DatItem /// public Machine? Machine { get; set; } /// /// Flag if item should be removed /// public bool RemoveFlag { get; set; } = false; /// /// Source information /// public Source? Source { get; set; } #endregion #region Accessors /// /// Gets the name to use for a DatItem /// /// Name if available, null otherwise public abstract string? GetName(); /// /// Sets the name to use for a DatItem /// /// Name to set for the item public abstract void SetName(string? name); #endregion #region Cloning Methods /// /// Clone the DatItem /// /// Clone of the DatItem public abstract object Clone(); /// /// Copy all machine information over in one shot /// /// Existing item to copy information from public void CopyMachineInformation(DatItem item) { // If there is no machine if (item.Machine is null) return; CopyMachineInformation(item.Machine); } /// /// Copy all machine information over in one shot /// /// Existing machine to copy information from public void CopyMachineInformation(Machine? machine) { if (machine is null) return; if (machine.Clone() is Machine cloned) Machine = cloned; } #endregion #region Comparision Methods /// /// Determine if an item is a duplicate using partial matching logic /// /// DatItem to use as a baseline /// True if the items are duplicates, false otherwise public abstract bool Equals(DatItem? other); #endregion #region Manipulation /// /// Runs a filter and determines if it passes or not /// /// Filter runner to use for checking /// True if the item and its machine passes the filter, false otherwise public abstract bool PassesFilter(FilterRunner filterRunner); /// /// Runs a filter and determines if it passes or not /// /// Filter runner to use for checking /// True if the item passes the filter, false otherwise public abstract bool PassesFilterDB(FilterRunner filterRunner); #endregion #region Sorting and Merging /// /// Get the dictionary key that should be used for a given item and bucketing type /// /// ItemKey value representing what key to get /// Machine associated with the item for renaming /// Source associated with the item for renaming /// True if the key should be lowercased (default), false otherwise /// True if games should only be compared on game and file name, false if system and source are counted /// String representing the key to be used for the DatItem public virtual string GetKey(ItemKey bucketedBy, Machine? machine, Source? source, bool lower = true, bool norename = true) { // Set the output key as the default blank string string key = string.Empty; string sourceKeyPadded = source?.Index.ToString().PadLeft(10, '0') + '-'; string machineName = machine?.Name ?? "Default"; // Now determine what the key should be based on the bucketedBy value switch (bucketedBy) { case ItemKey.CRC16: key = HashType.CRC16.ZeroString; break; case ItemKey.CRC32: key = HashType.CRC32.ZeroString; break; case ItemKey.CRC64: key = HashType.CRC64.ZeroString; break; case ItemKey.Machine: key = (norename ? string.Empty : sourceKeyPadded) + machineName; break; case ItemKey.MD2: key = HashType.MD2.ZeroString; break; case ItemKey.MD4: key = HashType.MD4.ZeroString; break; case ItemKey.MD5: key = HashType.MD5.ZeroString; break; case ItemKey.RIPEMD128: key = HashType.RIPEMD128.ZeroString; break; case ItemKey.RIPEMD160: key = HashType.RIPEMD160.ZeroString; break; case ItemKey.SHA1: key = HashType.SHA1.ZeroString; break; case ItemKey.SHA256: key = HashType.SHA256.ZeroString; break; case ItemKey.SHA384: key = HashType.SHA384.ZeroString; break; case ItemKey.SHA512: key = HashType.SHA512.ZeroString; break; case ItemKey.SpamSum: key = HashType.SpamSum.ZeroString; break; case ItemKey.NULL: default: // This should never happen break; } // Double and triple check the key for corner cases key ??= string.Empty; if (lower) key = key.ToLowerInvariant(); return key; } #endregion } }