use crate::{
BusinessProcessModelAndNotation,
element::BPMNElementTrait,
elements::task::task_consumed_tokens,
marking::{BPMNRootMarking, BPMNSubMarking, Token},
parser::parser_state::GlobalIndex,
semantics::TransitionIndex,
traits::{
objectable::{BPMNObject, EMPTY_FLOWS},
processable::Processable,
transitionable::{
Transitionable, enabledness_xor_join_only, execute_transition_parallel_split,
execute_transition_xor_join_consume, number_of_transitions_xor_join_only,
transition_2_consumed_tokens_message, transition_2_consumed_tokens_xor_join,
transition_2_produced_tokens_concurrent_split,
},
},
};
use anyhow::{Result, anyhow};
use bitvec::{bitvec, vec::BitVec};
use ebi_activity_key::Activity;
use ebi_arithmetic::{Fraction, One};
#[derive(Debug, Clone)]
pub struct BPMNReceiveTask {
pub(crate) global_index: GlobalIndex,
pub(crate) id: String,
pub(crate) local_index: usize,
pub activity: Activity,
pub(crate) incoming_sequence_flows: Vec<usize>,
pub(crate) outgoing_sequence_flows: Vec<usize>,
pub(crate) incoming_message_flow: Option<usize>,
}
impl BPMNElementTrait for BPMNReceiveTask {
fn add_incoming_sequence_flow(&mut self, flow_index: usize) -> Result<()> {
self.incoming_sequence_flows.push(flow_index);
Ok(())
}
fn add_outgoing_sequence_flow(&mut self, flow_index: usize) -> Result<()> {
self.outgoing_sequence_flows.push(flow_index);
Ok(())
}
fn add_incoming_message_flow(&mut self, flow_index: usize) -> Result<()> {
if self.incoming_message_flow.is_some() {
return Err(anyhow!(
"Cannot add a second incoming message flow to a receive task."
));
}
self.incoming_message_flow = Some(flow_index);
Ok(())
}
fn add_outgoing_message_flow(&mut self, _flow_index: usize) -> Result<()> {
Err(anyhow!(
"Cannot add an outgoing message flow to a receive task."
))
}
fn verify_structural_correctness(
&self,
_parent: &dyn Processable,
_bpmn: &BusinessProcessModelAndNotation,
) -> Result<()> {
Ok(())
}
}
impl BPMNObject for BPMNReceiveTask {
fn local_index(&self) -> usize {
self.local_index
}
fn global_index(&self) -> GlobalIndex {
self.global_index
}
fn activity(&self) -> Option<Activity> {
Some(self.activity)
}
fn id(&self) -> &str {
&self.id
}
fn is_unconstrained_start_event(
&self,
_bpmn: &BusinessProcessModelAndNotation,
) -> Result<bool> {
Ok(false)
}
fn is_end_event(&self) -> bool {
false
}
fn incoming_sequence_flows(&self) -> &[usize] {
&self.incoming_sequence_flows
}
fn outgoing_sequence_flows(&self) -> &[usize] {
&self.outgoing_sequence_flows
}
fn incoming_message_flows(&self) -> &[usize] {
&self.incoming_message_flow.as_slice()
}
fn outgoing_message_flows(&self) -> &[usize] {
&EMPTY_FLOWS
}
fn can_start_process_instance(&self, bpmn: &BusinessProcessModelAndNotation) -> Result<bool> {
if let Some(message_flow_index) = self.incoming_message_flow {
let source = bpmn.message_flow_index_2_source(message_flow_index)?;
if source.is_collapsed_pool() {
Ok(true)
} else {
Ok(false)
}
} else {
Ok(true)
}
}
fn outgoing_message_flows_always_have_tokens(&self) -> bool {
false
}
fn outgoing_messages_cannot_be_removed(&self) -> bool {
false
}
fn incoming_messages_are_ignored(&self) -> bool {
false
}
fn can_have_incoming_sequence_flows(&self) -> bool {
true
}
fn can_have_outgoing_sequence_flows(&self) -> bool {
false
}
}
impl Transitionable for BPMNReceiveTask {
fn number_of_transitions(&self, _marking: &BPMNSubMarking) -> usize {
number_of_transitions_xor_join_only!(self)
}
fn enabled_transitions(
&self,
root_marking: &BPMNRootMarking,
sub_marking: &BPMNSubMarking,
_parent: &dyn Processable,
bpmn: &BusinessProcessModelAndNotation,
) -> Result<BitVec> {
if let Some(message_flow_index) = self.incoming_message_flow {
let source = bpmn.message_flow_index_2_source(message_flow_index)?;
if !source.outgoing_message_flows_always_have_tokens() {
if root_marking.message_flow_2_tokens[message_flow_index] == 0 {
return Ok(bitvec![0;self.number_of_transitions(sub_marking)]);
}
} else {
}
} else {
}
Ok(enabledness_xor_join_only!(self, sub_marking))
}
fn execute_transition(
&self,
transition_index: TransitionIndex,
root_marking: &mut BPMNRootMarking,
sub_marking: &mut BPMNSubMarking,
parent: &dyn Processable,
bpmn: &BusinessProcessModelAndNotation,
) -> Result<()> {
if let Some(sequence_flow_index) = self.incoming_sequence_flows.iter().next() {
let sequence_flow = &parent.sequence_flows_non_recursive()[*sequence_flow_index];
let source = &parent.elements_non_recursive()[sequence_flow.source_local_index];
if source.is_event_based_gateway() {
for outgoing_sequence_flow in source.outgoing_sequence_flows() {
sub_marking.sequence_flow_2_tokens[*outgoing_sequence_flow] -= 1;
}
} else {
execute_transition_xor_join_consume!(self, sub_marking, transition_index);
}
} else {
execute_transition_xor_join_consume!(self, sub_marking, transition_index);
}
{
if let Some(message_flow_index) = self.incoming_message_flow {
let source = bpmn.message_flow_index_2_source(message_flow_index)?;
if !source.outgoing_message_flows_always_have_tokens() {
if !source.outgoing_messages_cannot_be_removed() {
root_marking.message_flow_2_tokens[message_flow_index] -= 1;
}
} else {
}
} else {
}
}
execute_transition_parallel_split!(self, sub_marking);
Ok(())
}
fn transition_activity(
&self,
_transition_index: TransitionIndex,
_marking: &BPMNSubMarking,
) -> Option<Activity> {
Some(self.activity)
}
fn transition_debug(
&self,
transition_index: TransitionIndex,
_marking: &BPMNSubMarking,
bpmn: &BusinessProcessModelAndNotation,
) -> Option<String> {
Some(format!(
"task `{}`; internal transition {}; label `{}`",
self.id,
transition_index,
bpmn.activity_key.deprocess_activity(&self.activity)
))
}
fn transition_probabilistic_penalty(
&self,
_transition_index: TransitionIndex,
_marking: &BPMNSubMarking,
_parent: &dyn Processable,
) -> Option<Fraction> {
Some(Fraction::one())
}
fn transition_2_consumed_tokens<'a>(
&'a self,
transition_index: TransitionIndex,
_marking: &BPMNRootMarking,
_sub_marking: &BPMNSubMarking,
parent: &'a dyn Processable,
bpmn: &BusinessProcessModelAndNotation,
) -> Result<Vec<Token>> {
let mut result = task_consumed_tokens!(self, transition_index, parent);
result.append(&mut transition_2_consumed_tokens_message!(self, bpmn));
Ok(result)
}
fn transition_2_produced_tokens(
&self,
_transition_index: TransitionIndex,
_marking: &BPMNRootMarking,
_sub_marking: &BPMNSubMarking,
parent: &dyn Processable,
_bpmn: &BusinessProcessModelAndNotation,
) -> Result<Vec<Token>> {
Ok(transition_2_produced_tokens_concurrent_split!(self, parent))
}
}