use ifc_model::{Entity, EntityId, Transaction, Value};
use crate::{AuthorError, AuthorResult};
#[derive(Debug, Clone, Copy, Default)]
pub struct PersonDraft<'a> {
pub identification: Option<&'a str>,
pub family_name: Option<&'a str>,
pub given_name: Option<&'a str>,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct OrganizationDraft<'a> {
pub identification: Option<&'a str>,
pub name: &'a str,
pub description: Option<&'a str>,
}
#[derive(Debug, Clone, Copy)]
pub struct ApplicationDraft<'a> {
pub developer: EntityId,
pub version: &'a str,
pub full_name: &'a str,
pub identifier: &'a str,
}
pub fn add_person(tx: &mut Transaction, draft: PersonDraft<'_>) -> AuthorResult<EntityId> {
if draft.identification.is_none() && draft.family_name.is_none() && draft.given_name.is_none() {
return Err(AuthorError::MissingRequired {
entity: "IFCPERSON".to_owned(),
attribute: "Identification|FamilyName|GivenName".to_owned(),
});
}
Ok(tx.create(Entity::new(
"IFCPERSON",
vec![
opt_text(draft.identification),
opt_text(draft.family_name),
opt_text(draft.given_name),
Value::Null,
Value::Null,
Value::Null,
Value::Null,
Value::Null,
],
)))
}
pub fn add_organization(
tx: &mut Transaction,
draft: OrganizationDraft<'_>,
) -> AuthorResult<EntityId> {
if draft.name.trim().is_empty() {
return Err(AuthorError::MissingRequired {
entity: "IFCORGANIZATION".to_owned(),
attribute: "Name".to_owned(),
});
}
Ok(tx.create(Entity::new(
"IFCORGANIZATION",
vec![
opt_text(draft.identification),
Value::Text(draft.name.into()),
opt_text(draft.description),
Value::Null,
Value::Null,
],
)))
}
pub fn add_person_and_organization(
tx: &mut Transaction,
person: EntityId,
organization: EntityId,
) -> EntityId {
tx.create(Entity::new(
"IFCPERSONANDORGANIZATION",
vec![Value::Ref(person), Value::Ref(organization), Value::Null],
))
}
pub fn add_application(
tx: &mut Transaction,
draft: ApplicationDraft<'_>,
) -> AuthorResult<EntityId> {
for (attribute, value) in [
("Version", draft.version),
("ApplicationFullName", draft.full_name),
("ApplicationIdentifier", draft.identifier),
] {
if value.trim().is_empty() {
return Err(AuthorError::MissingRequired {
entity: "IFCAPPLICATION".to_owned(),
attribute: attribute.to_owned(),
});
}
}
Ok(tx.create(Entity::new(
"IFCAPPLICATION",
vec![
Value::Ref(draft.developer),
Value::Text(draft.version.into()),
Value::Text(draft.full_name.into()),
Value::Text(draft.identifier.into()),
],
)))
}
#[derive(Debug, Clone, Copy)]
pub struct OwnerHistoryDraft<'a> {
pub owning_user: EntityId,
pub owning_application: EntityId,
pub change_action: Option<&'a str>,
pub creation_date: i64,
pub last_modified_date: Option<i64>,
}
const CHANGE_ACTIONS: &[&str] = &["NOCHANGE", "MODIFIED", "ADDED", "DELETED", "NOTDEFINED"];
pub fn add_owner_history(
tx: &mut Transaction,
draft: OwnerHistoryDraft<'_>,
) -> AuthorResult<EntityId> {
if let Some(action) = draft.change_action {
if !CHANGE_ACTIONS
.iter()
.any(|known| known.eq_ignore_ascii_case(action))
{
return Err(AuthorError::TypeMismatch {
entity: "IFCOWNERHISTORY".to_owned(),
attribute: "ChangeAction".to_owned(),
expected: "an IfcChangeActionEnum constant".to_owned(),
found: action.to_owned(),
});
}
}
if let Some(modified) = draft.last_modified_date {
if modified < draft.creation_date {
return Err(AuthorError::TypeMismatch {
entity: "IFCOWNERHISTORY".to_owned(),
attribute: "LastModifiedDate".to_owned(),
expected: "a timestamp at or after CreationDate".to_owned(),
found: modified.to_string(),
});
}
}
Ok(tx.create(Entity::new(
"IFCOWNERHISTORY",
vec![
Value::Ref(draft.owning_user),
Value::Ref(draft.owning_application),
Value::Null,
draft
.change_action
.map_or(Value::Null, |a| Value::Enum(a.into())),
draft.last_modified_date.map_or(Value::Null, Value::Integer),
Value::Null,
Value::Null,
Value::Integer(draft.creation_date),
],
)))
}
fn opt_text(value: Option<&str>) -> Value {
value.map_or(Value::Null, |v| Value::Text(v.into()))
}