use crate::ro_crate::constraints::EntityValue;
use crate::ro_crate::constraints::{DataType, License};
use crate::ro_crate::modify::{search_dynamic_entity_for_key, DynamicEntityManipulation};
use serde::ser::SerializeMap;
use serde::{
de::{self, MapAccess, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::collections::HashMap;
use std::fmt;
use super::constraints::Id;
#[derive(Debug, Clone)]
pub struct RootDataEntity {
pub id: String,
pub type_: DataType,
pub name: String,
pub description: String,
pub date_published: String,
pub license: License,
pub dynamic_entity: Option<HashMap<String, EntityValue>>,
}
impl fmt::Display for RootDataEntity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Metadata Description: ID={}, Type={:?}, Name={:?}, Description={:?}, Date Published={:?}, License={:?}",
self.id, self.type_, self.name, self.description, self.date_published, self.license
)
}
}
impl RootDataEntity {
pub fn add_entity_to_partof(&mut self, id_target: String) {
let dynamic_entity = self.dynamic_entity.get_or_insert_with(HashMap::new);
match dynamic_entity.get_mut("hasPart") {
Some(EntityValue::EntityId(Id::IdArray(id_array))) => {
if !id_array.iter().any(|id| id == &id_target) {
id_array.push(id_target);
}
}
_ => {
dynamic_entity.insert(
"hasPart".to_string(),
EntityValue::EntityId(Id::IdArray(vec![id_target])),
);
}
}
}
pub fn get_property_value(&self, property: &str) -> Option<(String, EntityValue)> {
match property {
"@type" => Some((
self.id.clone(),
EntityValue::EntityDataType(self.type_.clone()),
)),
"name" => Some((
self.id.clone(),
EntityValue::EntityString(self.name.clone()),
)),
"description" => Some((
self.id.clone(),
EntityValue::EntityString(self.description.clone()),
)),
"license" => Some((
self.id.clone(),
EntityValue::EntityLicense(self.license.clone()),
)),
_ => self
.search_properties_for_value(property)
.map(|value| (self.id.clone(), value)),
}
}
pub fn find_value_details(&self, target_value: &EntityValue) -> Option<(String, String)> {
if let Some(dynamic_entity) = &self.dynamic_entity {
if let Some(key) = search_dynamic_entity_for_key(dynamic_entity, target_value) {
return Some((self.id.clone(), key));
}
}
None
}
pub fn get_linked_ids(&self) -> Vec<Id> {
let mut ids = Vec::new();
match &self.license {
License::Id(id) => ids.push(id.clone()),
License::Description(id) => ids.push(Id::Id(id.to_string())),
};
if let Some(dynamic_entity) = &self.dynamic_entity {
for value in dynamic_entity.values() {
Self::extract_ids_from_entity_value(value, &mut ids);
}
}
ids
}
fn extract_ids_from_entity_value(value: &EntityValue, ids: &mut Vec<Id>) {
match value {
EntityValue::EntityId(id) => {
ids.push(id.clone());
}
EntityValue::EntityVec(vec) => {
for v in vec {
Self::extract_ids_from_entity_value(v, ids);
}
}
EntityValue::EntityObject(map) => {
for v in map.values() {
Self::extract_ids_from_entity_value(v, ids);
}
}
EntityValue::EntityVecObject(vec_map) => {
for map in vec_map {
for v in map.values() {
Self::extract_ids_from_entity_value(v, ids);
}
}
}
EntityValue::NestedDynamicEntity(nested_value) => {
Self::extract_ids_from_entity_value(nested_value, ids);
}
_ => {}
}
}
}
impl DynamicEntityManipulation for RootDataEntity {
fn dynamic_entity(&mut self) -> &mut Option<HashMap<String, EntityValue>> {
&mut self.dynamic_entity
}
fn dynamic_entity_immut(&self) -> &Option<HashMap<String, EntityValue>> {
&self.dynamic_entity
}
}
impl CustomSerialize for RootDataEntity {
fn dynamic_entity(&self) -> Option<&HashMap<String, EntityValue>> {
self.dynamic_entity.as_ref()
}
fn id(&self) -> &String {
&self.id
}
fn type_(&self) -> &DataType {
&self.type_
}
fn name(&self) -> &String {
&self.name
}
fn description(&self) -> &String {
&self.description
}
fn date_published(&self) -> &String {
&self.date_published
}
fn license(&self) -> &License {
&self.license
}
}
impl Serialize for RootDataEntity {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.custom_serialize(serializer)
}
}
pub trait CustomSerialize: Serialize {
fn dynamic_entity(&self) -> Option<&HashMap<String, EntityValue>>;
fn id(&self) -> &String;
fn type_(&self) -> &DataType;
fn name(&self) -> &String;
fn description(&self) -> &String;
fn date_published(&self) -> &String;
fn license(&self) -> &License;
fn custom_serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("@id", self.id())?;
map.serialize_entry("@type", self.type_())?;
map.serialize_entry("name", self.name())?;
map.serialize_entry("description", self.description())?;
map.serialize_entry("datePublished", self.date_published())?;
map.serialize_entry("license", self.license())?;
if let Some(dynamic_entity) = self.dynamic_entity() {
for (k, v) in dynamic_entity {
map.serialize_entry(k, v)?;
}
}
map.end()
}
}
impl<'de> Deserialize<'de> for RootDataEntity {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct RootDataEntityVisitor;
impl<'de> Visitor<'de> for RootDataEntityVisitor {
type Value = RootDataEntity;
fn expecting(&self, formatter: &mut fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a map representing a RootDataEntity")
}
fn visit_map<A>(self, mut map: A) -> Result<RootDataEntity, A::Error>
where
A: MapAccess<'de>,
{
println!("entered map");
let mut id = None;
let mut type_ = None;
let mut name = None;
let mut description = None;
let mut date_published = None;
let mut license = None;
let mut dynamic_entity: HashMap<String, EntityValue> = HashMap::new();
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"@id" => id = Some(map.next_value()?),
"@type" => type_ = Some(map.next_value()?),
"name" => name = Some(map.next_value()?),
"description" => description = Some(map.next_value()?),
"datePublished" => date_published = map.next_value()?,
"license" => license = map.next_value()?,
_ => {
let value: EntityValue = map.next_value()?;
dynamic_entity.insert(key, value);
}
}
}
let id = id.ok_or_else(|| de::Error::missing_field("@id"))?;
let type_ = type_.ok_or_else(|| de::Error::missing_field("@type"))?;
let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
let description =
description.ok_or_else(|| de::Error::missing_field("description"))?;
let date_published =
date_published.ok_or_else(|| de::Error::missing_field("datePublished"))?;
let license = license.ok_or_else(|| de::Error::missing_field("license"))?;
Ok(RootDataEntity {
id,
type_,
name,
description,
date_published,
license,
dynamic_entity: Some(dynamic_entity),
})
}
}
deserializer.deserialize_map(RootDataEntityVisitor)
}
}