use std::default::Default;
use std::collections::BTreeMap;
use std::sync::Mutex;
use std::io;
use std::io::*;
use std::result;
use dvcompute::simulation::event::*;
use dvcompute::simulation::observable::*;
use dvcompute::simulation::observable::observer::*;
use dvcompute_results::simulation::results::*;
use crate::simulation::experiment::*;
use crate::simulation::experiment::rendering::*;
use crate::simulation::utils::html::*;
#[derive(Clone)]
pub struct LastValues {
pub title: String,
pub run_title: String,
pub description: Option<String>,
pub format: Arc<dyn Fn(&str) -> String + Sync + Send>,
pub transform: Arc<dyn Fn() -> ResultTransform + Sync + Send>,
pub series: Arc<dyn Fn() -> ResultTransform + Sync + Send>
}
impl Default for LastValues {
fn default() -> Self {
Self {
title: String::from("Last Values"),
run_title: String::from("$TITLE / Run $RUN_INDEX of $RUN_COUNT"),
description: Some(String::from("It shows the values in the final time point(s).")),
format: Arc::new(|x| { String::from(x) }),
transform: Arc::new(|| { ResultTransform::empty() }),
series: Arc::new(|| { ResultTransform::empty() })
}
}
}
#[derive(Clone)]
struct LastValueState {
view: Arc<Mutex<LastValues>>,
experiment: Arc<Mutex<Experiment>>,
vals: Arc<Mutex<BTreeMap<usize, Vec<(String, String)>>>>
}
impl LastValueState {
pub fn new(view: LastValues, experiment: Experiment) -> Self {
let n = experiment.run_count;
let mut m = BTreeMap::new();
for i in 0 .. n {
m.insert(i, Vec::new());
}
Self {
view: Arc::new(Mutex::new(view)),
experiment: Arc::new(Mutex::new(experiment)),
vals: Arc::new(Mutex::new(m))
}
}
pub fn write_html_single(&self, w: &mut dyn Write, index: usize) -> io::Result<()> {
self.write_html_header(w, index)?;
let view = self.view.lock().unwrap();
let vals = self.vals.lock().unwrap();
for (k, v) in vals[&0].iter() {
write_html_pair(w, k, &(view.format)(v))?;
}
result::Result::Ok(())
}
pub fn write_html_multiple(&self, w: &mut dyn Write, index: usize) -> io::Result<()> {
self.write_html_header(w, index)?;
let view = self.view.lock().unwrap();
let experiment = self.experiment.lock().unwrap();
let vals = self.vals.lock().unwrap();
let n = experiment.run_count;
for run_index in 0 .. n {
let subtitle = {
view.run_title
.replace("$TITLE", &view.title)
.replace("$RUN_COUNT", &format!("{}", n))
.replace("$RUN_INDEX", &format!("{}", 1 + run_index))
};
write_html_header4(w, &subtitle)?;
for (k, v) in vals[&run_index].iter() {
write_html_pair(w, k, &(view.format)(v))?;
}
}
result::Result::Ok(())
}
pub fn write_html_header(&self, w: &mut dyn Write, index: usize) -> io::Result<()> {
let view = self.view.lock().unwrap();
let id = format!("id{}", index);
write_html_header3_by_id(w, &id, &view.title)?;
if let Some(description) = &view.description {
begin_html_paragraph(w)?;
write_html_text(w, &description)?;
end_html_paragraph(w)?;
}
result::Result::Ok(())
}
}
impl<T> ExperimentReporter<WebPageRendering<T>> for LastValueState {
fn initialise(&self) -> simulation::Result<()> {
result::Result::Ok(())
}
fn finalise(&self) -> simulation::Result<()> {
result::Result::Ok(())
}
fn simulate(&self, xs: &ExperimentData) -> CompositeBox<()> {
let loc = {
let experiment = self.experiment.lock().unwrap();
experiment.locale.clone()
};
let exts = {
let view = self.view.lock().unwrap();
let transform = (view.transform)();
let series = (view.series)();
transform.and_then(&series)
.call(&xs.results)
.and_then(|rs| {
rs.get_string_vals()
})
};
match exts {
result::Result::Err(e) => {
cons_event(move |_| {
let e = simulation::error::Error::panic(e);
result::Result::Err(e)
})
.into_composite()
.into_boxed()
},
result::Result::Ok(exts) => {
xs.predefined_observables
.in_stop_time()
.subscribe({
let st = self.clone();
cons_observer(move |_t, p| {
let loc = loc.clone();
let exts = exts.clone();
let st = st.clone();
enqueue_io_event(p.time,
cons_event(move |p| {
let xys = event_sequence({
let loc = loc.clone();
exts.iter().map(move |ext| {
let loc = loc.clone();
let x = ext.id_path
.iter()
.map(move |id| { id.get_title(&loc) })
.collect::<Vec<String>>()
.join(".");
(ext.data)()
.map(move |y| { (x, y) })
})
}).call_event(p)?;
let mut vals = st.vals.lock().unwrap();
vals.insert(p.run.run_index, xys);
result::Result::Ok(())
})
.into_boxed())
.call_event(p)
})
})
.into_composite()
.and_then(|h| {
disposable_composite(h)
})
.into_boxed()
}
}
}
fn context(&self) -> <WebPageRendering<T> as ExperimentRendering>::ExperimentContext {
Box::new(self.clone())
}
}
impl<T> ExperimentGenerator<WebPageRendering<T>> for LastValues {
fn report(&self, _rendering: &WebPageRendering<T>, experiment: &Experiment, _env: &<WebPageRendering<T> as ExperimentRendering>::ExperimentEnvironment) -> Box<dyn ExperimentReporter<WebPageRendering<T>> + Sync + Send> {
Box::new(LastValueState::new(self.clone(), experiment.clone()))
}
}
impl<T> ExperimentView<WebPageRendering<T>> for LastValues {
fn view(&self) -> Box<dyn ExperimentGenerator<WebPageRendering<T>>> {
Box::new(self.clone())
}
}
impl WebPageWriter for LastValueState {
fn write_toc_html(&self, w: &mut dyn Write, index: usize) -> io::Result<()> {
let view = self.view.lock().unwrap();
let id = format!("#id{}", index);
begin_html_list_item(w)?;
write_html_link(w, &id, &view.title)?;
end_html_list_item(w)
}
fn write_html(&self, w: &mut dyn Write, index: usize) -> io::Result<()> {
let run_count = {
let experiment = self.experiment.lock().unwrap();
experiment.run_count
};
if run_count == 1 {
self.write_html_single(w, index)
} else {
self.write_html_multiple(w, index)
}
}
}
fn write_html_pair(w: &mut dyn Write, k: &str, v: &str) -> io::Result<()> {
begin_html_paragraph(w)?;
write_html_text(w, k)?;
write_html_text(w, " = ")?;
write_html_text(w, v)?;
end_html_paragraph(w)
}