use crate::analysis::events::{dialogue_info::DialogueInfo, overlap::find_overlapping_event_refs};
use crate::parser::Event;
use alloc::vec::Vec;
use core::cmp::Ordering;
#[must_use]
pub fn find_overlapping_dialogue_events(events: &[DialogueInfo<'_>]) -> Vec<(usize, usize)> {
let event_refs: Vec<&Event> = events
.iter()
.map(super::dialogue_info::DialogueInfo::event)
.collect();
find_overlapping_event_refs(&event_refs).unwrap_or_else(|_| Vec::new())
}
#[must_use]
pub fn count_overlapping_dialogue_events(events: &[DialogueInfo<'_>]) -> usize {
find_overlapping_dialogue_events(events).len()
}
pub fn sort_events_by_time(events: &mut [DialogueInfo<'_>]) {
events.sort_by(|a, b| match a.start_time_cs().cmp(&b.start_time_cs()) {
Ordering::Equal => a.end_time_cs().cmp(&b.end_time_cs()),
other => other,
});
}
#[must_use]
pub fn calculate_total_duration(events: &[DialogueInfo<'_>]) -> Option<u32> {
if events.is_empty() {
return None;
}
let start = events
.iter()
.map(super::dialogue_info::DialogueInfo::start_time_cs)
.min()?;
let end = events
.iter()
.map(super::dialogue_info::DialogueInfo::end_time_cs)
.max()?;
Some(end - start)
}
#[must_use]
pub fn calculate_average_duration(events: &[DialogueInfo<'_>]) -> Option<u32> {
if events.is_empty() {
return None;
}
let total_duration: u32 = events
.iter()
.map(super::dialogue_info::DialogueInfo::duration_cs)
.sum();
Some(total_duration / u32::try_from(events.len()).unwrap_or(u32::MAX))
}
#[must_use]
pub fn find_events_in_range(events: &[DialogueInfo<'_>], start_cs: u32, end_cs: u32) -> Vec<usize> {
events
.iter()
.enumerate()
.filter_map(|(idx, event)| {
if event.overlaps_time_range(start_cs, end_cs) {
Some(idx)
} else {
None
}
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::{ast::Span, Event};
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use alloc::vec;
#[cfg(not(feature = "std"))]
fn create_test_dialogue_info(start: &'static str, end: &'static str) -> DialogueInfo<'static> {
let event = Box::leak(Box::new(Event {
event_type: crate::parser::ast::EventType::Dialogue,
start,
end,
text: "Test",
layer: "0",
style: "Default",
name: "",
margin_l: "0",
margin_r: "0",
margin_v: "0",
margin_t: None,
margin_b: None,
effect: "",
span: Span::new(0, 0, 0, 0),
}));
DialogueInfo::analyze(event).unwrap()
}
#[cfg(feature = "std")]
fn create_test_dialogue_info(start: &'static str, end: &'static str) -> DialogueInfo<'static> {
let event = Box::leak(Box::new(Event {
event_type: crate::parser::ast::EventType::Dialogue,
start,
end,
text: "Test",
layer: "0",
style: "Default",
name: "",
margin_l: "0",
margin_r: "0",
margin_v: "0",
margin_t: None,
margin_b: None,
effect: "",
span: Span::new(0, 0, 0, 0),
}));
DialogueInfo::analyze(event).unwrap()
}
#[test]
fn empty_events_no_overlaps() {
let events = vec![];
assert_eq!(find_overlapping_dialogue_events(&events).len(), 0);
assert_eq!(count_overlapping_dialogue_events(&events), 0);
}
#[test]
fn calculate_duration_empty() {
let events = vec![];
assert_eq!(calculate_total_duration(&events), None);
assert_eq!(calculate_average_duration(&events), None);
}
#[test]
fn calculate_duration_single_event() {
let events = vec![create_test_dialogue_info("0:00:00.00", "0:00:05.00")];
assert_eq!(calculate_total_duration(&events), Some(500)); assert_eq!(calculate_average_duration(&events), Some(500));
}
#[test]
fn calculate_duration_multiple_events() {
let events = vec![
create_test_dialogue_info("0:00:00.00", "0:00:05.00"),
create_test_dialogue_info("0:00:03.00", "0:00:08.00"),
create_test_dialogue_info("0:00:10.00", "0:00:15.00"),
];
assert_eq!(calculate_total_duration(&events), Some(1500));
assert_eq!(calculate_average_duration(&events), Some(500));
}
#[test]
fn sort_events_maintains_order() {
let mut events = vec![
create_test_dialogue_info("0:00:05.00", "0:00:10.00"),
create_test_dialogue_info("0:00:00.00", "0:00:05.00"),
create_test_dialogue_info("0:00:02.00", "0:00:07.00"),
];
sort_events_by_time(&mut events);
assert_eq!(events[0].start_time_cs(), 0); assert_eq!(events[1].start_time_cs(), 200); assert_eq!(events[2].start_time_cs(), 500); }
#[test]
fn find_events_in_range_filters_correctly() {
let events = vec![
create_test_dialogue_info("0:00:00.00", "0:00:05.00"), create_test_dialogue_info("0:00:03.00", "0:00:08.00"), create_test_dialogue_info("0:00:10.00", "0:00:15.00"), ];
let indices = find_events_in_range(&events, 250, 600); assert_eq!(indices, vec![0, 1]); }
#[test]
fn sort_events_same_start_time() {
let mut events = vec![
create_test_dialogue_info("0:00:05.00", "0:00:10.00"), create_test_dialogue_info("0:00:05.00", "0:00:08.00"), create_test_dialogue_info("0:00:05.00", "0:00:12.00"), ];
sort_events_by_time(&mut events);
assert_eq!(events[0].start_time_cs(), 500);
assert_eq!(events[0].end_time_cs(), 800); assert_eq!(events[1].start_time_cs(), 500);
assert_eq!(events[1].end_time_cs(), 1000); assert_eq!(events[2].start_time_cs(), 500);
assert_eq!(events[2].end_time_cs(), 1200); }
}