use unicode_segmentation::UnicodeSegmentation;
use crate::{
graphics::grapheme_width,
tdom::node::{NodeArena, NodeId, NodeType},
};
use super::cell::CellInfo;
pub(super) const CELL_PADDING: usize = 1;
pub(super) const MIN_COLUMN_WIDTH: usize = 3;
pub(super) fn collect_rows(arena: &NodeArena, table_id: NodeId) -> Vec<NodeId> {
let mut rows = Vec::new();
for &child_id in &arena[table_id].children {
match arena[child_id].node_type {
NodeType::Tr => rows.push(child_id),
NodeType::Thead | NodeType::Tbody | NodeType::Tfoot => {
for &grandchild_id in &arena[child_id].children {
if arena[grandchild_id].node_type == NodeType::Tr {
rows.push(grandchild_id);
}
}
}
_ => {}
}
}
rows
}
pub(super) fn collect_cells(arena: &NodeArena, row_id: NodeId) -> Vec<CellInfo> {
let mut cells = Vec::new();
for &child_id in &arena[row_id].children {
match arena[child_id].node_type {
NodeType::Td => cells.push(CellInfo {
node_id: child_id,
is_header: false,
}),
NodeType::Th => cells.push(CellInfo {
node_id: child_id,
is_header: true,
}),
_ => {}
}
}
cells
}
pub(super) fn cell_text_width(arena: &NodeArena, cell_id: NodeId) -> usize {
let node = &arena[cell_id];
let mut total = 0usize;
for &child_id in &node.children {
if arena[child_id].node_type == NodeType::Text
&& let Some(s) = arena[child_id].data.as_deref()
{
total += s.graphemes(true).map(grapheme_width).sum::<usize>();
}
}
total
}
pub(super) fn compute_column_widths(
arena: &NodeArena,
row_cells: &[Vec<CellInfo>],
available_width: usize,
) -> Vec<usize> {
let column_count = row_cells.iter().map(|row| row.len()).max().unwrap_or(0);
if column_count == 0 {
return Vec::new();
}
let mut widths = vec![0usize; column_count];
for row in row_cells {
for (col_idx, cell) in row.iter().enumerate() {
let w = cell_text_width(arena, cell.node_id) + CELL_PADDING * 2;
if w > widths[col_idx] {
widths[col_idx] = w;
}
}
}
for w in widths.iter_mut() {
if *w < MIN_COLUMN_WIDTH {
*w = MIN_COLUMN_WIDTH;
}
}
let total: usize = widths.iter().sum();
if total > available_width && total > 0 {
let mut scaled: Vec<usize> = widths.iter().map(|w| w * available_width / total).collect();
let scaled_total: usize = scaled.iter().sum();
let mut remainder = available_width.saturating_sub(scaled_total);
let mut indices: Vec<usize> = (0..column_count).collect();
indices.sort_by(|a, b| widths[*b].cmp(&widths[*a]));
let mut idx_pos = 0;
while remainder > 0 {
let i = indices[idx_pos % column_count];
scaled[i] = scaled[i].saturating_add(1);
remainder -= 1;
idx_pos += 1;
}
return scaled;
}
widths
}