use ifc_model::{EntityId, Model, Transaction, Value};
use super::procedure::{self, ProcedureDraft};
use super::{
checks, optional_enum, optional_text, reference_list, EventDraft, ScheduleAuthoringResult,
TaskDraft, WorkControlDraft,
};
use crate::error::ScheduleAuthoringError;
use crate::release::{bind, Release};
use crate::schedule::WorkControlKind;
use ifc_schema::SchemaVersion;
fn stage(
tx: &mut Transaction,
model: &Model,
release: Release,
entity: &'static str,
values: Vec<(&'static str, Value)>,
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let mut named = vec![("OwnerHistory", Value::Ref(owner_history))];
named.extend(values);
let record = release.record(entity, named)?;
release.require_owner_history(tx, model, entity, owner_history)?;
Ok(tx.create(record))
}
fn refs(ids: &[EntityId]) -> Value {
Value::List(ids.iter().copied().map(Value::Ref).collect())
}
pub fn create_task_with_owner_history(
tx: &mut Transaction,
model: &Model,
draft: TaskDraft<'_>,
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
checks::task(&draft)?;
let values = vec![
("GlobalId", Value::Text(draft.global_id.into())),
("Name", optional_text(draft.name)),
("Description", optional_text(draft.description)),
("Identification", optional_text(draft.identification)),
("LongDescription", optional_text(draft.long_description)),
("Status", optional_text(draft.status)),
("WorkMethod", optional_text(draft.work_method)),
("IsMilestone", Value::Bool(draft.is_milestone)),
(
"Priority",
draft.priority.map_or(Value::Null, Value::Integer),
),
("TaskTime", draft.task_time.map_or(Value::Null, Value::Ref)),
("PredefinedType", optional_enum(draft.predefined_type)),
];
stage(tx, model, release, "IFCTASK", values, owner_history)
}
#[allow(clippy::too_many_arguments)]
pub fn create_sequence_with_owner_history(
tx: &mut Transaction,
model: &Model,
global_id: &str,
predecessor: EntityId,
successor: EntityId,
sequence_type: Option<&str>,
time_lag: Option<EntityId>,
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
checks::sequence(global_id, predecessor, successor)?;
let values = vec![
("GlobalId", Value::Text(global_id.into())),
("RelatingProcess", Value::Ref(predecessor)),
("RelatedProcess", Value::Ref(successor)),
("TimeLag", time_lag.map_or(Value::Null, Value::Ref)),
("SequenceType", optional_enum(sequence_type)),
];
stage(tx, model, release, "IFCRELSEQUENCE", values, owner_history)
}
pub fn create_work_control_with_owner_history(
tx: &mut Transaction,
model: &Model,
kind: WorkControlKind,
draft: WorkControlDraft<'_>,
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
let type_name = checks::work_control(kind, &draft)?;
let values = vec![
("GlobalId", Value::Text(draft.global_id.into())),
("Name", optional_text(draft.name)),
("Description", optional_text(draft.description)),
("Identification", optional_text(draft.identification)),
("CreationDate", Value::Text(draft.creation_date.into())),
("Purpose", optional_text(draft.purpose)),
("Duration", optional_text(draft.duration)),
("TotalFloat", optional_text(draft.total_float)),
("StartTime", Value::Text(draft.start_time.into())),
("FinishTime", optional_text(draft.finish_time)),
("PredefinedType", optional_enum(draft.predefined_type)),
];
stage(tx, model, release, type_name, values, owner_history)
}
pub fn assign_tasks_to_control_with_owner_history(
tx: &mut Transaction,
model: &Model,
global_id: &str,
control: EntityId,
tasks: &[EntityId],
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
checks::assignment(global_id, tasks)?;
let values = vec![
("GlobalId", Value::Text(global_id.into())),
("RelatedObjects", refs(tasks)),
("RelatingControl", Value::Ref(control)),
];
stage(
tx,
model,
release,
"IFCRELASSIGNSTOCONTROL",
values,
owner_history,
)
}
pub fn nest_tasks_with_owner_history(
tx: &mut Transaction,
model: &Model,
global_id: &str,
parent: EntityId,
children: &[EntityId],
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
checks::nesting(global_id, parent, children)?;
let values = vec![
("GlobalId", Value::Text(global_id.into())),
("RelatingObject", Value::Ref(parent)),
("RelatedObjects", refs(children)),
];
stage(tx, model, release, "IFCRELNESTS", values, owner_history)
}
#[allow(clippy::too_many_arguments)]
pub fn create_work_calendar_with_owner_history(
tx: &mut Transaction,
model: &Model,
global_id: &str,
name: Option<&str>,
working_times: &[EntityId],
exception_times: &[EntityId],
predefined_type: Option<&str>,
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
checks::calendar(global_id, working_times, exception_times)?;
let values = vec![
("GlobalId", Value::Text(global_id.into())),
("Name", optional_text(name)),
("WorkingTimes", reference_list(working_times)),
("ExceptionTimes", reference_list(exception_times)),
("PredefinedType", optional_enum(predefined_type)),
];
stage(tx, model, release, "IFCWORKCALENDAR", values, owner_history)
}
pub fn create_event_with_owner_history(
tx: &mut Transaction,
model: &Model,
draft: EventDraft<'_>,
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
checks::event(&draft)?;
let values = vec![
("GlobalId", Value::Text(draft.global_id.into())),
("Name", optional_text(draft.name)),
("ObjectType", optional_text(draft.object_type)),
("Identification", optional_text(draft.identification)),
("LongDescription", optional_text(draft.long_description)),
("PredefinedType", optional_enum(draft.predefined_type)),
("EventTriggerType", optional_enum(draft.trigger_type)),
(
"UserDefinedEventTriggerType",
optional_text(draft.user_defined_trigger_type),
),
(
"EventOccurenceTime",
draft.occurence_time.map_or(Value::Null, Value::Ref),
),
];
stage(tx, model, release, "IFCEVENT", values, owner_history)
}
pub fn create_procedure_with_owner_history(
tx: &mut Transaction,
model: &Model,
draft: ProcedureDraft<'_>,
owner_history: EntityId,
) -> ScheduleAuthoringResult<EntityId> {
let release = bind(model)?;
procedure::check(&draft)?;
if release.version() == SchemaVersion::Ifc2x3 && draft.predefined_type == Some("USERDEFINED") {
return Err(ScheduleAuthoringError::InvalidValue {
entity: procedure::ENTITY,
attribute: "PredefinedType",
expected: "a token other than USERDEFINED: IFC2X3 WR4 needs a \
UserDefinedProcedureType this draft cannot carry",
});
}
let values = vec![
("GlobalId", Value::Text(draft.global_id.into())),
("Name", optional_text(draft.name)),
("Description", optional_text(draft.description)),
("ObjectType", optional_text(draft.object_type)),
("Identification", optional_text(draft.identification)),
("LongDescription", optional_text(draft.long_description)),
("PredefinedType", optional_enum(draft.predefined_type)),
];
stage(tx, model, release, procedure::ENTITY, values, owner_history)
}