use super::error::InterpreterResult;
use super::result::{NodeHandle, SelectionResult};
use super::{Interpreter, html};
use crate::parser::ElementNode;
use regex;
pub fn apply_element_selector(
it: &mut Interpreter,
elem_node: &ElementNode,
) -> InterpreterResult<()> {
let nodes = it.result.nodes()?;
let result = match elem_node {
ElementNode::Class(class_name, is_regex) => select_by_class(nodes, class_name, *is_regex)?,
ElementNode::Id(id, is_regex) => select_by_id(nodes, id, *is_regex)?,
ElementNode::Tag(tag_name, is_regex) => select_by_tag(nodes, tag_name, *is_regex)?,
ElementNode::Attr(attr_name, attr_value, is_regex) => {
let value_ref = attr_value.as_ref().map(|s| s.as_str());
select_by_attr(nodes, attr_name, value_ref, *is_regex)?
},
};
it.result = SelectionResult::with_nodes(result);
Ok(())
}
fn select_by_class(
current_selection: &Vec<NodeHandle>,
class_name: &str,
is_regex: bool,
) -> InterpreterResult<Vec<NodeHandle>> {
let mut result = Vec::new();
for node in current_selection {
let mut matches = html::find_by_class(node, class_name, is_regex)?;
result.append(&mut matches);
}
Ok(result)
}
fn select_by_id(
current_selection: &Vec<NodeHandle>,
id: &str,
is_regex: bool,
) -> InterpreterResult<Vec<NodeHandle>> {
let mut result = Vec::new();
for node in current_selection {
let mut matches = html::find_by_id(node, id, is_regex)?;
result.append(&mut matches);
}
Ok(result)
}
fn select_by_tag(
current_selection: &Vec<NodeHandle>,
tag_name: &str,
is_regex: bool,
) -> InterpreterResult<Vec<NodeHandle>> {
let mut result = Vec::new();
for node in current_selection {
let mut matches = html::find_by_tag(node, tag_name, is_regex)?;
result.append(&mut matches);
}
Ok(result)
}
fn select_by_attr(
current_selection: &Vec<NodeHandle>,
attr_name: &str,
attr_value: Option<&str>,
is_regex: bool,
) -> InterpreterResult<Vec<NodeHandle>> {
let mut result = Vec::new();
if attr_name.is_empty() && attr_value.is_some() {
for node in current_selection {
let attributes = html::get_all_attributes(node)?;
let target_value = attr_value.unwrap();
let mut found = false;
for (_, val) in attributes {
let is_match = if is_regex {
match regex::Regex::new(target_value) {
Ok(re) => re.is_match(&val),
Err(_) => false,
}
} else {
val == target_value
};
if is_match {
found = true;
break;
}
}
if found {
result.push(node.clone());
}
let children = html::get_children(node)?;
for child in children {
let mut child_results = select_by_attr(&vec![child], attr_name, attr_value, is_regex)?;
result.append(&mut child_results);
}
}
} else {
for node in current_selection {
let mut matches = html::find_by_attr(node, attr_name, attr_value, is_regex)?;
result.append(&mut matches);
}
}
Ok(result)
}