using System.Collections.Generic;
using System.Linq;
using SabreTools.Core.Filter;
using SabreTools.Core.Tools;
using SabreTools.DatItems;
using SabreTools.DatItems.Formats;
using SabreTools.IO.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 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 (datHeader == null || 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: 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);
}
}
}
}
}