use serde::{Deserialize, Serialize};
use tracing::{debug, warn};
use crate::parser::{
creature_effect::TOKEN_MAP as CREATURE_EFFECT_TOKENS,
serializer_helper, {clean_search_vec, Searchable},
};
use super::{phf_table::SYNDROME_TOKEN, tokens::SyndromeToken};
#[derive(Serialize, Deserialize, Debug, Clone, Default, specta::Type)]
#[serde(rename_all = "camelCase")]
pub struct Syndrome {
#[serde(skip_serializing_if = "Option::is_none")]
identifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
affected_classes: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
immune_classes: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
affected_creatures: Option<Vec<(String, String)>>,
#[serde(skip_serializing_if = "Option::is_none")]
immune_creatures: Option<Vec<(String, String)>>,
#[serde(skip_serializing_if = "Option::is_none")]
classes: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
concentration_added: Option<[u32; 2]>,
#[serde(skip_serializing_if = "Option::is_none")]
tags: Option<Vec<SyndromeToken>>,
#[serde(skip_serializing_if = "Option::is_none")]
conditions: Option<Vec<String>>,
}
impl Syndrome {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn from_name(name: &str) -> Self {
Self {
name: Some(String::from(name)),
..Self::default()
}
}
#[must_use]
pub fn cleaned(&self) -> Self {
let mut cleaned = self.clone();
if let Some(identifier) = &cleaned.identifier {
if identifier.is_empty() {
cleaned.identifier = None;
}
}
if let Some(name) = &cleaned.name {
if name.is_empty() {
cleaned.name = None;
}
}
if let Some(affected_classes) = &cleaned.affected_classes {
if affected_classes.is_empty() {
cleaned.affected_classes = None;
}
}
if let Some(immune_classes) = &cleaned.immune_classes {
if immune_classes.is_empty() {
cleaned.immune_classes = None;
}
}
if let Some(affected_creatures) = &cleaned.affected_creatures {
if affected_creatures.is_empty() {
cleaned.affected_creatures = None;
}
}
if let Some(immune_creatures) = &cleaned.immune_creatures {
if immune_creatures.is_empty() {
cleaned.immune_creatures = None;
}
}
if let Some(classes) = &cleaned.classes {
if classes.is_empty() {
cleaned.classes = None;
}
}
if serializer_helper::min_max_is_zeroes(&cleaned.concentration_added) {
cleaned.concentration_added = None;
}
if let Some(tags) = &cleaned.tags {
if tags.is_empty() {
cleaned.tags = None;
}
}
if let Some(conditions) = &cleaned.conditions {
if conditions.is_empty() {
cleaned.conditions = None;
}
}
cleaned
}
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
pub fn parse_tag(&mut self, key: &str, value: &str) {
if CREATURE_EFFECT_TOKENS.contains_key(key) {
if self.conditions.is_none() {
self.conditions = Some(Vec::new());
}
if let Some(conditions) = self.conditions.as_mut() {
conditions.push(String::from(value));
}
return;
}
if key == "CE" {
debug!("Manual handling of CE tag: {}:{}", key, value);
if self.conditions.is_none() {
self.conditions = Some(Vec::new());
}
if let Some(conditions) = self.conditions.as_mut() {
conditions.push(String::from(value));
}
return;
}
let token = SYNDROME_TOKEN.get(key).unwrap_or(&SyndromeToken::Unknown);
match token {
SyndromeToken::Name => self.name = Some(String::from(value)),
SyndromeToken::Identifier => self.identifier = Some(String::from(value)),
SyndromeToken::AffectedClass => {
if self.affected_classes.is_none() {
self.affected_classes = Some(Vec::new());
}
if let Some(affected_classes) = self.affected_classes.as_mut() {
affected_classes.push(String::from(value));
}
}
SyndromeToken::ImmuneClass => {
if self.immune_classes.is_none() {
self.immune_classes = Some(Vec::new());
}
if let Some(immune_classes) = self.immune_classes.as_mut() {
immune_classes.push(String::from(value));
}
}
SyndromeToken::AffectedCreature => {
if self.affected_creatures.is_none() {
self.affected_creatures = Some(Vec::new());
}
let mut split = value.split(':');
let creature = split.next().unwrap_or_default().trim();
let caste = split.next().unwrap_or_default().trim();
if let Some(affected_creatures) = self.affected_creatures.as_mut() {
affected_creatures.push((String::from(creature), String::from(caste)));
}
}
SyndromeToken::ImmuneCreature => {
if self.immune_creatures.is_none() {
self.immune_creatures = Some(Vec::new());
}
let mut split = value.split(':');
let creature = split.next().unwrap_or_default().trim();
let caste = split.next().unwrap_or_default().trim();
if let Some(immune_creatures) = self.immune_creatures.as_mut() {
immune_creatures.push((String::from(creature), String::from(caste)));
}
}
SyndromeToken::ConcentrationAdded => {
let mut split = value.split(':');
let min = split.next().unwrap_or_default().trim();
let max = split.next().unwrap_or_default().trim();
self.concentration_added = Some([
min.parse::<u32>().unwrap_or_default(),
max.parse::<u32>().unwrap_or_default(),
]);
}
SyndromeToken::Injected => {
if self.tags.is_none() {
self.tags = Some(Vec::new());
}
if let Some(tags) = self.tags.as_mut() {
tags.push(SyndromeToken::Injected);
}
}
SyndromeToken::Contact => {
if self.tags.is_none() {
self.tags = Some(Vec::new());
}
if let Some(tags) = self.tags.as_mut() {
tags.push(SyndromeToken::Contact);
}
}
SyndromeToken::Inhaled => {
if self.tags.is_none() {
self.tags = Some(Vec::new());
}
if let Some(tags) = self.tags.as_mut() {
tags.push(SyndromeToken::Inhaled);
}
}
SyndromeToken::Ingested => {
if self.tags.is_none() {
self.tags = Some(Vec::new());
}
if let Some(tags) = self.tags.as_mut() {
tags.push(SyndromeToken::Ingested);
}
}
SyndromeToken::Unknown => {
warn!("Unknown syndrome token: {}", key);
}
SyndromeToken::Class => {
if self.classes.is_none() {
self.classes = Some(Vec::new());
}
if let Some(classes) = self.classes.as_mut() {
classes.push(String::from(value));
}
}
SyndromeToken::NoHospital => {
if self.tags.is_none() {
self.tags = Some(Vec::new());
}
if let Some(tags) = self.tags.as_mut() {
tags.push(SyndromeToken::NoHospital);
}
}
}
}
}
impl Searchable for Syndrome {
fn get_search_vec(&self) -> Vec<String> {
let mut vec = Vec::new();
if let Some(identifier) = &self.identifier {
vec.push(identifier.clone());
}
if let Some(name) = &self.name {
vec.push(name.clone());
}
if let Some(affected_classes) = &self.affected_classes {
for affected_class in affected_classes {
vec.push(affected_class.clone());
}
}
if let Some(immune_classes) = &self.immune_classes {
for immune_class in immune_classes {
vec.push(immune_class.clone());
}
}
if let Some(affected_creatures) = &self.affected_creatures {
for (creature, caste) in affected_creatures {
vec.push(creature.clone());
vec.push(caste.clone());
}
}
if let Some(immune_creatures) = &self.immune_creatures {
for (creature, caste) in immune_creatures {
vec.push(creature.clone());
vec.push(caste.clone());
}
}
if let Some(classes) = &self.classes {
for class in classes {
vec.push(class.clone());
}
}
if let Some(conditions) = &self.conditions {
for condition in conditions {
vec.push(condition.clone());
}
}
clean_search_vec(vec.as_slice())
}
}