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;
}
}
}
}