using System; using System.Collections.Generic; using System.Linq; using Jackett.Common.Indexers; namespace Jackett.Common.Utils.FilterFuncs { public class FilterFuncExpression : FilterFunc { private static readonly char Separator = ':'; private static readonly char NotOperator = '!'; private static readonly char OrOperator = ','; private static readonly char AndOperator = '+'; private readonly IReadOnlyDictionary>> components; public FilterFuncExpression(params FilterFuncComponent[] components) { if (components == null) throw new ArgumentNullException(nameof(components)); if (components.Length == 0) throw new ArgumentException("Filters cannot be an empty collection.", nameof(components)); if (components.Any(x => x == null)) throw new ArgumentException("Filters cannot contains null values.", nameof(components)); this.components = components.ToDictionary>>(x => x.ID, x => x.ToFunc, StringComparer.InvariantCultureIgnoreCase); } public override Func FromFilter(string source) { if (string.IsNullOrWhiteSpace(source)) return null; if (source.Contains(OrOperator)) return source.Split(OrOperator).Select(FromFilter).Aggregate(Or); if (source.Contains(AndOperator)) return source.Split(AndOperator).Select(FromFilter).Aggregate(And); if (source[0] == NotOperator) return Not(FromFilter(source.Substring(1))); if (source.Contains(Separator)) { var parts = source.Split(new[] { Separator }, 2); if (parts.Length == 2 && components.TryGetValue(parts[0], out var toFunc)) return toFunc(parts[1]); } return null; } private static Func Not(Func u) => i => !u(i); private static Func And(Func l, Func r) => i => l(i) && r(i); private static Func Or(Func l, Func r) => i => l(i) || r(i); } }