ImportLinkRelation
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using AngleSharp.Io;
using AngleSharp.Io.Processors;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace AngleSharp.Html.LinkRels
{
internal class ImportLinkRelation : BaseLinkRelation
{
private sealed class ImportList
{
private readonly List<ImportEntry> _list;
public ImportList()
{
_list = new List<ImportEntry>();
}
public bool Contains(Url location)
{
for (int i = 0; i < _list.Count; i++) {
Url url = _list[i].Relation.Url;
if (url != null && url.Equals(location))
return true;
}
return false;
}
public void Add(ImportEntry item)
{
_list.Add(item);
}
public void Remove(ImportEntry item)
{
_list.Remove(item);
}
}
private struct ImportEntry
{
public ImportLinkRelation Relation;
public bool IsCycle;
}
private static readonly ConditionalWeakTable<IDocument, ImportList> ImportLists = new ConditionalWeakTable<IDocument, ImportList>();
private bool _async;
public IDocument Import => (base.Processor as DocumentRequestProcessor)?.ChildDocument;
public bool IsAsync => _async;
public ImportLinkRelation(IHtmlLinkElement link)
: base(link, new DocumentRequestProcessor(link?.Owner.Context))
{
}
public override Task LoadAsync()
{
IHtmlLinkElement link = base.Link;
IDocument owner = link.Owner;
ImportList orCreateValue = ImportLists.GetOrCreateValue(owner);
Url url = base.Url;
IRequestProcessor processor = base.Processor;
ImportEntry importEntry = new ImportEntry {
Relation = this,
IsCycle = (url != null && CheckCycle(owner, url))
};
orCreateValue.Add(importEntry);
if (url != null && !importEntry.IsCycle) {
ResourceRequest request = link.CreateRequestFor(url);
_async = link.HasAttribute(AttributeNames.Async);
return processor?.ProcessAsync(request);
}
return Task.CompletedTask;
}
private static bool CheckCycle(IDocument document, Url location)
{
IDocument importAncestor = document.ImportAncestor;
ImportList value;
while (importAncestor != null && ImportLists.TryGetValue(importAncestor, out value)) {
if (value.Contains(location))
return true;
importAncestor = importAncestor.ImportAncestor;
}
return false;
}
}
}