use std::hash::Hash;
use std::collections::{HashSet,HashMap};
use ab_glyph::{Font, PxScale};
use crate::to_image::drawable::leaf::broadcast::*;
use crate::to_image::drawable::leaf::info::*;
impl<LifelineIdentifier : Eq + Hash + Copy + Clone> DrawableBroadcastLeafPattern<LifelineIdentifier> {
pub fn get_intermediate_information(
&self,
scale: impl Into<PxScale> + Copy,
font: &impl Font,
all_lifelines_in_diagram : &[LifelineIdentifier],
y_margin_between_seq_operands : f32,
x_margin_between_items : f32,
y_margin_between_items : f32,
) -> BroadcastLeafPatternIntermediateInformation<LifelineIdentifier> {
let minimum_horizontal_space_for_involved_lifeliens = LifelineRequiredHorizontalSpaceInDiagram::new(
2.5*x_margin_between_items,
2.5*x_margin_between_items
);
let mut input_gate_width = 0.0_f32;
let mut output_gates_max_width = 0.0_f32;
let mut involved_lifelines : HashSet<LifelineIdentifier> = HashSet::new();
let mut lifelines_horizontal_requirements : HashMap<LifelineIdentifier, LifelineRequiredHorizontalSpaceInDiagram> = HashMap::new();
let (msg_txt_width, msg_txt_height, _) = self.message.paragraph_size(scale, font);
let mut y_space_top_to_midline = msg_txt_height + y_margin_between_items;
let mut y_space_midline_to_bottom = y_margin_between_items;
let mut required_space_under_emission : Option<(LifelineIdentifier, f32)> = None;
let message_drawing_location : MessageDrawingLocation<LifelineIdentifier>;
let mut message_drawing_location_lf_horizontal_reqs_if_emission : Option<LifelineRequiredHorizontalSpaceInDiagram> = None;
match &self.origin {
DrawableBroadcastLeafPatternOrigin::Empty => {
let leftmost_lf_id = *self.lifeline_targets.keys()
.min_by(|l1,l2|
{
let l1_idx = all_lifelines_in_diagram.iter().position(|l| l == *l1).unwrap();
let l2_idx = all_lifelines_in_diagram.iter().position(|l| l == *l2).unwrap();
l1_idx.cmp(&l2_idx)
}
)
.unwrap();
message_drawing_location = MessageDrawingLocation::new(leftmost_lf_id,true);
},
DrawableBroadcastLeafPatternOrigin::InputOutsideGate(ref gate_parag) => {
let leftmost_lf_id = *self.lifeline_targets.keys()
.min_by(|l1,l2|
{
let l1_idx = all_lifelines_in_diagram.iter().position(|l| l == *l1).unwrap();
let l2_idx = all_lifelines_in_diagram.iter().position(|l| l == *l2).unwrap();
l1_idx.cmp(&l2_idx)
}
)
.unwrap();
message_drawing_location = MessageDrawingLocation::new(leftmost_lf_id,true);
let (gate_width, gate_height, _) = gate_parag.paragraph_size(scale, font);
input_gate_width = gate_width;
y_space_top_to_midline = f32::max(y_space_top_to_midline, gate_height/2.0);
y_space_midline_to_bottom = f32::max(y_space_midline_to_bottom, gate_height/2.0);
},
DrawableBroadcastLeafPatternOrigin::Lifeline(ref orig_lf,ref orig_act) => {
let (pre_w,pre_h,post_w,post_h) = orig_act.get_size_around_midline(scale, font);
let half_max_act_width = (f32::max(pre_w,post_w) + x_margin_between_items) /2.0;
required_space_under_emission = Some((*orig_lf,f32::max(post_h,2.0*y_margin_between_items)));
y_space_top_to_midline = f32::max(y_space_top_to_midline, pre_h);
y_space_midline_to_bottom = f32::max(y_space_midline_to_bottom, post_h);
let draw_message_on_left =
(!self.lifeline_targets.is_empty())
&&
self.lifeline_targets.iter()
.all(
|(tar_lf,_)| {
let orig_lf_idx = all_lifelines_in_diagram.iter().position(|l| l == orig_lf).unwrap();
let tar_lf_idx = all_lifelines_in_diagram.iter().position(|l| l == tar_lf).unwrap();
tar_lf_idx <= orig_lf_idx
}
)
&&
self.output_outside_gates_targets.is_empty();
message_drawing_location = MessageDrawingLocation::new(*orig_lf, draw_message_on_left);
message_drawing_location_lf_horizontal_reqs_if_emission = Some(
LifelineRequiredHorizontalSpaceInDiagram::new(half_max_act_width, half_max_act_width)
);
let mut reqs = LifelineRequiredHorizontalSpaceInDiagram::new(half_max_act_width, half_max_act_width);
reqs.update_to_max(minimum_horizontal_space_for_involved_lifeliens.clone());
lifelines_horizontal_requirements.insert(*orig_lf, reqs);
involved_lifelines.insert(*orig_lf);
}
}
for (tar_lf, tar_act) in &self.lifeline_targets {
let (pre_w,pre_h,post_w,post_h) = tar_act.get_size_around_midline(scale, font);
let half_max_act_width = (f32::max(pre_w,post_w) + x_margin_between_items) /2.0;
let mut new_reqs = LifelineRequiredHorizontalSpaceInDiagram::new(half_max_act_width, half_max_act_width);
let mut default_upd_y_space_top_to_midline = pre_h;
let mut default_upd_y_space_midline_to_bottom = post_h;
if let Some((orig_lf,req_space_under_emission)) = &required_space_under_emission {
if orig_lf == tar_lf {
default_upd_y_space_top_to_midline = 0.0;
default_upd_y_space_midline_to_bottom = req_space_under_emission + y_margin_between_seq_operands + pre_h + post_h + y_margin_between_items;
new_reqs.update_to_max(lifelines_horizontal_requirements.remove(orig_lf).unwrap());
}
}
y_space_top_to_midline = f32::max(y_space_top_to_midline, default_upd_y_space_top_to_midline);
y_space_midline_to_bottom = f32::max(y_space_midline_to_bottom, default_upd_y_space_midline_to_bottom);
new_reqs.update_to_max(minimum_horizontal_space_for_involved_lifeliens.clone());
lifelines_horizontal_requirements.insert(*tar_lf, new_reqs);
involved_lifelines.insert(*tar_lf);
}
let precise_message_drawing_location_x_shift_wrt_anchor_lifeline : f32;
{
let msg_anchor_lf = message_drawing_location.anchor_lifeline;
let msg_anchor_lf_idx = all_lifelines_in_diagram.iter().position(|l| *l == msg_anchor_lf).unwrap();
let mut msg_anchor_lf_previous_horizontal_reqs = if let Some(x) = message_drawing_location_lf_horizontal_reqs_if_emission {
x
} else {
lifelines_horizontal_requirements.get(&msg_anchor_lf).unwrap().clone()
};
if message_drawing_location.draw_message_on_left {
precise_message_drawing_location_x_shift_wrt_anchor_lifeline = 0.0 - (msg_anchor_lf_previous_horizontal_reqs.on_the_left + msg_txt_width/2.0 + x_margin_between_items);
if msg_anchor_lf_idx > 0 {
let left_neighbor_lf = all_lifelines_in_diagram.get(msg_anchor_lf_idx - 1).unwrap();
let mut left_neighbor_req = if let Some(x) = lifelines_horizontal_requirements.remove(left_neighbor_lf) {
x
} else {
LifelineRequiredHorizontalSpaceInDiagram::new_empty()
};
msg_anchor_lf_previous_horizontal_reqs.on_the_left += x_margin_between_items + msg_txt_width/2.0;
lifelines_horizontal_requirements.get_mut(&msg_anchor_lf).unwrap().update_to_max(
msg_anchor_lf_previous_horizontal_reqs
);
left_neighbor_req.on_the_right += x_margin_between_items + msg_txt_width/2.0;
lifelines_horizontal_requirements.insert(*left_neighbor_lf, left_neighbor_req);
} else {
msg_anchor_lf_previous_horizontal_reqs.on_the_left += x_margin_between_items + msg_txt_width;
lifelines_horizontal_requirements.get_mut(&msg_anchor_lf).unwrap().update_to_max(
msg_anchor_lf_previous_horizontal_reqs
);
}
} else {
precise_message_drawing_location_x_shift_wrt_anchor_lifeline = msg_anchor_lf_previous_horizontal_reqs.on_the_right + msg_txt_width/2.0 + x_margin_between_items;
if msg_anchor_lf_idx < (all_lifelines_in_diagram.len() - 1) {
let right_neighbor_lf = all_lifelines_in_diagram.get(msg_anchor_lf_idx + 1).unwrap();
let mut right_neighbor_req = if let Some(x) = lifelines_horizontal_requirements.remove(right_neighbor_lf) {
x
} else {
LifelineRequiredHorizontalSpaceInDiagram::new_empty()
};
msg_anchor_lf_previous_horizontal_reqs.on_the_right += x_margin_between_items + msg_txt_width/2.0;
lifelines_horizontal_requirements.get_mut(&msg_anchor_lf).unwrap().update_to_max(
msg_anchor_lf_previous_horizontal_reqs
);
right_neighbor_req.on_the_left += x_margin_between_items + msg_txt_width/2.0;
lifelines_horizontal_requirements.insert(*right_neighbor_lf, right_neighbor_req);
} else {
msg_anchor_lf_previous_horizontal_reqs.on_the_right += x_margin_between_items + msg_txt_width;
lifelines_horizontal_requirements.get_mut(&msg_anchor_lf).unwrap().update_to_max(
msg_anchor_lf_previous_horizontal_reqs
);
}
}
}
let y_shift_above_midline_for_output_gates = if !self.output_outside_gates_targets.is_empty() {
let mut stacked_output_gates_heights = y_margin_between_items;
for target_output_gate in &self.output_outside_gates_targets {
let (gate_width, gate_height, _) = target_output_gate.paragraph_size(scale, font);
output_gates_max_width = f32::max(output_gates_max_width, gate_width);
stacked_output_gates_heights += gate_height + y_margin_between_items;
}
let half_stacked_output_gates_heights = stacked_output_gates_heights/2.0;
y_space_top_to_midline = f32::max(y_space_top_to_midline, half_stacked_output_gates_heights);
y_space_midline_to_bottom = f32::max(y_space_midline_to_bottom, half_stacked_output_gates_heights);
half_stacked_output_gates_heights
} else {
0.0
};
let y_space_top_to_bottom = y_space_top_to_midline + y_space_midline_to_bottom;
BroadcastLeafPatternIntermediateInformation::new(
y_space_top_to_bottom,
y_space_top_to_midline,
(message_drawing_location,precise_message_drawing_location_x_shift_wrt_anchor_lifeline),
involved_lifelines,
lifelines_horizontal_requirements,
required_space_under_emission,
input_gate_width,
output_gates_max_width,
y_shift_above_midline_for_output_gates
)
}
}