use ifc_model::guid::Guid;
use ifc_model::EntityId;
use super::WorkControlDraft;
use super::{blank, is_user_defined, EventDraft, ScheduleAuthoringResult, TaskDraft};
use crate::error::ScheduleAuthoringError;
use crate::schedule::WorkControlKind;
fn invalid(
entity: &'static str,
attribute: &'static str,
expected: &'static str,
) -> ScheduleAuthoringError {
ScheduleAuthoringError::InvalidValue {
entity,
attribute,
expected,
}
}
pub(super) fn guid(entity: &'static str, global_id: &str) -> ScheduleAuthoringResult<()> {
if Guid::parse(global_id).is_none() {
return Err(invalid(entity, "GlobalId", "an IFC compressed GUID"));
}
Ok(())
}
pub(super) fn task(draft: &TaskDraft<'_>) -> ScheduleAuthoringResult<()> {
guid("IFCTASK", draft.global_id)?;
if let Some(priority) = draft.priority {
if !(0..=100).contains(&priority) {
return Err(invalid("IFCTASK", "Priority", "an integer in 0..=100"));
}
}
Ok(())
}
pub(super) fn sequence(
global_id: &str,
predecessor: EntityId,
successor: EntityId,
) -> ScheduleAuthoringResult<()> {
guid("IFCRELSEQUENCE", global_id)?;
if predecessor == successor {
return Err(invalid(
"IFCRELSEQUENCE",
"RelatedProcess",
"a successor distinct from the predecessor",
));
}
Ok(())
}
pub(super) fn work_control(
kind: WorkControlKind,
draft: &WorkControlDraft<'_>,
) -> ScheduleAuthoringResult<&'static str> {
let type_name = match kind {
WorkControlKind::Plan => "IFCWORKPLAN",
WorkControlKind::Schedule => "IFCWORKSCHEDULE",
};
guid(type_name, draft.global_id)?;
for (attribute, value) in [
("CreationDate", draft.creation_date),
("StartTime", draft.start_time),
] {
if value.trim().is_empty() {
return Err(invalid(
type_name,
attribute,
"a non-empty ISO 8601 timestamp",
));
}
}
Ok(type_name)
}
pub(super) fn assignment(global_id: &str, tasks: &[EntityId]) -> ScheduleAuthoringResult<()> {
guid("IFCRELASSIGNSTOCONTROL", global_id)?;
if tasks.is_empty() {
return Err(invalid(
"IFCRELASSIGNSTOCONTROL",
"RelatedObjects",
"at least one assigned object",
));
}
Ok(())
}
pub(super) fn nesting(
global_id: &str,
parent: EntityId,
children: &[EntityId],
) -> ScheduleAuthoringResult<()> {
guid("IFCRELNESTS", global_id)?;
if children.is_empty() {
return Err(invalid(
"IFCRELNESTS",
"RelatedObjects",
"at least one nested object",
));
}
if children.contains(&parent) {
return Err(invalid(
"IFCRELNESTS",
"RelatedObjects",
"children that do not include the parent",
));
}
Ok(())
}
pub(super) fn calendar(
global_id: &str,
working_times: &[EntityId],
exception_times: &[EntityId],
) -> ScheduleAuthoringResult<()> {
guid("IFCWORKCALENDAR", global_id)?;
if working_times.is_empty() && exception_times.is_empty() {
return Err(invalid(
"IFCWORKCALENDAR",
"WorkingTimes",
"at least one working or exception period",
));
}
Ok(())
}
pub(super) fn event(draft: &EventDraft<'_>) -> ScheduleAuthoringResult<()> {
guid("IFCEVENT", draft.global_id)?;
if is_user_defined(draft.predefined_type) && blank(draft.object_type) {
return Err(invalid(
"IFCEVENT",
"ObjectType",
"a label when PredefinedType is USERDEFINED",
));
}
if is_user_defined(draft.trigger_type) && blank(draft.user_defined_trigger_type) {
return Err(invalid(
"IFCEVENT",
"UserDefinedEventTriggerType",
"a label when EventTriggerType is USERDEFINED",
));
}
Ok(())
}