use std::{
convert::TryFrom,
fs::File,
io::{BufReader, Read, Seek},
path::Path,
};
use super::{raw, Agent, Event, EvtcError, Log};
pub fn process(data: &raw::Evtc) -> Result<Log, EvtcError> {
let mut agents = setup_agents(data)?;
set_agent_awares(data, &mut agents)?;
set_agent_masters(data, &mut agents)?;
let events = data
.events
.iter()
.filter_map(|e| Event::try_from(e).ok())
.collect();
Ok(Log {
agents,
events,
boss_id: data.header.combat_id,
})
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Compression {
None,
Zip,
}
pub fn process_stream<R: Read + Seek>(
input: R,
compression: Compression,
) -> Result<Log, EvtcError> {
let evtc = match compression {
Compression::None => raw::parse_file(input)?,
Compression::Zip => raw::parse_zip(input)?,
};
process(&evtc)
}
pub fn process_file<P: AsRef<Path>>(path: P, compression: Compression) -> Result<Log, EvtcError> {
let file = File::open(path).map_err(Into::<raw::ParseError>::into)?;
let buffered = BufReader::new(file);
process_stream(buffered, compression)
}
fn setup_agents(data: &raw::Evtc) -> Result<Vec<Agent>, EvtcError> {
let mut agents = Vec::with_capacity(data.agents.len());
for raw_agent in &data.agents {
agents.push(Agent::try_from(raw_agent)?);
}
Ok(agents)
}
fn get_agent_by_addr(agents: &mut [Agent], addr: u64) -> Option<&mut Agent> {
for agent in agents {
if agent.addr == addr {
return Some(agent);
}
}
None
}
fn set_agent_awares(data: &raw::Evtc, agents: &mut [Agent]) -> Result<(), EvtcError> {
for event in &data.events {
if event.is_statechange == raw::CbtStateChange::None {
if let Some(current_agent) = get_agent_by_addr(agents, event.src_agent) {
current_agent.instance_id = event.src_instid;
if current_agent.first_aware == 0 {
current_agent.first_aware = event.time;
}
current_agent.last_aware = event.time;
}
}
}
Ok(())
}
fn set_agent_masters(data: &raw::Evtc, agents: &mut [Agent]) -> Result<(), EvtcError> {
for event in &data.events {
if event.src_master_instid != 0 {
let mut master_addr = None;
for agent in &*agents {
if agent.instance_id == event.src_master_instid
&& agent.first_aware < event.time
&& event.time < agent.last_aware
{
master_addr = Some(agent.addr);
break;
}
}
if let Some(master_addr) = master_addr {
if let Some(current_slave) = get_agent_by_addr(agents, event.src_agent) {
current_slave.master_agent = Some(master_addr);
}
}
}
}
Ok(())
}