use chappi_syntax::{Atom, Document, Form, FormKind, Span, canonicalize};
use crate::resume::{
affect_text, attention_text, confidence_text, constraint_text, desire_text, goal_status,
lifetime_text, metacognition_text, prediction_text, question_text, tension_text,
};
use crate::{CognitiveState, FocusFrame, Node, NodeKind, Relation, Source};
pub fn snapshot_document(state: &CognitiveState) -> Document {
let mut forms = vec![list(vec![symbol("chappi"), integer(state.version)])];
forms.extend(state.nodes.iter().map(node_form));
forms.extend(
state
.nodes
.iter()
.filter(|node| node.revision > 0)
.map(|node| {
list(vec![
symbol("revision"),
symbol(&node.id),
integer(node.revision),
])
}),
);
forms.extend(state.relations.iter().map(relation_form));
forms.extend(
state
.focus_streams
.iter()
.flat_map(|stream| stream.frames.iter())
.map(focus_form),
);
Document { forms }
}
pub fn snapshot_source(state: &CognitiveState) -> Vec<u8> {
canonicalize(&snapshot_document(state))
}
fn node_form(node: &Node) -> Form {
let mut items = vec![
symbol(node_head(&node.kind)),
symbol(&node.id),
symbol(&node.owner),
symbol(lifetime_text(node.lifetime)),
integer(node.salience),
];
match &node.kind {
NodeKind::Entity { entity_kind } => items.push(symbol(entity_kind)),
NodeKind::Claim { confidence } => items.push(symbol(confidence_text(*confidence))),
NodeKind::Evidence {
evidence_kind,
source,
} => {
items.push(symbol(evidence_kind));
items.push(match source {
Source::Symbol(value) => symbol(value),
Source::String(value) => string(value),
});
}
NodeKind::Goal { status } => items.push(symbol(goal_status(*status))),
NodeKind::Constraint { strength } => items.push(symbol(constraint_text(*strength))),
NodeKind::Question { status } => items.push(symbol(question_text(*status))),
NodeKind::Relationship { target, status } => {
items.push(symbol(target));
items.push(symbol(status));
}
NodeKind::Desire { force } => items.push(symbol(desire_text(*force))),
NodeKind::Attention { mode } => items.push(symbol(attention_text(*mode))),
NodeKind::Association => {}
NodeKind::Tension { status } => items.push(symbol(tension_text(*status))),
NodeKind::Prediction { confidence, status } => {
items.push(symbol(confidence_text(*confidence)));
items.push(symbol(prediction_text(*status)));
}
NodeKind::Perspective(value) => {
items.push(symbol(&value.target));
items.push(symbol(confidence_text(value.confidence)));
}
NodeKind::Affect {
target,
affect_kind,
intensity,
} => {
items.push(symbol(target));
items.push(symbol(affect_kind));
items.push(symbol(affect_text(*intensity)));
}
NodeKind::Metacognition { status } => items.push(symbol(metacognition_text(*status))),
}
items.push(node.payload.clone());
list(items)
}
fn node_head(kind: &NodeKind) -> &'static str {
match kind {
NodeKind::Entity { .. } => "entity",
NodeKind::Claim { .. } => "claim",
NodeKind::Evidence { .. } => "evidence",
NodeKind::Goal { .. } => "goal",
NodeKind::Constraint { .. } => "constraint",
NodeKind::Question { .. } => "question",
NodeKind::Relationship { .. } => "relationship",
NodeKind::Desire { .. } => "desire",
NodeKind::Attention { .. } => "attention",
NodeKind::Association => "association",
NodeKind::Tension { .. } => "tension",
NodeKind::Prediction { .. } => "prediction",
NodeKind::Perspective(_) => "perspective",
NodeKind::Affect { .. } => "affect",
NodeKind::Metacognition { .. } => "metacognition",
}
}
fn relation_form(relation: &Relation) -> Form {
list(vec![
symbol("rel"),
symbol(relation.kind.as_str()),
symbol(&relation.source),
symbol(&relation.target),
])
}
fn focus_form(frame: &FocusFrame) -> Form {
list(vec![
symbol("focus"),
symbol(&frame.stream_id),
integer(frame.sequence),
symbol(&frame.owner),
symbol(frame.transition.as_str()),
frame
.previous_sequence
.map_or_else(|| symbol("none"), integer),
bucket("fg", &frame.foreground),
bucket("bg", &frame.background),
bucket("residue", &frame.residue),
frame.trigger.clone(),
])
}
fn bucket(head: &str, ids: &[String]) -> Form {
let mut ids = ids.iter().collect::<Vec<_>>();
ids.sort_unstable();
list(
std::iter::once(symbol(head))
.chain(ids.into_iter().map(|id| symbol(id)))
.collect(),
)
}
fn list(items: Vec<Form>) -> Form {
Form {
span: empty_span(),
kind: FormKind::List(items),
}
}
fn symbol(value: &str) -> Form {
Form {
span: empty_span(),
kind: FormKind::Atom(Atom::Symbol(value.to_owned())),
}
}
fn string(value: &str) -> Form {
Form {
span: empty_span(),
kind: FormKind::Atom(Atom::String(value.to_owned())),
}
}
fn integer(value: impl ToString) -> Form {
Form {
span: empty_span(),
kind: FormKind::Atom(Atom::Integer(value.to_string())),
}
}
fn empty_span() -> Span {
Span {
start: 0,
end: 0,
start_line: 1,
start_column: 1,
end_line: 1,
end_column: 1,
}
}