use ifc_model::{EntityId, Model, Transaction, Value};
use super::draft::{
CostItemDraft, CostItemType, CostScheduleDraft, CostScheduleType, NestingDraft,
ScheduleAssignmentDraft,
};
use super::release::{bind, Release};
use super::validate::{guid, invalid, non_empty_unique, reference_type, validate_nesting};
use super::value::{optional_enum, optional_text, refs};
use super::CostAuthoringResult;
pub fn create_cost_item(
tx: &mut Transaction,
model: &Model,
draft: CostItemDraft<'_>,
) -> CostAuthoringResult<EntityId> {
cost_item(tx, model, draft, None)
}
pub fn create_cost_item_with_owner_history(
tx: &mut Transaction,
model: &Model,
draft: CostItemDraft<'_>,
owner_history: EntityId,
) -> CostAuthoringResult<EntityId> {
cost_item(tx, model, draft, Some(owner_history))
}
fn cost_item(
tx: &mut Transaction,
model: &Model,
draft: CostItemDraft<'_>,
owner_history: Option<EntityId>,
) -> CostAuthoringResult<EntityId> {
const ENTITY: &str = "IFCCOSTITEM";
let release = bind(model)?;
guid(tx, model, ENTITY, draft.global_id)?;
if draft.predefined_type == Some(CostItemType::UserDefined) && draft.object_type.is_none() {
return Err(invalid(
ENTITY,
"ObjectType",
"required for USERDEFINED PredefinedType",
));
}
for target in draft.cost_values {
reference_type(tx, model, ENTITY, "CostValues", *target, "IFCCOSTVALUE")?;
}
let record = release.record(
ENTITY,
vec![
("GlobalId", Value::Text(draft.global_id.into())),
(
"OwnerHistory",
owner_history.map_or(Value::Null, Value::Ref),
),
("Name", optional_text(draft.name)),
("Description", optional_text(draft.description)),
("ObjectType", optional_text(draft.object_type)),
("Identification", optional_text(draft.identification)),
(
"PredefinedType",
optional_enum(draft.predefined_type.map(CostItemType::token)),
),
("CostValues", optional_refs(draft.cost_values)),
],
)?;
stage(tx, model, release, ENTITY, record, owner_history)
}
pub fn create_cost_schedule(
tx: &mut Transaction,
model: &Model,
draft: CostScheduleDraft<'_>,
) -> CostAuthoringResult<EntityId> {
cost_schedule(tx, model, draft, None)
}
pub fn create_cost_schedule_with_owner_history(
tx: &mut Transaction,
model: &Model,
draft: CostScheduleDraft<'_>,
owner_history: EntityId,
) -> CostAuthoringResult<EntityId> {
cost_schedule(tx, model, draft, Some(owner_history))
}
fn cost_schedule(
tx: &mut Transaction,
model: &Model,
draft: CostScheduleDraft<'_>,
owner_history: Option<EntityId>,
) -> CostAuthoringResult<EntityId> {
const ENTITY: &str = "IFCCOSTSCHEDULE";
let release = bind(model)?;
guid(tx, model, ENTITY, draft.global_id)?;
if draft.predefined_type == Some(CostScheduleType::UserDefined) && draft.object_type.is_none() {
return Err(invalid(
ENTITY,
"ObjectType",
"required for USERDEFINED PredefinedType",
));
}
let record = release.record(
ENTITY,
vec![
("GlobalId", Value::Text(draft.global_id.into())),
(
"OwnerHistory",
owner_history.map_or(Value::Null, Value::Ref),
),
("Name", optional_text(draft.name)),
("Description", optional_text(draft.description)),
("ObjectType", optional_text(draft.object_type)),
("Identification", optional_text(draft.identification)),
(
"PredefinedType",
optional_enum(draft.predefined_type.map(CostScheduleType::token)),
),
("Status", optional_text(draft.status)),
("SubmittedOn", optional_text(draft.submitted_on)),
("UpdateDate", optional_text(draft.update_date)),
],
)?;
stage(tx, model, release, ENTITY, record, owner_history)
}
pub fn nest_cost_items(
tx: &mut Transaction,
model: &Model,
draft: NestingDraft<'_>,
) -> CostAuthoringResult<EntityId> {
nesting(tx, model, draft, None)
}
pub fn nest_cost_items_with_owner_history(
tx: &mut Transaction,
model: &Model,
draft: NestingDraft<'_>,
owner_history: EntityId,
) -> CostAuthoringResult<EntityId> {
nesting(tx, model, draft, Some(owner_history))
}
fn nesting(
tx: &mut Transaction,
model: &Model,
draft: NestingDraft<'_>,
owner_history: Option<EntityId>,
) -> CostAuthoringResult<EntityId> {
const ENTITY: &str = "IFCRELNESTS";
let release = bind(model)?;
guid(tx, model, ENTITY, draft.global_id)?;
non_empty_unique(ENTITY, "RelatedObjects", draft.children)?;
reference_type(
tx,
model,
ENTITY,
"RelatingObject",
draft.parent,
"IFCCOSTITEM",
)?;
for child in draft.children {
reference_type(tx, model, ENTITY, "RelatedObjects", *child, "IFCCOSTITEM")?;
}
validate_nesting(tx, model, draft.parent, draft.children)?;
let record = release.record(
ENTITY,
vec![
("GlobalId", Value::Text(draft.global_id.into())),
(
"OwnerHistory",
owner_history.map_or(Value::Null, Value::Ref),
),
("RelatingObject", Value::Ref(draft.parent)),
("RelatedObjects", refs(draft.children)),
],
)?;
stage(tx, model, release, ENTITY, record, owner_history)
}
pub fn assign_schedule_items(
tx: &mut Transaction,
model: &Model,
draft: ScheduleAssignmentDraft<'_>,
) -> CostAuthoringResult<EntityId> {
schedule_assignment(tx, model, draft, None)
}
pub fn assign_schedule_items_with_owner_history(
tx: &mut Transaction,
model: &Model,
draft: ScheduleAssignmentDraft<'_>,
owner_history: EntityId,
) -> CostAuthoringResult<EntityId> {
schedule_assignment(tx, model, draft, Some(owner_history))
}
fn schedule_assignment(
tx: &mut Transaction,
model: &Model,
draft: ScheduleAssignmentDraft<'_>,
owner_history: Option<EntityId>,
) -> CostAuthoringResult<EntityId> {
const ENTITY: &str = "IFCRELASSIGNSTOCONTROL";
let release = bind(model)?;
guid(tx, model, ENTITY, draft.global_id)?;
non_empty_unique(ENTITY, "RelatedObjects", draft.items)?;
reference_type(
tx,
model,
ENTITY,
"RelatingControl",
draft.schedule,
"IFCCOSTSCHEDULE",
)?;
for item in draft.items {
reference_type(tx, model, ENTITY, "RelatedObjects", *item, "IFCCOSTITEM")?;
}
let record = release.record(
ENTITY,
vec![
("GlobalId", Value::Text(draft.global_id.into())),
(
"OwnerHistory",
owner_history.map_or(Value::Null, Value::Ref),
),
("RelatedObjects", refs(draft.items)),
("RelatedObjectsType", Value::Null),
("RelatingControl", Value::Ref(draft.schedule)),
],
)?;
stage(tx, model, release, ENTITY, record, owner_history)
}
fn stage(
tx: &mut Transaction,
model: &Model,
release: Release,
entity: &'static str,
record: ifc_model::Entity,
owner_history: Option<EntityId>,
) -> CostAuthoringResult<EntityId> {
if let Some(owner_history) = owner_history {
release.require_owner_history(tx, model, entity, owner_history)?;
}
Ok(tx.create(record))
}
fn optional_refs(ids: &[EntityId]) -> Value {
if ids.is_empty() {
Value::Null
} else {
refs(ids)
}
}