use std::time::Duration;
use chrono::{DateTime, Local, Timelike};
use wasm_bindgen::JsCast;
use web_sys::{Element, HtmlTableRowElement};
use crate::{
frontend::{
util::web_idl::{document, get_element_by_id},
view::View,
},
shared::snapshot::log::MessageType,
};
pub fn display(view: &View) {
LogDisplayer::new(view).display();
}
struct LogDisplayer<'a> {
view: &'a View,
log_wrapper_element: Element,
log_body_element: Element,
}
impl LogDisplayer<'_> {
fn new(view: &View) -> LogDisplayer {
let log_wrapper_element = get_element_by_id("log_wrapper");
let log_body_element = get_element_by_id("log").first_element_child().unwrap();
let log_body_element = log_body_element.dyn_into().unwrap();
LogDisplayer {
view,
log_wrapper_element,
log_body_element,
}
}
fn display(&self) {
let previous_num_children = self.log_body_element.child_element_count();
let first_child = self.log_body_element.first_element_child().unwrap();
self.log_body_element.set_inner_html("");
self.log_body_element.append_child(&first_child).unwrap();
for message in &self.view.snapshot().log.messages {
let row_element: HtmlTableRowElement =
document().create_element("tr").unwrap().dyn_into().unwrap();
let time_element = row_element.insert_cell().unwrap();
let duration_element = row_element.insert_cell().unwrap();
duration_element.set_text_content(Some("-"));
let type_element = row_element.insert_cell().unwrap();
let message_element = row_element.insert_cell().unwrap();
let local_time: DateTime<Local> = message.time.into();
time_element.set_text_content(Some(&pretty_time(&local_time)));
match &message.ty {
MessageType::Error(msg) => {
type_element.set_text_content(Some("Error"));
message_element.set_text_content(Some(&format!("Error: {}", msg)));
}
MessageType::Step(step_message) => {
duration_element
.set_text_content(Some(&pretty_duration(&step_message.duration)));
type_element.set_text_content(Some("Step"));
message_element.set_text_content(Some(&format!(
"{} after {} refinements.",
match step_message.status {
crate::shared::snapshot::log::StepStatus::Completed => "Completed",
crate::shared::snapshot::log::StepStatus::Cancelled => "Cancelled",
},
step_message.num_refinements
)));
}
MessageType::Reset => {
type_element.set_text_content(Some("Reset"));
message_element
.set_text_content(Some("The verification framework has been reset."));
}
}
self.log_body_element.append_child(&row_element).unwrap();
}
let num_children = self.log_body_element.child_element_count();
if num_children > previous_num_children {
self.log_wrapper_element
.set_scroll_top(self.log_wrapper_element.scroll_height());
}
}
}
fn pretty_time(time: &DateTime<Local>) -> String {
let time = time.time();
format!(
"{:0>2}:{:0>2}:{:0>2}",
time.hour(),
time.minute(),
time.second()
)
}
fn pretty_duration(duration: &Duration) -> String {
const SECONDS_IN_MINUTE: u64 = 60;
const SECONDS_IN_HOUR: u64 = SECONDS_IN_MINUTE * 60;
let seconds = duration.as_secs();
let hours = seconds / SECONDS_IN_HOUR;
let seconds = seconds % SECONDS_IN_HOUR;
let minutes = seconds / SECONDS_IN_MINUTE;
let seconds = seconds % SECONDS_IN_MINUTE;
let millis = duration.subsec_millis();
if hours == 0 {
if minutes == 0 {
format!("{}.{:0>3} s", seconds, millis)
} else {
format!("{}:{:0>2}.{:0>3} s", minutes, seconds, millis)
}
} else {
format!("{}:{:0>2}:{:0>2}.{:0>3} s", hours, minutes, seconds, millis)
}
}