using System.Collections.Generic; using System.Linq; using SabreTools.Core.Filter; using SabreTools.Core.Tools; using SabreTools.DatFiles; using SabreTools.DatItems; using SabreTools.DatItems.Formats; using SabreTools.IO.Logging; namespace SabreTools.DatTools { /// /// Set fields on DatItems /// public class Setter { #region Fields /// /// Mappings to set DatHeader fields /// public Dictionary HeaderFieldMappings { get; } = []; /// /// Mappings to set Machine fields /// public Dictionary MachineFieldMappings { get; } = []; /// /// Mappings to set DatItem fields /// public Dictionary ItemFieldMappings { get; } = []; #endregion #region Logging /// /// Logging object /// private readonly Logger _logger = new(); #endregion #region Population /// /// Populate the setters using a field name and a value /// /// Field name /// Field value public void PopulateSetters(FilterKey field, string value) => PopulateSettersFromList([field], [value]); /// /// Populate the setters using a set of field names /// /// List of field names /// List of field values public void PopulateSettersFromList(List fields, List values) { // If the list is null or empty, just return if (values == null || values.Count == 0) return; var watch = new InternalStopwatch("Populating setters from list"); // Now we loop through and get values for everything for (int i = 0; i < fields.Count; i++) { FilterKey field = fields[i]; string value = values[i]; if (!SetSetter(field, value)) _logger.Warning($"The value {value} did not match any known field names. Please check the wiki for more details on supported field names."); } watch.Stop(); } /// /// Populate the setters using a set of field names /// /// Dictionary of mappings public void PopulateSettersFromDictionary(Dictionary? mappings) { // If the dictionary is null or empty, just return if (mappings == null || mappings.Count == 0) return; var watch = new InternalStopwatch("Populating setters from dictionary"); // Now we loop through and get values for everything foreach (var mapping in mappings) { FilterKey field = mapping.Key; string value = mapping.Value; if (!SetSetter(field, value)) _logger.Warning($"The value {value} did not match any known field names. Please check the wiki for more details on supported field names."); } watch.Stop(); } /// /// Set remover from a value /// /// Key for the remover to be set private bool SetSetter(FilterKey key, string value) { switch (key.ItemName) { case Models.Metadata.MetadataFile.HeaderKey: HeaderFieldMappings[key.FieldName] = value; return true; case Models.Metadata.MetadataFile.MachineKey: MachineFieldMappings[key.FieldName] = value; return true; default: ItemFieldMappings[key] = value; return true; } } #endregion /// /// Set fields with given values /// /// DatHeader to set fields on public void SetFields(DatHeader datHeader) { // If we have an invalid input, return if (HeaderFieldMappings.Count == 0) return; foreach (var kvp in HeaderFieldMappings) { datHeader.SetField(kvp.Key, kvp.Value); } } /// /// Set fields with given values /// /// Machine to set fields on public void SetFields(Machine? machine) { // If we have an invalid input, return if (machine == null || MachineFieldMappings.Count == 0) return; foreach (var kvp in MachineFieldMappings) { machine.SetField(kvp.Key, kvp.Value); } } /// /// Set fields with given values /// /// DatItem to set fields on public void SetFields(DatItem datItem) { // If we have an invalid input, return if (datItem == null) return; #region Common // Handle Machine fields if (MachineFieldMappings.Count > 0 && datItem.GetFieldValue(DatItem.MachineKey) != null) SetFields(datItem.GetFieldValue(DatItem.MachineKey)!); // If there are no field names, return if (ItemFieldMappings == null || ItemFieldMappings.Count == 0) return; // If there are no field names for this type or generic, return string? itemType = datItem.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue().AsStringValue(); if (itemType == null || (!ItemFieldMappings.Keys.Any(kvp => kvp.ItemName == itemType) && !ItemFieldMappings.Keys.Any(kvp => kvp.ItemName == "item"))) return; // Get the combined list of fields to remove var fieldMappings = new Dictionary(); foreach (var mapping in ItemFieldMappings.Where(kvp => kvp.Key.ItemName == "item").ToDictionary(kvp => kvp.Key.FieldName, kvp => kvp.Value)) { fieldMappings[mapping.Key] = mapping.Value; } foreach (var mapping in ItemFieldMappings.Where(kvp => kvp.Key.ItemName == itemType).ToDictionary(kvp => kvp.Key.FieldName, kvp => kvp.Value)) { fieldMappings[mapping.Key] = mapping.Value; } // If the field specifically contains Name, set it separately if (fieldMappings.Keys.Contains(Models.Metadata.Rom.NameKey)) { datItem.SetName(fieldMappings[Models.Metadata.Rom.NameKey]); fieldMappings.Remove(Models.Metadata.Rom.NameKey); } #endregion #region Item-Specific // Handle unnested sets first foreach (var kvp in fieldMappings) { datItem.SetField(kvp.Key, kvp.Value); } // Handle nested sets switch (datItem) { case Adjuster adjuster: SetNestedFields(adjuster); break; case Configuration condition: SetNestedFields(condition); break; case ConfSetting confSetting: SetNestedFields(confSetting); break; case Device device: SetNestedFields(device); break; case DipSwitch dipSwitch: SetNestedFields(dipSwitch); break; case DipValue dipValue: SetNestedFields(dipValue); break; case Disk disk: SetNestedFields(disk); break; case Input input: SetNestedFields(input); break; case Part part: SetNestedFields(part); break; case Port port: SetNestedFields(port); break; case Rom rom: SetNestedFields(rom); break; case Slot slot: SetNestedFields(slot); break; } #endregion } /// /// Set fields with given values /// /// Adjuster to remove replace fields in private void SetNestedFields(Adjuster adjuster) { // Field.DatItem_Conditions does not apply here if (adjuster.ConditionsSpecified) { foreach (Condition subCondition in adjuster.GetFieldValue(Models.Metadata.Adjuster.ConditionKey)!) { SetFields(subCondition); } } } /// /// Set fields with given values /// /// Configuration to remove replace fields in private void SetNestedFields(Configuration configuration) { if (configuration.ConditionsSpecified) { foreach (Condition subCondition in configuration.GetFieldValue(Models.Metadata.Configuration.ConditionKey)!) { SetFields(subCondition); } } if (configuration.LocationsSpecified) { foreach (ConfLocation subLocation in configuration.GetFieldValue(Models.Metadata.Configuration.ConfLocationKey)!) { SetFields(subLocation); } } if (configuration.SettingsSpecified) { foreach (ConfSetting subSetting in configuration.GetFieldValue(Models.Metadata.Configuration.ConfSettingKey)!) { SetFields(subSetting as DatItem); } } } /// /// Set fields with given values /// /// ConfSetting to remove replace fields in private void SetNestedFields(ConfSetting confSetting) { if (confSetting.ConditionsSpecified) { foreach (Condition subCondition in confSetting.GetFieldValue(Models.Metadata.ConfSetting.ConditionKey)!) { SetFields(subCondition); } } } /// /// Set fields with given values /// /// Device to remove replace fields in private void SetNestedFields(Device device) { if (device.ExtensionsSpecified) { foreach (Extension subExtension in device.GetFieldValue(Models.Metadata.Device.ExtensionKey)!) { SetFields(subExtension); } } if (device.InstancesSpecified) { foreach (Instance subInstance in device.GetFieldValue(Models.Metadata.Device.InstanceKey)!) { SetFields(subInstance); } } } /// /// Set fields with given values /// /// DipSwitch to remove replace fields in private void SetNestedFields(DipSwitch dipSwitch) { if (dipSwitch.ConditionsSpecified) { foreach (Condition subCondition in dipSwitch.GetFieldValue(Models.Metadata.DipSwitch.ConditionKey)!) { SetFields(subCondition); } } if (dipSwitch.LocationsSpecified) { foreach (DipLocation subLocation in dipSwitch.GetFieldValue(Models.Metadata.DipSwitch.DipLocationKey)!) { SetFields(subLocation); } } if (dipSwitch.ValuesSpecified) { foreach (DipValue subValue in dipSwitch.GetFieldValue(Models.Metadata.DipSwitch.DipValueKey)!) { SetFields(subValue as DatItem); } } if (!dipSwitch.PartSpecified) dipSwitch.SetFieldValue(DipSwitch.PartKey, new Part()); SetFields((dipSwitch.GetFieldValue(DipSwitch.PartKey) as DatItem)!); } /// /// Set fields with given values /// /// DipValue to remove replace fields in private void SetNestedFields(DipValue dipValue) { if (dipValue.ConditionsSpecified) { foreach (Condition subCondition in dipValue.GetFieldValue(Models.Metadata.DipValue.ConditionKey)!) { SetFields(subCondition); } } } /// /// Set fields with given values /// /// Disk to remove replace fields in private void SetNestedFields(Disk disk) { if (!disk.DiskAreaSpecified) disk.SetFieldValue(Disk.DiskAreaKey, new DiskArea()); SetFields(disk.GetFieldValue(Disk.DiskAreaKey)! as DatItem); if (!disk.PartSpecified) disk.SetFieldValue(Disk.PartKey, new Part()); SetFields(disk.GetFieldValue(Disk.PartKey)! as DatItem); } /// /// Set fields with given values /// /// Input to remove replace fields in private void SetNestedFields(Input input) { if (input.ControlsSpecified) { foreach (Control subControl in input.GetFieldValue(Models.Metadata.Input.ControlKey)!) { SetFields(subControl); } } } /// s /// Set fields with given values /// /// Part to remove replace fields in private void SetNestedFields(Part part) { if (part.FeaturesSpecified) { foreach (PartFeature subPartFeature in part.GetFieldValue(Models.Metadata.Part.FeatureKey)!) { SetFields(subPartFeature); } } } /// /// Set fields with given values /// /// Port to remove replace fields in private void SetNestedFields(Port port) { if (port.AnalogsSpecified) { foreach (Analog subAnalog in port.GetFieldValue(Models.Metadata.Port.AnalogKey)!) { SetFields(subAnalog); } } } /// /// Set fields with given values /// /// Rom to remove replace fields in private void SetNestedFields(Rom rom) { if (!rom.DataAreaSpecified) rom.SetFieldValue(Rom.DataAreaKey, new DataArea()); SetFields(rom.GetFieldValue(Rom.DataAreaKey)! as DatItem); if (!rom.PartSpecified) rom.SetFieldValue(Rom.PartKey, new Part()); SetFields(rom.GetFieldValue(Rom.PartKey)! as DatItem); } /// /// Set fields with given values /// /// Slot to remove replace fields in private void SetNestedFields(Slot slot) { if (slot.SlotOptionsSpecified) { foreach (SlotOption subSlotOption in slot.GetFieldValue(Models.Metadata.Slot.SlotOptionKey)!) { SetFields(subSlotOption); } } } } }