use ifc_model::{EntityId, Model, Transaction, Value};
use super::authoring::{optional_text, require_name};
use super::owned::{stage_ifc4, stage_owned, Rooted};
use super::predefined::{invalid, require_guid, token};
use crate::error::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> {
super::root_authoring::attach_type_record(tx, model, global_id, objects, relating_type, None)
}
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> {
stage_ifc4(
tx,
set_template(global_id, name, applicable_entity, templates)?,
)
}
pub fn add_property_set_template_with_owner_history(
tx: &mut Transaction,
model: &Model,
global_id: &str,
name: &str,
applicable_entity: Option<&str>,
templates: &[EntityId],
owner_history: EntityId,
) -> PropertyResult<EntityId> {
let rooted = set_template(global_id, name, applicable_entity, templates)?;
stage_owned(tx, model, rooted, owner_history)
}
fn set_template<'a>(
global_id: &'a str,
name: &'a str,
applicable_entity: Option<&str>,
templates: &[EntityId],
) -> PropertyResult<Rooted<'a>> {
const ENTITY: &str = "IFCPROPERTYSETTEMPLATE";
require_guid(ENTITY, global_id)?;
require_name(ENTITY, name)?;
if templates.is_empty() {
return Err(invalid(ENTITY, "HasPropertyTemplates", "empty"));
}
let values = vec![
("ApplicableEntity", optional_text(applicable_entity)),
(
"HasPropertyTemplates",
Value::List(templates.iter().copied().map(Value::Ref).collect()),
),
];
Ok(Rooted {
entity: ENTITY,
global_id,
name: Some(name),
description: None,
values,
})
}
pub fn attach_template(
tx: &mut Transaction,
global_id: &str,
property_sets: &[EntityId],
template: EntityId,
) -> PropertyResult<EntityId> {
stage_ifc4(tx, defines_by_template(global_id, property_sets, template)?)
}
pub fn attach_template_with_owner_history(
tx: &mut Transaction,
model: &Model,
global_id: &str,
property_sets: &[EntityId],
template: EntityId,
owner_history: EntityId,
) -> PropertyResult<EntityId> {
let rooted = defines_by_template(global_id, property_sets, template)?;
stage_owned(tx, model, rooted, owner_history)
}
fn defines_by_template<'a>(
global_id: &'a str,
property_sets: &[EntityId],
template: EntityId,
) -> PropertyResult<Rooted<'a>> {
const ENTITY: &str = "IFCRELDEFINESBYTEMPLATE";
require_guid(ENTITY, global_id)?;
if property_sets.is_empty() {
return Err(invalid(ENTITY, "RelatedPropertySets", "empty"));
}
let values = vec![
(
"RelatedPropertySets",
Value::List(property_sets.iter().copied().map(Value::Ref).collect()),
),
("RelatingTemplate", Value::Ref(template)),
];
Ok(Rooted {
entity: ENTITY,
global_id,
name: None,
description: None,
values,
})
}
const COMPLEX_TEMPLATE_TYPE: &[&str] = &["P_COMPLEX", "Q_COMPLEX"];
pub fn add_complex_property_template(
tx: &mut Transaction,
global_id: &str,
name: Option<&str>,
usage: (Option<&str>, Option<&str>),
templates: &[(&str, EntityId)],
) -> PropertyResult<EntityId> {
stage_ifc4(tx, complex_template(global_id, name, usage, templates)?)
}
pub fn add_complex_property_template_with_owner_history(
tx: &mut Transaction,
model: &Model,
global_id: &str,
name: Option<&str>,
usage: (Option<&str>, Option<&str>),
templates: &[(&str, EntityId)],
owner_history: EntityId,
) -> PropertyResult<EntityId> {
let rooted = complex_template(global_id, name, usage, templates)?;
stage_owned(tx, model, rooted, owner_history)
}
fn complex_template<'a>(
global_id: &'a str,
name: Option<&'a str>,
(usage_name, template_type): (Option<&str>, Option<&str>),
templates: &[(&str, EntityId)],
) -> PropertyResult<Rooted<'a>> {
const ENTITY: &str = "IFCCOMPLEXPROPERTYTEMPLATE";
require_guid(ENTITY, global_id)?;
let mut values = vec![("UsageName", optional_text(usage_name))];
if let Some(kind) = template_type {
values.push((
"TemplateType",
token(ENTITY, "TemplateType", kind, COMPLEX_TEMPLATE_TYPE)?,
));
}
if !templates.is_empty() {
for (index, (child, _)) in templates.iter().enumerate() {
if templates[..index].iter().any(|(seen, _)| seen == child) {
return Err(invalid(ENTITY, "HasPropertyTemplates", (*child).to_owned()));
}
}
let children = templates.iter().map(|(_, id)| Value::Ref(*id));
values.push(("HasPropertyTemplates", Value::List(children.collect())));
}
Ok(Rooted {
entity: ENTITY,
global_id,
name,
description: None,
values,
})
}