use crate::{
query::{NationEventKind, NationEvents},
CountryTag, Eu4Date,
};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy)]
pub struct TagData {
pub current: CountryTag,
pub stored: CountryTag,
}
#[derive(Debug, Default)]
struct TagHistory {
initial: Option<NationEvents>,
timeline: Vec<(Eu4Date, NationEvents)>,
}
#[derive(Debug)]
pub struct TagResolver {
switches: HashMap<CountryTag, TagHistory>,
}
impl TagResolver {
pub fn create(nation_events: &[NationEvents]) -> Self {
let mut changes: HashMap<_, TagHistory> = HashMap::new();
for nation in nation_events {
let initial = changes.entry(nation.initial).or_default();
initial.initial = Some(nation.clone());
for event in nation.events.iter() {
if let NationEventKind::TagSwitch(to) = event.kind {
let v = changes.entry(to).or_default();
v.timeline.push((event.date, nation.clone()));
}
}
}
for history in changes.values_mut() {
history.timeline.sort_by_key(|(date, _)| *date);
}
TagResolver { switches: changes }
}
fn resolve_nation(&self, tag: CountryTag, date: Eu4Date) -> Option<&NationEvents> {
self.switches.get(&tag).and_then(|x| {
x.timeline
.iter()
.take_while(|(change_date, _)| *change_date <= date)
.last()
.map(|(_, nation)| nation)
.or(x.initial.as_ref())
})
}
pub fn resolve(&self, tag: CountryTag, date: Eu4Date) -> Option<TagData> {
self.resolve_nation(tag, date).map(|x| TagData {
current: x.latest,
stored: x.stored,
})
}
fn initial_nation(&self, tag: CountryTag) -> Option<&NationEvents> {
self.switches.get(&tag).and_then(|x| x.initial.as_ref())
}
pub fn initial(&self, tag: CountryTag) -> Option<TagData> {
self.initial_nation(tag).map(|x| TagData {
current: x.latest,
stored: x.stored,
})
}
pub fn at(&self, date: Eu4Date) -> TagResolverDated {
TagResolverDated { inner: self, date }
}
}
#[derive(Debug)]
pub struct TagResolverDated<'a> {
inner: &'a TagResolver,
date: Eu4Date,
}
impl<'a> TagResolverDated<'a> {
fn filter_events(&self, nation: &NationEvents) -> Option<(CountryTag, CountryTag)> {
nation
.events
.iter()
.take_while(|e| e.date <= self.date)
.filter_map(|x| x.as_tag_switch())
.last()
.map(|(_date, tag)| (tag, nation.stored))
}
pub fn resolve(&self, tag: CountryTag, date: Eu4Date) -> Option<TagData> {
self.inner.resolve_nation(tag, date).map(|x| {
self.filter_events(x)
.map(|(current, stored)| TagData { current, stored })
.unwrap_or_else(|| TagData {
current: x.initial,
stored: x.stored,
})
})
}
pub fn initial(&self, tag: CountryTag) -> Option<TagData> {
self.inner
.initial_nation(tag)
.and_then(|x| self.filter_events(x))
.map(|(current, stored)| TagData { current, stored })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::query::NationEvent;
#[test]
pub fn tag_resolver_1() {
let data = vec![NationEvents {
initial: "OIR".parse().unwrap(),
latest: "HLR".parse().unwrap(),
stored: "HLR".parse().unwrap(),
events: vec![
NationEvent {
date: "1456.11.16".parse().unwrap(),
kind: NationEventKind::TagSwitch("MCH".parse().unwrap()),
},
NationEvent {
date: "1460.5.25".parse().unwrap(),
kind: NationEventKind::TagSwitch("TIM".parse().unwrap()),
},
NationEvent {
date: "1463.1.21".parse().unwrap(),
kind: NationEventKind::TagSwitch("GLH".parse().unwrap()),
},
NationEvent {
date: "1463.6.7".parse().unwrap(),
kind: NationEventKind::TagSwitch("SIA".parse().unwrap()),
},
NationEvent {
date: "1463.6.17".parse().unwrap(),
kind: NationEventKind::TagSwitch("BAV".parse().unwrap()),
},
NationEvent {
date: "1467.3.4".parse().unwrap(),
kind: NationEventKind::TagSwitch("KOJ".parse().unwrap()),
},
NationEvent {
date: "1467.8.12".parse().unwrap(),
kind: NationEventKind::TagSwitch("POL".parse().unwrap()),
},
NationEvent {
date: "1467.8.12".parse().unwrap(),
kind: NationEventKind::TagSwitch("ENG".parse().unwrap()),
},
NationEvent {
date: "1467.8.12".parse().unwrap(),
kind: NationEventKind::TagSwitch("MOR".parse().unwrap()),
},
NationEvent {
date: "1467.9.20".parse().unwrap(),
kind: NationEventKind::TagSwitch("SCO".parse().unwrap()),
},
NationEvent {
date: "1467.9.20".parse().unwrap(),
kind: NationEventKind::TagSwitch("TUN".parse().unwrap()),
},
NationEvent {
date: "1467.10.1".parse().unwrap(),
kind: NationEventKind::TagSwitch("DLH".parse().unwrap()),
},
NationEvent {
date: "1467.10.1".parse().unwrap(),
kind: NationEventKind::TagSwitch("DAI".parse().unwrap()),
},
NationEvent {
date: "1467.10.1".parse().unwrap(),
kind: NationEventKind::TagSwitch("YUA".parse().unwrap()),
},
NationEvent {
date: "1467.10.1".parse().unwrap(),
kind: NationEventKind::TagSwitch("MGE".parse().unwrap()),
},
NationEvent {
date: "1468.12.12".parse().unwrap(),
kind: NationEventKind::TagSwitch("HLR".parse().unwrap()),
},
],
}];
let oirat: CountryTag = "OIR".parse().unwrap();
let manchu: CountryTag = "MCH".parse().unwrap();
let mongol: CountryTag = "MGE".parse().unwrap();
let hre: CountryTag = "HLR".parse().unwrap();
let resolver = TagResolver::create(&data);
let x = resolver.initial(oirat).unwrap();
assert_eq!(x.current, hre);
assert_eq!(x.stored, hre);
let x = resolver
.resolve(oirat, "1445.08.03".parse().unwrap())
.unwrap();
assert_eq!(x.current, hre);
assert_eq!(x.stored, hre);
let x = resolver
.resolve(manchu, "1458.12.04".parse().unwrap())
.unwrap();
assert_eq!(x.current, hre);
assert_eq!(x.stored, hre);
let x = resolver
.resolve("TUN".parse().unwrap(), "1467.9.20".parse().unwrap())
.unwrap();
assert_eq!(x.current, hre);
assert_eq!(x.stored, hre);
let dated = resolver.at("1458.12.04".parse().unwrap());
let olgii = dated.initial(oirat).unwrap();
assert_eq!(olgii.current, manchu);
assert_eq!(olgii.stored, hre);
let almaty = dated.resolve(oirat, "1445.08.03".parse().unwrap()).unwrap();
assert_eq!(almaty.current, manchu);
assert_eq!(almaty.stored, hre);
let yongping = dated
.resolve(manchu, "1458.12.04".parse().unwrap())
.unwrap();
assert_eq!(yongping.current, manchu);
assert_eq!(yongping.stored, hre);
let dated = resolver.at("1468.1.1".parse().unwrap());
let x = dated.initial(oirat).unwrap();
assert_eq!(x.current, mongol);
assert_eq!(x.stored, hre);
let dated = resolver.at("1467.10.1".parse().unwrap());
let x = dated.initial(oirat).unwrap();
assert_eq!(x.current, mongol);
assert_eq!(x.stored, hre);
let x = dated
.resolve("TUN".parse().unwrap(), "1467.9.20".parse().unwrap())
.unwrap();
assert_eq!(x.current, mongol);
assert_eq!(x.stored, hre);
let almaty = resolver
.resolve(oirat, "1445.08.03".parse().unwrap())
.unwrap();
assert_eq!(almaty.current, hre);
assert_eq!(almaty.stored, hre);
let dated = resolver.at("1447.03.11".parse().unwrap());
let almaty = dated.resolve(oirat, "1445.08.03".parse().unwrap()).unwrap();
assert_eq!(almaty.current, oirat);
assert_eq!(almaty.stored, hre);
}
}