use std::fmt::Write;
use yog_data::schema::StructShape;
use crate::EventInfo;
use super::{Entry, Out, file, name, target};
pub(super) const CLASS: &str = "YogEvents";
fn event_body(e: &EventInfo) -> String {
let mut body = String::new();
if e.key.is_none() {
let _ = write!(
body,
"\n\n private static final class Address {{\n static final int POST = YogBus.resolve({});",
name(e.address)
);
if let Some(p) = e.pre {
let _ = write!(
body,
"\n static final int PRE = YogBus.resolve({});",
name(p)
);
}
body.push_str("\n }\n\n /** Whether anyone listens — skip building an event no one hears. */\n public static boolean heard() {\n return YogBus.heard(Address.POST);\n }");
}
let _ = write!(
body,
"\n\n /** Emits it; the reply, read in place, is what the handlers changed it to (empty: none did). */\n public YogMessage emit() {{\n return YogBus.emit({}, packedFrame());\n }}",
target(e.address, e.key, "POST")
);
body.push_str("\n\n /** Emits it and reads back what the handlers made of it (itself when the reply isn't one). */\n public ");
body.push_str(e.name);
body.push_str(" emitChanged() {\n YogMessage r = emit();\n // Nothing back: no handler changed it.\n if (!r.ok() || r.isEmpty()) return this;\n try {\n return fromFrame(r);\n } catch (RuntimeException e) {\n return this;\n }\n }");
if let Some(p) = e.pre {
let _ = write!(
body,
"\n\n public boolean emitPre() {{\n return YogBus.emit({}, packedFrame()).status() != YogBus.CANCELLED;\n }}",
target(p, e.key, "PRE")
);
}
body
}
pub(super) fn events(package: &str) -> (String, Vec<StructShape>) {
let entries: Vec<Entry> = crate::all()
.into_iter()
.map(|e| Entry {
path: e.plane,
name: e.name,
body: event_body(&e),
shape: e.shape,
})
.collect();
file(
package,
CLASS,
"The bus's events: a record per event; {@code emit} after the game did it, {@code emitPre} before (false: a handler cancelled it).",
Out::default(),
&entries,
)
}