use std::borrow::Cow;
use textlane_core::hast::{Element, Node};
use crate::helpers::text::read_text;
use crate::helpers::value::{find_value, is_truthy, parse_int, read_value, write_value};
const STACK_RED_ZONE: usize = 64 * 1024;
const STACK_GROWTH: usize = 1024 * 1024;
pub(crate) type OptionValues = Vec<(String, Option<String>)>;
pub(crate) fn find_selected_options<'a>(
element: &Element<'a>,
settings: &Element<'a>,
) -> OptionValues {
let mut options = vec![];
find_options(&element.children, &mut options);
let size = read_shown_count(settings);
let selected: Vec<&Element<'a>> = options
.iter()
.copied()
.filter(|option| is_truthy(find_value(option, "selected")))
.collect();
let list = if selected.is_empty() {
options
} else {
selected
};
let max = list.len().min(size);
list[..max]
.iter()
.map(|option| {
let content = read_text(option);
let label = if content.is_empty() {
read_value(option, "label").into_owned()
} else {
content.clone()
};
let value = match read_value(option, "value") {
Cow::Borrowed("") => content,
value => value.into_owned(),
};
let label = (label != value && !label.is_empty()).then_some(label);
(value, label)
})
.collect()
}
pub(crate) fn read_shown_count(settings: &Element<'_>) -> usize {
let size =
find_value(settings, "size").and_then(|size| parse_int(&write_value(size)));
match size {
Some(size) if size < 0.0 => 0,
_ if is_truthy(find_value(settings, "multiple")) => 4,
_ => 1,
}
}
fn find_options<'n, 'a>(children: &'n [Node<'a>], options: &mut Vec<&'n Element<'a>>) {
for child in children {
let Node::Element(element) = child else {
continue;
};
stacker::maybe_grow(STACK_RED_ZONE, STACK_GROWTH, || {
find_options(&element.children, options);
});
if element.tag_name == "option" && !is_truthy(find_value(element, "disabled")) {
options.push(element);
}
}
}