using System;
using System.Collections.Generic;
using SabreTools.Data.Models.Metadata;
namespace SabreTools.Metadata.Filter
{
///
/// Represents a set of filters that can be run against an object
///
public class FilterRunner
{
///
/// Set of filters to be run against an object
///
public readonly Dictionary Filters = [];
///
/// Cached item type names for filter selection
///
#if NET5_0_OR_GREATER
private static readonly string[] _datItemTypeNames = Enum.GetNames();
#else
private static readonly string[] _datItemTypeNames = Enum.GetNames(typeof(ItemType));
#endif
public FilterRunner(FilterObject[] filters)
{
Array.ForEach(filters, AddFilter);
}
public FilterRunner(string[] filterStrings)
{
Array.ForEach(filterStrings, AddFilter);
}
///
/// Run filtering on an item
///
public bool Run(object obj)
{
string? itemName = obj switch
{
Header => "header",
Machine => "machine",
DatItem datItem => datItem.ItemType.ToString(),
_ => null,
};
// Null is invalid
if (itemName is null)
return false;
// Loop through and run each filter in order
foreach (var filterKey in Filters.Keys)
{
// Skip filters not applicable to the item
if (filterKey.StartsWith("item.") && Array.IndexOf(_datItemTypeNames, itemName) == -1)
continue;
else if (!filterKey.StartsWith("item.") && !filterKey.StartsWith(itemName, StringComparison.OrdinalIgnoreCase))
continue;
// If we don't get a match, it's a failure
bool matchOne = Filters[filterKey].Matches(obj);
if (!matchOne)
return false;
}
return true;
}
///
/// Add a single filter to the runner in a group by key
///
private void AddFilter(FilterObject filter)
{
// Get the key as a string
string key = filter.Key.ToString();
// Set the expected group type
GroupType groupType = GroupType.OR;
// Special case for size
if (filter.Key.ItemName == "item" && filter.Key.FieldName == "size")
groupType = GroupType.AND;
else if (filter.Key.ItemName == "dataarea" && filter.Key.FieldName == "size")
groupType = GroupType.AND;
else if (filter.Key.ItemName == "rom" && filter.Key.FieldName == "size")
groupType = GroupType.AND;
// Ensure the key exists
if (!Filters.ContainsKey(key))
Filters[key] = new FilterGroup(groupType);
// Add the filter to the set
Filters[key].AddFilter(filter);
}
///
/// Add a single filter to the runner in a group by key
///
private void AddFilter(string filterString)
{
try
{
var filter = new FilterObject(filterString);
AddFilter(filter);
}
catch { }
}
}
}