using System.Collections.Generic; using System.Linq; using SabreTools.Core; using SabreTools.Core.Tools; using SabreTools.DatItems; using SabreTools.DatItems.Formats; using SabreTools.Filter; using SabreTools.Logging; namespace SabreTools.DatFiles { /// /// Set fields on DatItems /// /// TODO: Figure out how to get this into the Filtering namespace 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<(string, string), string> 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(string 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++) { string 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<(string, string), string>? 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) { string field = $"{mapping.Key.Item1}.{mapping.Key.Item2}"; 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(string field, string value) { // If the key is null or empty, return false if (string.IsNullOrEmpty(field)) return false; // Get the parser pair out of it, if possible (string? type, string? key) = FilterParser.ParseFilterId(field); if (type == null || key == null) return false; switch (type) { case Models.Metadata.MetadataFile.HeaderKey: HeaderFieldMappings[key] = value; return true; case Models.Metadata.MetadataFile.MachineKey: MachineFieldMappings[key] = value; return true; default: ItemFieldMappings[(type, 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 (datHeader == null || !HeaderFieldMappings.Any()) 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.Any()) 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.Any() && datItem.GetFieldValue(DatItem.MachineKey) != null) SetFields(datItem.GetFieldValue(DatItem.MachineKey)!); // If there are no field names, return if (ItemFieldMappings == null || !ItemFieldMappings.Any()) return; // If there are no field names for this type or generic, return string? itemType = datItem.GetFieldValue(Models.Metadata.DatItem.TypeKey).AsStringValue(); if (itemType == null || (!ItemFieldMappings.Keys.Any(kvp => kvp.Item1 == itemType) && !ItemFieldMappings.Keys.Any(kvp => kvp.Item1 == "item"))) return; // Get the combined list of fields to remove var fieldMappings = new Dictionary(); foreach (var mapping in ItemFieldMappings.Where(kvp => kvp.Key.Item1 == "item").ToDictionary(kvp => kvp.Key.Item2, kvp => kvp.Value)) { fieldMappings[mapping.Key] = mapping.Value; } foreach (var mapping in ItemFieldMappings.Where(kvp => kvp.Key.Item1 == itemType).ToDictionary(kvp => kvp.Key.Item2, 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]); #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: SetFields(adjuster); break; case Configuration condition: SetFields(condition); break; case ConfSetting confSetting: SetFields(confSetting); break; case Device device: SetFields(device); break; case DipSwitch dipSwitch: SetFields(dipSwitch); break; case DipValue dipValue: SetFields(dipValue); break; case Disk disk: SetFields(disk); break; case Input input: SetFields(input); break; case Part part: SetFields(part); break; case Port port: SetFields(port); break; case Rom rom: SetFields(rom); break; case Slot slot: SetFields(slot); break; } #endregion } /// /// Set fields with given values /// /// Adjuster to remove replace fields in private void SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(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 SetFields(Slot slot) { if (slot.SlotOptionsSpecified) { foreach (SlotOption subSlotOption in slot.GetFieldValue(Models.Metadata.Slot.SlotOptionKey)!) { SetFields(subSlotOption); } } } } }