use machine_check_common::NodeId;
use mck::abstr::{AbstractDisplay, ArrayDisplay};
use wasm_bindgen::JsCast;
use web_sys::{HtmlTableCellElement, HtmlTableElement, HtmlTableRowElement};
use crate::{frontend::util::web_idl::get_element_by_id, shared::snapshot::Node};
use super::View;
pub fn display(view: &View) {
FieldDisplayer::new(view).display();
}
const STANDARD_FIELD_CLASSES: &[&str; 0] = &[];
const STANDARD_VALUE_CLASSES: &[&str; 1] = &["monospace"];
struct FieldDisplayer<'a> {
view: &'a View,
state_fields: HtmlTableElement,
}
impl FieldDisplayer<'_> {
fn new(view: &View) -> FieldDisplayer {
let state_fields = get_element_by_id("state_fields");
let state_fields = state_fields.dyn_into().unwrap();
FieldDisplayer { view, state_fields }
}
fn display(&self) {
self.state_fields.set_inner_html("");
let mut selected = false;
if let Some(node_id) = self.view.selected_node_id() {
let node = self.view.snapshot().state_space.nodes.get(&node_id);
if let Some(node) = node {
selected = true;
self.display_node_fields(node_id, node);
}
}
if !selected {
self.add_auxiliary_row("No node selected");
}
}
fn display_node_fields(&self, node_id: NodeId, node: &Node) {
self.add_field_row("id", &node_id.to_string(), &["bold", "italic"], &[]);
let panic_value = match &node.panic_state {
Some(panic_state) => {
panic_state.expect_struct()[1].to_string()
}
None => String::from("(none)"),
};
self.add_field_row("panic", &panic_value, &["bold", "italic"], &["bold"]);
let Some(panic_state) = &node.panic_state else {
return;
};
let field_types = &self.view.snapshot().state_info.fields;
let field_values = panic_state.expect_struct()[0].expect_struct();
assert_eq!(field_types.len(), field_values.len());
for (field_ident, value) in field_types.keys().zip(field_values) {
match value {
AbstractDisplay::Array(array) => {
self.display_array_field(field_ident.name(), array);
}
AbstractDisplay::Boolean(boolean) => {
self.add_field_row(
field_ident.name(),
&boolean.to_string(),
STANDARD_FIELD_CLASSES,
STANDARD_VALUE_CLASSES,
);
}
AbstractDisplay::Bitvector(_) | AbstractDisplay::Struct(_) => {
self.add_field_row(
field_ident.name(),
&value.to_string(),
STANDARD_FIELD_CLASSES,
STANDARD_VALUE_CLASSES,
);
}
};
}
}
fn display_array_field(&self, field_name: &str, array: &ArrayDisplay) {
for ((start_index, end_index), element) in &array.0 {
let field_part_name = if start_index == end_index {
format!("{}[{}]", field_name, start_index)
} else {
format!("{}[{}..={}]", field_name, start_index, end_index)
};
self.add_field_row(
&field_part_name,
&element.to_string(),
STANDARD_FIELD_CLASSES,
STANDARD_VALUE_CLASSES,
);
}
}
fn add_field_row(
&self,
field: &str,
value: &str,
field_classes: &[&str],
value_classes: &[&str],
) {
let row: HtmlTableRowElement = self.state_fields.insert_row().unwrap().dyn_into().unwrap();
let field_element = row.insert_cell().unwrap();
field_element.set_inner_text(field);
let value_element = row.insert_cell().unwrap();
value_element.set_inner_text(value);
for field_class in field_classes {
field_element.class_list().add_1(field_class).unwrap();
}
for value_class in value_classes {
value_element.class_list().add_1(value_class).unwrap();
}
}
fn add_auxiliary_row(&self, text: &str) {
let row: HtmlTableRowElement = self.state_fields.insert_row().unwrap().dyn_into().unwrap();
row.class_list().add_1("dynamic").unwrap();
let field_cell: HtmlTableCellElement = row.insert_cell().unwrap().dyn_into().unwrap();
field_cell.set_inner_text(text);
field_cell.set_col_span(2);
}
}