use crate::{Actor, ActorBehavior, Message, Port};
use anyhow::{Error, Result};
use reflow_actor::ActorContext;
use reflow_actor_macro::actor;
use serde_json::json;
use std::collections::HashMap;
#[actor(
AnimationTimeActor,
inports::<10>(trigger),
outports::<1>(time, frame_number),
state(MemoryState)
)]
pub async fn animation_time_actor(ctx: ActorContext) -> Result<HashMap<String, Message>, Error> {
let config = ctx.get_config_hashmap();
let log_progress = config
.get("logProgress")
.and_then(|v| v.as_bool())
.unwrap_or(false);
let speed = config.get("speed").and_then(|v| v.as_f64()).unwrap_or(1.0);
let fps = config.get("fps").and_then(|v| v.as_f64()).unwrap_or(30.0);
let _duration = config
.get("duration")
.and_then(|v| v.as_f64())
.unwrap_or(0.0);
let state: HashMap<String, serde_json::Value> =
ctx.get_pool("_anim_time").into_iter().collect();
let elapsed = state.get("elapsed").and_then(|v| v.as_f64()).unwrap_or(0.0);
let frame = state.get("frame").and_then(|v| v.as_u64()).unwrap_or(0);
let dt = (1.0 / fps) * speed;
let new_elapsed = elapsed + dt;
let new_frame = frame + 1;
ctx.pool_upsert("_anim_time", "elapsed", json!(new_elapsed));
ctx.pool_upsert("_anim_time", "frame", json!(new_frame));
if log_progress && (new_frame <= 3 || new_frame % 6 == 0) {
eprintln!(
"[anim_time] frame={} time={:.3} dt={:.3}",
new_frame, new_elapsed, dt
);
}
let mut out = HashMap::new();
out.insert("time".to_string(), Message::Float(new_elapsed));
out.insert(
"frame_number".to_string(),
Message::Integer(new_frame as i64),
);
Ok(out)
}