use serde::{Deserialize, Serialize};
use slug::slugify;
use crate::parser::{
clean_search_vec, material::Material, serializer_helper, ObjectType, RawMetadata, RawObject,
Searchable,
};
use super::{
phf_table::{ENVIRONMENT_CLASS_TOKENS, INCLUSION_TYPE_TOKENS, INORGANIC_TOKENS},
tokens::{EnvironmentClass, InclusionType, InorganicToken},
};
#[derive(Serialize, Deserialize, Debug, Clone, Default, specta::Type)]
#[serde(rename_all = "camelCase")]
pub struct Inorganic {
identifier: String,
#[serde(skip_serializing_if = "Option::is_none")]
metadata: Option<RawMetadata>,
object_id: String,
material: Material,
#[serde(skip_serializing_if = "Option::is_none")]
metal_ore_chance: Option<Vec<(String, u8)>>,
#[serde(skip_serializing_if = "Option::is_none")]
thread_metal_chance: Option<Vec<(String, u8)>>,
#[serde(skip_serializing_if = "Option::is_none")]
environment_class: Option<EnvironmentClass>,
#[serde(skip_serializing_if = "Option::is_none")]
environment_inclusion_type: Option<InclusionType>,
#[serde(skip_serializing_if = "Option::is_none")]
environment_inclusion_frequency: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
environment_class_specific: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
tags: Option<Vec<InorganicToken>>,
}
impl Inorganic {
#[must_use]
pub fn empty() -> Self {
Self {
metadata: Some(
RawMetadata::default()
.with_object_type(ObjectType::Inorganic)
.with_hidden(true),
),
..Self::default()
}
}
#[must_use]
pub fn new(identifier: &str, metadata: &RawMetadata) -> Self {
Self {
identifier: String::from(identifier),
metadata: Some(metadata.clone()),
object_id: format!(
"{}-{}-{}",
metadata.get_raw_identifier(),
"INORGANIC",
slugify(identifier)
),
..Self::default()
}
}
#[must_use]
pub fn cleaned(&self) -> Self {
let mut cleaned = self.clone();
if let Some(metadata) = &cleaned.metadata {
if metadata.is_hidden() {
cleaned.metadata = None;
}
}
if let Some(metal_ore_chance) = &cleaned.metal_ore_chance {
if metal_ore_chance.is_empty() {
cleaned.metal_ore_chance = None;
}
}
if let Some(thread_metal_chance) = &cleaned.thread_metal_chance {
if thread_metal_chance.is_empty() {
cleaned.thread_metal_chance = None;
}
}
if let Some(environment_class) = &cleaned.environment_class {
if environment_class.is_default() {
cleaned.environment_class = None;
}
}
if let Some(environment_inclusion_type) = &cleaned.environment_inclusion_type {
if environment_inclusion_type.is_default() {
cleaned.environment_inclusion_type = None;
}
}
if serializer_helper::is_zero(cleaned.environment_inclusion_frequency) {
cleaned.environment_inclusion_frequency = None;
}
if let Some(environment_class_specific) = &cleaned.environment_class_specific {
if environment_class_specific.is_empty() {
cleaned.environment_class_specific = None;
}
}
cleaned
}
pub fn add_tag(&mut self, tag: InorganicToken) {
if self.tags.is_none() {
self.tags = Some(Vec::new());
}
if let Some(tags) = self.tags.as_mut() {
tags.push(tag);
} else {
tracing::warn!(
"Inorganic::add_tag: ({}) Failed to add tag {:?}",
self.identifier,
tag
);
}
}
}
#[typetag::serde]
impl RawObject for Inorganic {
fn get_identifier(&self) -> &str {
&self.identifier
}
fn get_name(&self) -> &str {
&self.identifier
}
fn get_metadata(&self) -> RawMetadata {
self.metadata.as_ref().map_or_else(
|| {
tracing::warn!("Metadata is missing for Inorganic {}", self.get_object_id());
RawMetadata::default()
.with_object_type(ObjectType::Inorganic)
.with_hidden(true)
},
std::clone::Clone::clone,
)
}
fn is_empty(&self) -> bool {
self.identifier.is_empty()
}
fn get_type(&self) -> &ObjectType {
&ObjectType::Inorganic
}
fn clean_self(&mut self) {
*self = self.cleaned();
}
fn parse_tag(&mut self, key: &str, value: &str) {
if INORGANIC_TOKENS.contains_key(key) {
let token = INORGANIC_TOKENS
.get(key)
.unwrap_or(&InorganicToken::Unknown);
match token {
InorganicToken::Environment => {
let mut split = value.split(':');
self.environment_class = Some(
ENVIRONMENT_CLASS_TOKENS
.get(split.next().unwrap_or(""))
.unwrap_or(&EnvironmentClass::None)
.clone(),
);
self.environment_inclusion_type = Some(
INCLUSION_TYPE_TOKENS
.get(split.next().unwrap_or(""))
.unwrap_or(&InclusionType::None)
.clone(),
);
self.environment_inclusion_frequency =
Some(split.next().unwrap_or("0").parse::<u32>().unwrap_or(0));
}
InorganicToken::EnvironmentSpecific => {
if self.environment_class_specific.is_none() {
self.environment_class_specific = Some(Vec::new());
}
if let Some(environment_class_specific) = &mut self.environment_class_specific {
environment_class_specific.push(String::from(value));
}
}
InorganicToken::MetalOre => {
if self.metal_ore_chance.is_none() {
self.metal_ore_chance = Some(Vec::new());
}
let mut split = value.split(':');
let metal = String::from(split.next().unwrap_or(""));
let chance = split.next().unwrap_or("0").parse::<u8>().unwrap_or(0);
if let Some(metal_ore_chance) = self.metal_ore_chance.as_mut() {
metal_ore_chance.push((metal, chance));
}
}
InorganicToken::ThreadMetal => {
if self.thread_metal_chance.is_none() {
self.thread_metal_chance = Some(Vec::new());
}
let mut split = value.split(':');
let metal = String::from(split.next().unwrap_or(""));
let chance = split.next().unwrap_or("0").parse::<u8>().unwrap_or(0);
if let Some(thread_metal_chance) = self.thread_metal_chance.as_mut() {
thread_metal_chance.push((metal, chance));
}
}
_ => {
self.add_tag(token.clone());
}
}
return;
}
self.material.parse_tag(key, value);
}
fn get_object_id(&self) -> &str {
&self.object_id
}
}
impl Searchable for Inorganic {
fn get_search_vec(&self) -> Vec<String> {
let mut vec = Vec::new();
vec.push(self.identifier.clone());
vec.extend(self.material.get_search_vec());
if let Some(tags) = &self.tags {
vec.extend(tags.iter().map(std::string::ToString::to_string));
}
if let Some(environment_class) = &self.environment_class {
vec.push(environment_class.to_string());
}
if let Some(environment_inclusion_type) = &self.environment_inclusion_type {
vec.push(environment_inclusion_type.to_string());
}
if let Some(environment_inclusion_frequency) = &self.environment_inclusion_frequency {
vec.push(environment_inclusion_frequency.to_string());
}
if let Some(environment_class_specific) = &self.environment_class_specific {
vec.extend(environment_class_specific.iter().cloned());
}
clean_search_vec(vec.as_slice())
}
}