use std::cmp::Ordering;
use std::fs::File;
use std::io::{BufWriter, Write};
use e173::controller::{DmxDriver, ParamRange, ParameterCombo, ParameterConstraint};
use e173::schema::E173Document;
use e173::schema::EstaDmx;
use itertools::Itertools;
fn main() {
let doc: E173Document =
serde_json::from_str(include_str!("data/martin_mac_encore_performance_cld.json")).unwrap();
let device_class = doc
.e173doc
.device_classes
.get("com.martin.dev.encore-performance-cold")
.unwrap()
.get("1.0.0")
.unwrap();
eprintln!("Deserialized UDR Document:");
eprintln!(" -- Author: {}", device_class.author);
eprintln!(" -- Manufacturer: {}", device_class.info.manufacturer.name);
eprintln!(" -- Model: {}", device_class.info.model.name);
eprint!("\nParsing ESTA DMX serializer...");
let esta_dmx = serde_json::from_value::<EstaDmx>(
device_class
.serializers
.get("dmx")
.unwrap()
.default
.clone()
.unwrap(),
)
.unwrap();
eprintln!("Done.");
eprint!("Transforming DMX data...");
let transformed = DmxDriver::from(&esta_dmx).unwrap();
eprintln!("Done.");
println!("{}", serde_json::to_string_pretty(&transformed).unwrap());
to_html_output(&transformed, "export.html").unwrap();
}
fn to_html_output(dmx_driver: &DmxDriver, file_name: &str) -> std::io::Result<()> {
let mut out = BufWriter::new(File::create(file_name)?);
out.write(b"<html><head>\n")?;
out.write(b"<title>MAC Encore Performance - Standard</title>")?;
out.write(
b"<style>\n\
table { border-collapse: collapse; }\n\
td { border: 1px solid black; }\n\
.dmx { color: grey; }\n\
.none { color: grey; }\n\
.calc { color: grey; }\n\
</style>\n",
)?;
out.write(b"<h2>DMX Combinations</h2>")?;
for cluster in &dmx_driver.clusters {
let mut param_vec: Vec<_> = cluster.parameters.iter().collect();
param_vec.sort();
out.write(b"<table>\n")?;
out.write(b"<tr>")?;
for parameter in ¶m_vec {
out.write(format!("<th>{}</th>", parameter).as_bytes())?;
}
out.write(b"</tr>")?;
let mut combinations = cluster.combinations.clone();
combinations.sort_by(compare_parameter_combo);
for combination in combinations {
out.write(b"<tr>\n")?;
for parameter in ¶m_vec {
out.write(b"<td>")?;
if let Some(constraint) = combination.constraints.get(*parameter) {
out.write(range_to_html(&constraint.param_range).as_bytes())?;
if let Some(mapping) = &constraint.dmx_mapping {
let offsets = &dmx_driver.chunks.get(&mapping.chunk_id).unwrap().offsets;
out.write(b"<br><span class=\"dmx\">Ch ")?;
out.write(
offsets
.iter()
.map(|offset| (offset + 1).to_string())
.join("+")
.as_bytes(),
)?;
out.write(format!(": {}", mapping.start).as_bytes())?;
if mapping.end != mapping.start {
out.write(format!(" > {}", mapping.end).as_bytes())?;
}
out.write(b"</span>")?;
}
if constraint.calculated {
out.write(b"<br><span class=\"calc\">calculated</span>")?;
}
}
out.write(b"</td>")?;
}
out.write(b"</tr>")?;
}
out.write(b"</table>")?;
}
out.write(b"</body></html>")?;
out.flush()
}
fn compare_parameter_combo(lhs: &ParameterCombo, rhs: &ParameterCombo) -> Ordering {
if lhs.constraints.len() != rhs.constraints.len() {
return lhs.constraints.len().cmp(&rhs.constraints.len());
}
let mut lhs_constraints: Vec<_> = lhs.constraints.iter().collect();
let mut rhs_constraints: Vec<_> = rhs.constraints.iter().collect();
lhs_constraints.sort_by(compare_constraint);
rhs_constraints.sort_by(compare_constraint);
let mismatch = lhs_constraints
.into_iter()
.zip(rhs_constraints.into_iter())
.find(|(lhs, rhs)| lhs != rhs);
match mismatch {
None => Ordering::Equal,
Some((lhs, rhs)) => compare_constraint(&lhs, &rhs),
}
}
fn compare_constraint(
lhs: &(&String, &ParameterConstraint),
rhs: &(&String, &ParameterConstraint),
) -> Ordering {
lhs.0.cmp(&rhs.0).then(
lhs.1
.param_range
.partial_cmp(&rhs.1.param_range)
.unwrap_or(Ordering::Equal),
)
}
fn range_to_html(range: &ParamRange) -> String {
match range {
ParamRange::Null => "<span class=\"none\" />".into(),
ParamRange::Bool { start, end } => {
if start != end {
format!("{start} > {end}")
} else {
format!("{start}")
}
}
ParamRange::Numeric { start, end } => {
if start != end {
format!("{start} > {end}")
} else {
format!("{start}")
}
}
}
}