use crate::commands::{step, Command, CommandError};
use crate::event::Event;
use crate::observer::EventObserver;
use crate::state::GameState;
use std::io::{BufRead, Write};
use std::path::Path;
pub struct Session {
pub state: GameState,
pub log: Vec<Event>,
}
impl Session {
pub fn from_events(log: Vec<Event>, observers: &mut [&mut dyn EventObserver]) -> Session {
let state = GameState::replay(&log);
for event in &log {
for obs in observers.iter_mut() {
obs.on_event(event);
}
}
Session { state, log }
}
pub fn execute(
&mut self,
command: Command,
observers: &mut [&mut dyn EventObserver],
) -> Result<&[Event], CommandError> {
let events = step(&self.state, command)?;
let start = self.log.len();
for event in events {
self.state.apply(&event);
for obs in observers.iter_mut() {
obs.on_event(&event);
}
self.log.push(event);
}
Ok(&self.log[start..])
}
}
pub fn save_log(path: &Path, log: &[Event]) -> std::io::Result<()> {
let file = std::fs::File::create(path)?;
let mut writer = std::io::BufWriter::new(file);
for event in log {
let line = serde_json::to_string(event)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
writeln!(writer, "{line}")?;
}
writer.flush()
}
pub fn load_log(path: &Path) -> std::io::Result<Vec<Event>> {
let file = std::fs::File::open(path)?;
let reader = std::io::BufReader::new(file);
let mut log = Vec::new();
for line in reader.lines() {
let line = line?;
if line.trim().is_empty() {
continue;
}
let event: Event = serde_json::from_str(&line)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
log.push(event);
}
Ok(log)
}