2019-01-11 13:43:59 -08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
|
2020-07-30 22:51:33 -07:00
|
|
|
|
namespace SabreTools.Library.Filtering
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Represents a single filter within the overall filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">Generic type representing the filtered object</typeparam>
|
|
|
|
|
|
public class FilterItem<T>
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Single positive value for this filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public T Positive { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// List of positive values for this filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<T> PositiveSet { get; set; } = new List<T>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Single negative value for this filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public T Negative { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// List of negative values for this filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<T> NegativeSet { get; set; } = new List<T>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Single neutral value for this filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public T Neutral { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// List of neutral values for this filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<T> NeutralSet { get; set; } = new List<T>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if a value matches the positive filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="def">Default value to check filter value</param>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in the positive filter, null on default value, false otherwise</returns>
|
|
|
|
|
|
public bool? MatchesPositive(T def, T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
return Matches(this.Positive, def, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if a value matches the negative filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="def">Default value to check filter value</param>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in the negative filter, null on default value, false otherwise</returns>
|
|
|
|
|
|
public bool? MatchesNegative(T def, T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
return Matches(this.Negative, def, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if a value matches the neutral filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="def">Default value to check filter value</param>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in the neutral filter, null on default value, false otherwise</returns>
|
|
|
|
|
|
public bool? MatchesNeutral(T def, T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
return Matches(this.Neutral, def, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if the given value matches any of the positive filters
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in a positive filter, null on an empty set, false otherwise</returns>
|
|
|
|
|
|
public bool? MatchesPositiveSet(T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
return MatchesSet(this.PositiveSet, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if the given value matches any of the negative filters
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in a negative filter, null on an empty set, false otherwise</returns>
|
|
|
|
|
|
public bool? MatchesNegativeSet(T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
return MatchesSet(this.NegativeSet, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if the given value matches any of the neutral filters
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in a neutral filter, null on an empty set, false otherwise</returns>
|
|
|
|
|
|
public bool? MatchesNeutralSet(T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
return MatchesSet(this.NeutralSet, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if a value matches the supplied filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="single">Value to check against</param>
|
|
|
|
|
|
/// <param name="def">Default value to check filter value</param>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in the supplied filter, null on default value, false otherwise</returns>
|
|
|
|
|
|
private bool? Matches(T single, T def, T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
// If the filter is default, we ignore
|
|
|
|
|
|
if (single.Equals(def))
|
2019-02-08 15:05:15 -08:00
|
|
|
|
return null;
|
2019-01-11 13:43:59 -08:00
|
|
|
|
|
|
|
|
|
|
// If we have a flag
|
|
|
|
|
|
if (typeof(T).IsEnum && (single as Enum).HasFlag(value as Enum))
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
return single.Equals(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if a value matches the supplied filter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="set">Set to check against</param>
|
|
|
|
|
|
/// <param name="value">Value to check</param>
|
2019-02-08 15:05:15 -08:00
|
|
|
|
/// <returns>True if the value was found in the supplied filter, null on an empty set, false otherwise</returns>
|
|
|
|
|
|
private bool? MatchesSet(List<T> set, T value)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
2019-02-08 15:05:15 -08:00
|
|
|
|
if (set.Count == 0)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
if (this.FindValueInList(set, value))
|
|
|
|
|
|
return true;
|
2019-01-11 13:43:59 -08:00
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Generic code to check if a specific value is in the list given
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="haystack">List to search for the value in</param>
|
|
|
|
|
|
/// <param name="needle">Value to search the list for</param>
|
|
|
|
|
|
/// <returns>True if the value could be found, false otherwise</returns>
|
|
|
|
|
|
private bool FindValueInList(List<T> haystack, T needle)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
foreach (T straw in haystack)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (straw is string)
|
|
|
|
|
|
{
|
|
|
|
|
|
string needleString = needle as string;
|
|
|
|
|
|
string strawString = straw as string;
|
2020-06-10 22:37:19 -07:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(strawString) && needleString != null)
|
2019-01-11 13:43:59 -08:00
|
|
|
|
{
|
|
|
|
|
|
string regexStraw = strawString;
|
|
|
|
|
|
|
2019-05-23 10:43:02 -07:00
|
|
|
|
// If the straw has no special characters at all (excluding whitespace), treat it as an exact match
|
|
|
|
|
|
if (regexStraw == Regex.Escape(regexStraw).Replace("\\ ", " "))
|
2020-06-10 22:37:19 -07:00
|
|
|
|
regexStraw = $"^{regexStraw}$";
|
2019-01-11 13:43:59 -08:00
|
|
|
|
|
|
|
|
|
|
// Check if a match is found with the regex
|
|
|
|
|
|
found |= Regex.IsMatch(needleString, regexStraw, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
found |= (needle.Equals(straw));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|