ComplexSelector
Represents a complex selector.
One or more compound selectors separated by combinators.
using AngleSharp.Css;
using AngleSharp.Parser.Css;
using System;
using System.Collections.Generic;
using System.Text;
namespace AngleSharp.Dom.Css
{
internal sealed class ComplexSelector : ISelector
{
private struct CombinatorSelector
{
public char Delimiter;
public Func<IElement, IEnumerable<IElement>> Transform;
public ISelector Selector;
}
private readonly List<CombinatorSelector> selectors;
public Priority Specifity {
get {
Priority priority = default(Priority);
int count = selectors.Count;
for (int i = 0; i < count; i++) {
priority += selectors[i].Selector.Specifity;
}
return priority;
}
}
public string Text {
get {
StringBuilder stringBuilder = Pool.NewStringBuilder();
if (selectors.Count > 0) {
int num = selectors.Count - 1;
for (int i = 0; i < num; i++) {
stringBuilder.Append(selectors[i].Selector.Text).Append(selectors[i].Delimiter);
}
stringBuilder.Append(selectors[num].Selector.Text);
}
return stringBuilder.ToPool();
}
}
public int Length => selectors.Count;
public bool IsReady { get; set; }
public ComplexSelector()
{
selectors = new List<CombinatorSelector>();
}
public bool Match(IElement element)
{
int num = selectors.Count - 1;
if (selectors[num].Selector.Match(element)) {
if (num <= 0)
return true;
return MatchCascade(num - 1, element);
}
return false;
}
public ComplexSelector ConcludeSelector(ISelector selector)
{
if (!IsReady) {
selectors.Add(new CombinatorSelector {
Selector = selector,
Transform = null,
Delimiter = ' '
});
IsReady = true;
}
return this;
}
public ComplexSelector AppendSelector(ISelector selector, CssCombinator combinator)
{
if (IsReady)
return this;
selectors.Add(new CombinatorSelector {
Selector = combinator.Change(selector),
Transform = combinator.Transform,
Delimiter = combinator.Delimiter
});
return this;
}
public ComplexSelector ClearSelectors()
{
IsReady = false;
selectors.Clear();
return this;
}
private bool MatchCascade(int pos, IElement element)
{
IEnumerable<IElement> enumerable = selectors[pos].Transform(element);
foreach (IElement item in enumerable) {
if (selectors[pos].Selector.Match(item) && (pos == 0 || MatchCascade(pos - 1, item)))
return true;
}
return false;
}
}
}