mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-21 21:59:47 +00:00
265 lines
9.7 KiB
C#
265 lines
9.7 KiB
C#
using System;
|
|
using SabreTools.Data.Models.Metadata;
|
|
using static SabreTools.Metadata.Filter.Constants;
|
|
|
|
namespace SabreTools.Metadata.Filter
|
|
{
|
|
/// <summary>
|
|
/// Represents a single filter key
|
|
/// </summary>
|
|
public class FilterKey
|
|
{
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// Item name associated with the filter
|
|
/// </summary>
|
|
public readonly string ItemName;
|
|
|
|
/// <summary>
|
|
/// Field name associated with the filter
|
|
/// </summary>
|
|
public readonly string FieldName;
|
|
|
|
#endregion
|
|
|
|
#region Constants
|
|
|
|
/// <summary>
|
|
/// Cached item type names for filter selection
|
|
/// </summary>
|
|
#if NET5_0_OR_GREATER
|
|
private static readonly string[] _datItemTypeNames = Enum.GetNames<ItemType>();
|
|
#else
|
|
private static readonly string[] _datItemTypeNames = Enum.GetNames(typeof(ItemType));
|
|
#endif
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Validating combined key constructor
|
|
/// </summary>
|
|
public FilterKey(string? key)
|
|
{
|
|
if (!ParseFilterId(key, out string itemName, out string fieldName))
|
|
throw new ArgumentException($"{nameof(key)} could not be parsed", nameof(key));
|
|
|
|
ItemName = itemName;
|
|
FieldName = fieldName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validating discrete value constructor
|
|
/// </summary>
|
|
public FilterKey(string itemName, string fieldName)
|
|
{
|
|
if (!ParseFilterId(ref itemName, ref fieldName))
|
|
throw new ArgumentException($"{nameof(itemName)} was not recognized", nameof(itemName));
|
|
|
|
ItemName = itemName;
|
|
FieldName = fieldName;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override string ToString() => $"{ItemName}.{FieldName}";
|
|
|
|
/// <summary>
|
|
/// Parse a filter ID string into the item name and field name, if possible
|
|
/// </summary>
|
|
private static bool ParseFilterId(string? itemFieldString, out string itemName, out string fieldName)
|
|
{
|
|
// Set default values
|
|
itemName = string.Empty; fieldName = string.Empty;
|
|
|
|
// If we don't have a filter ID, we can't do anything
|
|
if (string.IsNullOrEmpty(itemFieldString))
|
|
return false;
|
|
|
|
// If we only have one part, we can't do anything
|
|
string[] splitFilter = itemFieldString!.Split('.');
|
|
if (splitFilter.Length < 2)
|
|
return false;
|
|
|
|
// Set and sanitize the filter ID
|
|
itemName = splitFilter[0];
|
|
fieldName = string.Join(".", splitFilter, 1, splitFilter.Length - 1);
|
|
return ParseFilterId(ref itemName, ref fieldName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a filter ID string into the item name and field name, if possible
|
|
/// </summary>
|
|
private static bool ParseFilterId(ref string itemName, ref string fieldName)
|
|
{
|
|
// If we don't have a filter ID, we can't do anything
|
|
if (string.IsNullOrEmpty(itemName) || string.IsNullOrEmpty(fieldName))
|
|
return false;
|
|
|
|
// Return santized values based on the split ID
|
|
return itemName.ToLowerInvariant() switch
|
|
{
|
|
// Header
|
|
"header" => ParseHeaderFilterId(ref itemName, ref fieldName),
|
|
|
|
// Machine
|
|
"game" => ParseMachineFilterId(ref itemName, ref fieldName),
|
|
"machine" => ParseMachineFilterId(ref itemName, ref fieldName),
|
|
"resource" => ParseMachineFilterId(ref itemName, ref fieldName),
|
|
"set" => ParseMachineFilterId(ref itemName, ref fieldName),
|
|
|
|
// DatItem
|
|
"datitem" => ParseDatItemFilterId(ref itemName, ref fieldName),
|
|
"item" => ParseDatItemFilterId(ref itemName, ref fieldName),
|
|
_ => ParseDatItemFilterId(ref itemName, ref fieldName),
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse and validate header fields
|
|
/// </summary>
|
|
private static bool ParseHeaderFilterId(ref string itemName, ref string fieldName)
|
|
{
|
|
// Get if there's a match to a property
|
|
string localFieldName = fieldName;
|
|
string? propertyMatch = Array.Find(HeaderKeys, c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
|
|
if (propertyMatch is null)
|
|
return false;
|
|
|
|
// Return the sanitized ID
|
|
itemName = "header";
|
|
fieldName = propertyMatch.ToLowerInvariant();
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse and validate machine/game fields
|
|
/// </summary>
|
|
private static bool ParseMachineFilterId(ref string itemName, ref string fieldName)
|
|
{
|
|
// Get if there's a match to a property
|
|
string localFieldName = fieldName;
|
|
string? propertyMatch = Array.Find(MachineKeys, c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
|
|
if (propertyMatch is null)
|
|
return false;
|
|
|
|
// Return the sanitized ID
|
|
itemName = "machine";
|
|
fieldName = propertyMatch.ToLowerInvariant();
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse and validate item fields
|
|
/// </summary>
|
|
private static bool ParseDatItemFilterId(ref string itemName, ref string fieldName)
|
|
{
|
|
// Special case if the item name is reserved
|
|
if (string.Equals(itemName, "datitem", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(itemName, "item", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Handle item type
|
|
if (string.Equals(fieldName, "type", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(fieldName, "_type", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
itemName = "item";
|
|
fieldName = "type";
|
|
return true;
|
|
}
|
|
|
|
// If we get any matches
|
|
string localFieldName = fieldName;
|
|
string? matchedType = Array.Find(_datItemTypeNames, t => DatItemContainsField(t, localFieldName));
|
|
if (matchedType is not null)
|
|
{
|
|
// Check for a matching field
|
|
string? matchedField = GetMatchingField(matchedType, fieldName);
|
|
if (matchedField is null)
|
|
return false;
|
|
|
|
itemName = "item";
|
|
fieldName = matchedField;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check for a matching field
|
|
string? matchedField = GetMatchingField(itemName, fieldName);
|
|
if (matchedField is null)
|
|
return false;
|
|
|
|
itemName = itemName.ToLowerInvariant();
|
|
fieldName = matchedField;
|
|
return true;
|
|
}
|
|
|
|
// Nothing was found
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if an item type contains a field
|
|
/// </summary>
|
|
private static bool DatItemContainsField(string itemName, string fieldName)
|
|
=> GetMatchingField(itemName, fieldName) is not null;
|
|
|
|
/// <summary>
|
|
/// Determine if an item type contains a field
|
|
/// </summary>
|
|
private static string? GetMatchingField(string itemName, string fieldName)
|
|
{
|
|
// Get the set of properties
|
|
string[]? properties = itemName.ToLowerInvariant() switch
|
|
{
|
|
"adjuster" => AdjusterKeys,
|
|
"archive" => ArchiveKeys,
|
|
"biosset" => BiossetKeys,
|
|
"chip" => ChipKeys,
|
|
"configuration" => ConfigurationKeys,
|
|
"conflocation" => ConfLocationKeys,
|
|
"confsetting" => ConfSettingKeys,
|
|
"control" => ControlKeys,
|
|
"dataarea" => DataAreaKeys,
|
|
"device" => DeviceKeys,
|
|
"deviceref" => DeviceRefKeys,
|
|
"diplocation" => DipLocationKeys,
|
|
"dipswitch" => DipSwitchKeys,
|
|
"dipvalue" => DipValueKeys,
|
|
"disk" => DiskKeys,
|
|
"diskarea" => DiskAreaKeys,
|
|
"display" => DisplayKeys,
|
|
"driver" => DriverKeys,
|
|
"feature" or "partfeature" => FeatureKeys,
|
|
"game" or "machine" or "resource" or "set" => MachineKeys,
|
|
"header" => HeaderKeys,
|
|
"info" => InfoKeys,
|
|
"input" => InputKeys,
|
|
"media" => MediaKeys,
|
|
"original" => OriginalKeys,
|
|
"part" => PartKeys,
|
|
"port" => PortKeys,
|
|
"ramoption" => RamOptionKeys,
|
|
"release" => ReleaseKeys,
|
|
"releasedetails" => ReleaseDetailsKeys,
|
|
"rom" => RomKeys,
|
|
"sample" => SampleKeys,
|
|
"serials" => SerialsKeys,
|
|
"sharedfeat" => SharedFeatKeys,
|
|
"slot" => SlotKeys,
|
|
"slotoption" => SlotOptionKeys,
|
|
"softwarelist" => SoftwareListKeys,
|
|
"sound" => SoundKeys,
|
|
"sourcedetails" => SourceDetailsKeys,
|
|
"video" => VideoKeys,
|
|
_ => null,
|
|
};
|
|
if (properties is null)
|
|
return null;
|
|
|
|
// Get if there's a match to a property
|
|
string? propertyMatch = Array.Find(properties, c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase));
|
|
return propertyMatch?.ToLowerInvariant();
|
|
}
|
|
}
|
|
}
|