use std::collections::HashSet;
use super::*;
pub mod criterion;
pub mod ext;
pub mod htree;
pub mod lod;
pub mod org;
pub mod semantic_series;
pub mod standard;
pub mod status;
pub mod status_action;
pub use criterion::*;
pub use ext::*;
pub use htree::SubTreeGrouping;
pub use lod::AssetLod;
pub use org::{AssetGov, AssetOrg, StatusFilter};
pub use semantic_series::*;
pub use standard::*;
pub use status::AssetStatus;
pub use status_action::*;
#[cfg(feature = "gui")]
use mktree::MkTree;
use mkentity::{Entity, ProjectSource};
pub type SemanticMap = HashMap<Semantic, Vec<ProductionAsset>>;
const EMPTY_ASSET_NAME: &str = "";
const MAX_ASSET_NAME_LENGTH: u8 = 80;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ProductionAsset {
#[default]
Null,
Manual(StandardAsset),
#[cfg(feature = "mongo")]
Mongo(StandardAsset),
#[cfg(feature = "kitsu")]
Kitsu(KitsuAsset),
}
impl Entity for ProductionAsset {
fn empty() -> Self {
Self::Null
}
fn as_group(group_name: &str, typ: &ProjectSource) -> Self {
match typ {
ProjectSource::Offline => Self::Manual(StandardAsset::as_group(group_name, typ)),
#[cfg(feature = "mongo")]
ProjectSource::Mongo => Self::Mongo(StandardAsset::as_group(group_name, typ)),
#[cfg(feature = "kitsu")]
ProjectSource::Zou => Self::Kitsu(KitsuAsset::as_group(group_name, typ)),
}
}
fn name(&self) -> Option<&String> {
match self {
Self::Null => None,
Self::Manual(inner) => inner.name(),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => inner.name(),
#[cfg(feature = "kitsu")]
Self::Kitsu(inner) => inner.name(),
}
}
}
impl ProductionAsset {
#[cfg(feature = "mongo")]
pub fn mongo(sem: &Semantic, asset_name: &str) -> Self {
Self::Mongo(StandardAsset::new(sem, asset_name))
}
pub fn inner_standard_owned(self) -> Option<StandardAsset> {
match self {
Self::Manual(inner) => Some(inner),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => Some(inner),
_ => None,
}
}
pub fn inner_standard(&self) -> Option<&StandardAsset> {
match self {
Self::Manual(inner) => Some(inner),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => Some(inner),
_ => None,
}
}
#[cfg(feature = "kitsu")]
pub fn inner_kitsu(&self) -> Option<&KitsuAsset> {
match self {
Self::Kitsu(inner) => Some(inner),
_ => None,
}
}
pub fn name_or_empty(&self) -> &str {
match self {
Self::Null => EMPTY_ASSET_NAME,
Self::Manual(inner) => inner.name_or_empty(),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => inner.name_or_empty(),
#[cfg(feature = "kitsu")]
Self::Kitsu(inner) => inner.name_or_empty(),
}
}
pub fn selection_names(selection: &HashSet<Self>, bullet: Option<&str>) -> String {
let join = match bullet {
Some(b) => format!("\n{}", b),
None => String::from("\n"),
};
let mut names = selection
.iter()
.filter_map(|a| a.name())
.map(|n| n.as_str())
.collect::<Vec<&str>>()
.join(&join);
if let Some(b) = bullet {
names = format!("{}{}", b, names);
};
names
}
pub fn semantic_str_and_name(&self) -> AnyResult<(String, String)> {
match self {
Self::Null => Err(anyhow!("Null asset doesn\'t have category and name")),
Self::Manual(inner) => inner.semantic_and_name(),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => inner.semantic_and_name(),
#[cfg(feature = "kitsu")]
Self::Kitsu(_) => Err(anyhow!("kitsu category and asset name: unimplemented")),
}
}
pub fn format_with_active_project(&self, project: &Project) -> String {
format!("🚩[{}]:: {}", project, self.name_or_empty())
}
pub fn bson_id_owned(self) -> Option<ObjectId> {
match self {
Self::Null => None,
Self::Manual(inner) => inner.id,
#[cfg(feature = "mongo")]
Self::Mongo(inner) => inner.id,
#[cfg(feature = "kitsu")]
Self::Kitsu(_) => None,
}
}
pub fn has_semantic(&self) -> bool {
self.semantic().is_some()
}
pub fn semantic(&self) -> Option<&Semantic> {
match self {
Self::Null => None,
Self::Manual(inner) => Some(inner.semantic()),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => Some(inner.semantic()),
#[cfg(feature = "kitsu")]
Self::Kitsu(_) => None,
}
}
pub fn has_criteria(&self) -> bool {
self.criteria().is_some()
}
pub fn criteria(&self) -> Option<&Vec<ObjectId>> {
match self {
Self::Null => None,
Self::Manual(inner) => inner.criteria(),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => inner.criteria(),
#[cfg(feature = "kitsu")]
Self::Kitsu(_) => None,
}
}
pub fn group_by_semantic(assets: Vec<Self>) -> Vec<SemanticSeries> {
let mut map = HashMap::new();
for a in assets.into_iter().filter(|a| a.has_semantic()) {
let sem = a.semantic().unwrap();
match map.contains_key(sem) {
false => {
map.insert(sem.to_owned(), vec![a]);
}
true => {
if let Some(assets) = map.get_mut(sem) {
assets.push(a);
};
}
}
}
let mut groups: Vec<SemanticSeries> = map
.into_iter()
.map(|(sem, mut assets)| {
assets.sort();
SemanticSeries::from_semantic(sem).with_assets(assets)
})
.collect();
groups.sort_by(|a, b| a.semantic.partial_cmp(&b.semantic).unwrap());
groups
}
}
impl BsonId for ProductionAsset {
fn bson_id_as_ref(&self) -> Option<&ObjectId> {
match self {
Self::Null => None,
Self::Manual(inner) => inner.bson_id_as_ref(),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => inner.bson_id_as_ref(),
#[cfg(feature = "kitsu")]
Self::Kitsu(inner) => inner.bson_id_as_ref(),
}
}
fn bson_id(&self) -> AnyResult<&ObjectId> {
match self {
Self::Null => Err(anyhow!(
"Null ProductionAsset does not contain BSON ObjectId"
)),
Self::Manual(inner) => inner.bson_id(),
#[cfg(feature = "mongo")]
Self::Mongo(inner) => inner.bson_id(),
#[cfg(feature = "kitsu")]
Self::Kitsu(inner) => inner.bson_id(),
}
}
}
#[cfg(feature = "kitsu")]
#[derive(Serialize, Deserialize, Debug, Clone, Default, Eq, Hash)]
pub struct KitsuAsset {
id: String,
name: String,
description: String,
entity_type_id: String,
#[serde(skip)]
entity_type: String,
}
#[cfg(feature = "kitsu")]
impl Entity for KitsuAsset {
fn empty() -> Self {
Self::default()
}
fn as_group(entity_type: &str, _typ: &ProjectSource) -> Self {
Self {
entity_type: entity_type.to_owned(),
..Self::default()
}
}
fn name(&self) -> Option<&String> {
Some(&self.name)
}
}
#[cfg(feature = "kitsu")]
impl KitsuAsset {
fn name_or_empty(&self) -> &str {
&self.name
}
}
#[cfg(feature = "kitsu")]
impl BsonId for KitsuAsset {
fn bson_id_as_ref(&self) -> Option<&ObjectId> {
None
}
fn bson_id(&self) -> AnyResult<&ObjectId> {
self.bson_id_as_ref()
.context("kitsu asset BSON ID: unimplemented")
}
}
#[cfg(feature = "kitsu")]
impl PartialEq for KitsuAsset {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
#[cfg(feature = "kitsu")]
impl Ord for KitsuAsset {
fn cmp(&self, other: &Self) -> Ordering {
self.name.cmp(&other.name)
}
}
#[cfg(feature = "kitsu")]
impl PartialOrd for KitsuAsset {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}