using HtmlAgilityPack; using System.Text.Json.Serialization; namespace Beam.Dynamic { public record class DataBindings { #region ---------------------- Common Bindings ---------------------- [JsonIgnore] public IDataProvider? Title { get => Get(nameof(Title)); set => Providers[nameof(Title)] = value; } [JsonIgnore] public IDataProvider? Authors { get => Get(nameof(Authors)); set => Providers[nameof(Authors)] = value; } [JsonIgnore] public IDataProvider? Description { get => Get(nameof(Description)); set => Providers[nameof(Description)] = value; } [JsonIgnore] public IDataProvider? Content { get => Get(nameof(Content)); set => Providers[nameof(Content)] = value; } [JsonIgnore] public IDataProvider? Language { get => Get(nameof(Language)); set => Providers[nameof(Language)] = value; } [JsonIgnore] public IDataProvider? Tags { get => Get(nameof(Tags)); set => Providers[nameof(Tags)] = value; } [JsonIgnore] public IDataProvider? Publisher { get => Get(nameof(Publisher)); set => Providers[nameof(Publisher)] = value; } [JsonIgnore] public IDataProvider? PublicationDate { get => Get(nameof(PublicationDate)); set => Providers[nameof(PublicationDate)] = value; } [JsonIgnore] public IDataProvider? ISBN { get => Get(nameof(ISBN)); set => Providers[nameof(ISBN)] = value; } [JsonIgnore] public IDataProvider? PageCount { get => Get(nameof(PageCount)); set => Providers[nameof(PageCount)] = value; } [JsonIgnore] public IDataProvider? CoverImage { get => Get(nameof(CoverImage)); set => Providers[nameof(CoverImage)] = value; } [JsonIgnore] public IDataProvider? Series { get => Get(nameof(Series)); set => Providers[nameof(Series)] = value; } [JsonIgnore] public IDataProvider? Edition { get => Get(nameof(Edition)); set => Providers[nameof(Edition)] = value; } [JsonIgnore] public IDataProvider? Contributors { get => Get(nameof(Contributors)); set => Providers[nameof(Contributors)] = value; } [JsonIgnore] public IDataProvider? Subjects { get => Get(nameof(Subjects)); set => Providers[nameof(Subjects)] = value; } [JsonIgnore] public IDataProvider? Rights { get => Get(nameof(Rights)); set => Providers[nameof(Rights)] = value; } [JsonIgnore] public IDataProvider? TableOfContents { get => Get(nameof(TableOfContents)); set => Providers[nameof(TableOfContents)] = value; } [JsonIgnore] public IDataProvider? PagesDropDown { get => Get(nameof(PagesDropDown)); set => Providers[nameof(PagesDropDown)] = value; } [JsonIgnore] public IDataProvider? NextPageButton { get => Get(nameof(NextPageButton)); set => Providers[nameof(NextPageButton)] = value; } [JsonIgnore] public IDataProvider? PreviousPageButton { get => Get(nameof(PreviousPageButton)); set => Providers[nameof(PreviousPageButton)] = value; } #endregion public Dictionary Providers { get; set; } = []; private IDataProvider? Get(string key) { if (Providers.TryGetValue(key, out var k) && k is IDataProvider ks) return ks; return default; } public virtual ResolvedBindings Resolve(HtmlDocument doc) { // explicit fields already handled below var mappedKeys = new HashSet { nameof(Title), nameof(Authors), nameof(Description), nameof(Content), nameof(Language), nameof(Tags), nameof(Publisher), nameof(PublicationDate), nameof(ISBN), nameof(PageCount), nameof(CoverImage), nameof(Series), nameof(Edition), nameof(Contributors), nameof(Subjects), nameof(Rights), nameof(TableOfContents), nameof(PagesDropDown), nameof(NextPageButton), nameof(PreviousPageButton) }; var additional = new Dictionary(); foreach (var (key, provider) in Providers) { if (!mappedKeys.Contains(key) && provider is not null) { // dynamic call so any IDataProvider works additional[key] = ((dynamic)provider).Get(doc); } } return new ResolvedBindings { Title = Title?.Get(doc), Authors = Authors?.Get(doc) ?? [], Description = Description?.Get(doc), Content = Content?.Get(doc), Language = Language?.Get(doc), Tags = Tags?.Get(doc) ?? [], Publisher = Publisher?.Get(doc), PublicationDate = PublicationDate?.Get(doc), ISBN = ISBN?.Get(doc), PageCount = PageCount?.Get(doc), CoverImage = CoverImage?.Get(doc), Series = Series?.Get(doc) ?? [], Edition = Edition?.Get(doc), Contributors = Contributors?.Get(doc) ?? [], Subjects = Subjects?.Get(doc) ?? [], Rights = Rights?.Get(doc), TableOfContents = TableOfContents?.Get(doc) ?? [], PagesDropDown = PagesDropDown?.Get(doc), NextPageButton = NextPageButton?.Get(doc), PreviousPageButton = PreviousPageButton?.Get(doc), Additional = additional }; } } public record class ResolvedBindings { public string? Title { get; set; } public string[]? Authors { get; set; } public string? Description { get; set; } public string? Content { get; set; } public string[]? Language { get; set; } public string[]? Tags { get; set; } public string? Publisher { get; set; } public DateTimeOffset? PublicationDate { get; set; } public string? ISBN { get; set; } public int? PageCount { get; set; } public SourceLink? CoverImage { get; set; } public string[]? Series { get; set; } public int? Edition { get; set; } public string[]? Contributors { get; set; } public string[]? Subjects { get; set; } public string? Rights { get; set; } public SourceLink[]? TableOfContents { get; set; } public SourceLink[]? PagesDropDown { get; set; } public SourceLink? NextPageButton { get; set; } public SourceLink? PreviousPageButton { get; set; } /// /// Values resolved from any providers whose keys aren’t represented /// by the named properties above. /// public Dictionary Additional { get; set; } = []; } }