use ifc_model::guid::Guid;
use ifc_model::{Entity, EntityId, Model, Transaction, Value};
use ifc_schema::ifc4;
use super::authoring::{optional_text, require_name};
use crate::error::{PropertyError, PropertyResult};
pub mod defines_by_type_slot {
pub const GLOBAL_ID: usize = 0;
pub const RELATED_OBJECTS: usize = 4;
pub const RELATING_TYPE: usize = 5;
}
pub fn attach_type(
tx: &mut Transaction,
model: &Model,
global_id: &str,
objects: &[EntityId],
relating_type: EntityId,
) -> PropertyResult<EntityId> {
if Guid::parse(global_id).is_none() {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCRELDEFINESBYTYPE",
attribute: "GlobalId",
value: global_id.to_owned(),
});
}
if objects.is_empty() {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCRELDEFINESBYTYPE",
attribute: "RelatedObjects",
value: "empty".to_owned(),
});
}
let schema = ifc4();
let is_type = |id: EntityId| {
model
.get(id)
.is_some_and(|entity| schema.is_a(&entity.type_name, "IFCTYPEOBJECT"))
};
if !is_type(relating_type) {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCRELDEFINESBYTYPE",
attribute: "RelatingType",
value: "not an IfcTypeObject".to_owned(),
});
}
for object in objects {
if is_type(*object) {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCRELDEFINESBYTYPE",
attribute: "RelatedObjects",
value: "a type object cannot be an occurrence".to_owned(),
});
}
}
let mut attributes = vec![Value::Null; defines_by_type_slot::RELATING_TYPE + 1];
attributes[defines_by_type_slot::GLOBAL_ID] = Value::Text(global_id.into());
attributes[defines_by_type_slot::RELATED_OBJECTS] =
Value::List(objects.iter().copied().map(Value::Ref).collect());
attributes[defines_by_type_slot::RELATING_TYPE] = Value::Ref(relating_type);
Ok(tx.create(Entity::new("IFCRELDEFINESBYTYPE", attributes)))
}
pub mod pset_template_slot {
pub const GLOBAL_ID: usize = 0;
pub const NAME: usize = 2;
pub const DESCRIPTION: usize = 3;
pub const TEMPLATE_TYPE: usize = 4;
pub const APPLICABLE_ENTITY: usize = 5;
pub const HAS_PROPERTY_TEMPLATES: usize = 6;
}
pub mod defines_by_template_slot {
pub const GLOBAL_ID: usize = 0;
pub const RELATED_PROPERTY_SETS: usize = 4;
pub const RELATING_TEMPLATE: usize = 5;
}
pub fn add_property_set_template(
tx: &mut Transaction,
global_id: &str,
name: &str,
applicable_entity: Option<&str>,
templates: &[EntityId],
) -> PropertyResult<EntityId> {
if Guid::parse(global_id).is_none() {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCPROPERTYSETTEMPLATE",
attribute: "GlobalId",
value: global_id.to_owned(),
});
}
require_name("IFCPROPERTYSETTEMPLATE", name)?;
if templates.is_empty() {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCPROPERTYSETTEMPLATE",
attribute: "HasPropertyTemplates",
value: "empty".to_owned(),
});
}
let mut attributes = vec![Value::Null; pset_template_slot::HAS_PROPERTY_TEMPLATES + 1];
attributes[pset_template_slot::GLOBAL_ID] = Value::Text(global_id.into());
attributes[pset_template_slot::NAME] = Value::Text(name.into());
attributes[pset_template_slot::APPLICABLE_ENTITY] = optional_text(applicable_entity);
attributes[pset_template_slot::HAS_PROPERTY_TEMPLATES] =
Value::List(templates.iter().copied().map(Value::Ref).collect());
Ok(tx.create(Entity::new("IFCPROPERTYSETTEMPLATE", attributes)))
}
pub fn attach_template(
tx: &mut Transaction,
global_id: &str,
property_sets: &[EntityId],
template: EntityId,
) -> PropertyResult<EntityId> {
if Guid::parse(global_id).is_none() {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCRELDEFINESBYTEMPLATE",
attribute: "GlobalId",
value: global_id.to_owned(),
});
}
if property_sets.is_empty() {
return Err(PropertyError::AuthoringInvalid {
entity: "IFCRELDEFINESBYTEMPLATE",
attribute: "RelatedPropertySets",
value: "empty".to_owned(),
});
}
let mut attributes = vec![Value::Null; defines_by_template_slot::RELATING_TEMPLATE + 1];
attributes[defines_by_template_slot::GLOBAL_ID] = Value::Text(global_id.into());
attributes[defines_by_template_slot::RELATED_PROPERTY_SETS] =
Value::List(property_sets.iter().copied().map(Value::Ref).collect());
attributes[defines_by_template_slot::RELATING_TEMPLATE] = Value::Ref(template);
Ok(tx.create(Entity::new("IFCRELDEFINESBYTEMPLATE", attributes)))
}