using System.Collections.Generic; using System.Linq; using API.DTOs.Reader; namespace API.Helpers; #nullable enable public static class BookChapterItemHelper { /// /// For a given page, finds all toc items that match the page number. /// Returns flattened list to allow for best decision making. /// /// The table of contents collection /// Page number to search for /// Flattened list of all TOC items matching the page public static IList GetTocForPage(ICollection toc, int pageNum) { var flattenedToc = FlattenToc(toc); return flattenedToc.Where(item => item.Page == pageNum).ToList(); } /// /// Flattens the hierarchical table of contents into a single list. /// Preserves all items regardless of nesting level. /// /// The hierarchical table of contents /// Flattened list of all TOC items public static IList FlattenToc(ICollection toc) { var result = new List(); foreach (var item in toc) { result.Add(item); if (item.Children?.Any() == true) { var childItems = FlattenToc(item.Children); result.AddRange(childItems); } } return result; } /// /// Gets the most specific (deepest nested) TOC item for a given page. /// Useful when you want the most granular chapter/section title. /// /// The table of contents collection /// Page number to search for /// The deepest nested TOC item for the page, or null if none found public static BookChapterItem? GetMostSpecificTocForPage(ICollection toc, int pageNum) { var (item, _) = GetTocItemsWithDepth(toc, pageNum, 0) .OrderByDescending(x => x.depth) .FirstOrDefault(); return item; } /// /// Helper method that tracks depth while flattening, useful for determining hierarchy level. /// /// Table of contents collection /// Page number to filter by /// Current nesting depth /// Items with their depth information private static IEnumerable<(BookChapterItem item, int depth)> GetTocItemsWithDepth( ICollection toc, int pageNum, int currentDepth) { foreach (var item in toc) { if (item.Page == pageNum) { yield return (item, currentDepth); } if (item.Children?.Any() != true) continue; foreach (var childResult in GetTocItemsWithDepth(item.Children, pageNum, currentDepth + 1)) { yield return childResult; } } } }