Skip to main content

ass_core/analysis/
queries.rs

1//! Accessors and performance queries for [`ScriptAnalysis`].
2//!
3//! Exposes the cached analysis results (lint issues, resolved styles, dialogue
4//! information) and derives the aggregate [`PerformanceSummary`] from them.
5
6use super::{
7    count_overlapping_dialogue_events, linting, DialogueInfo, LintIssue, PerformanceSummary,
8    ResolvedStyle, ScriptAnalysis,
9};
10use crate::parser::Script;
11
12impl<'a> ScriptAnalysis<'a> {
13    /// Get all lint issues found during analysis
14    #[must_use]
15    pub fn lint_issues(&self) -> &[LintIssue] {
16        &self.lint_issues
17    }
18
19    /// Get resolved styles
20    #[must_use]
21    pub fn resolved_styles(&self) -> &[ResolvedStyle<'a>] {
22        &self.resolved_styles
23    }
24
25    /// Get dialogue analysis results
26    #[must_use]
27    pub fn dialogue_info(&self) -> &[DialogueInfo<'a>] {
28        &self.dialogue_info
29    }
30
31    /// Get reference to the analyzed script
32    #[must_use]
33    pub const fn script(&self) -> &'a Script<'a> {
34        self.script
35    }
36
37    /// Find resolved style by name
38    #[must_use]
39    pub fn resolve_style(&self, name: &str) -> Option<&ResolvedStyle<'a>> {
40        self.resolved_styles.iter().find(|style| style.name == name)
41    }
42
43    /// Check if script has any critical issues
44    #[must_use]
45    pub fn has_critical_issues(&self) -> bool {
46        self.lint_issues
47            .iter()
48            .any(|issue| issue.severity() == linting::IssueSeverity::Critical)
49    }
50
51    /// Get performance summary
52    #[must_use]
53    pub fn performance_summary(&self) -> PerformanceSummary {
54        PerformanceSummary {
55            total_events: self.dialogue_info.len(),
56            overlapping_events: self.count_overlapping_events(),
57            complex_animations: self.count_complex_animations(),
58            large_fonts: self.count_large_fonts(),
59            performance_score: self.calculate_performance_score(),
60        }
61    }
62
63    /// Count overlapping events using efficient O(n log n) algorithm
64    fn count_overlapping_events(&self) -> usize {
65        count_overlapping_dialogue_events(&self.dialogue_info)
66    }
67
68    /// Count complex animations (transforms, etc.)
69    fn count_complex_animations(&self) -> usize {
70        self.dialogue_info
71            .iter()
72            .filter(|info| info.animation_score() > 3)
73            .count()
74    }
75
76    /// Count fonts larger than reasonable size
77    fn count_large_fonts(&self) -> usize {
78        self.resolved_styles
79            .iter()
80            .filter(|style| style.font_size() > 72.0)
81            .count()
82    }
83
84    /// Calculate overall performance score (0-100)
85    fn calculate_performance_score(&self) -> u8 {
86        let mut score = 100u8;
87
88        if self.dialogue_info.len() > 1000 {
89            score = score.saturating_sub(20);
90        } else if self.dialogue_info.len() > 500 {
91            score = score.saturating_sub(10);
92        }
93
94        let overlaps = self.count_overlapping_events();
95        if overlaps > 50 {
96            score = score.saturating_sub(15);
97        } else if overlaps > 20 {
98            score = score.saturating_sub(8);
99        }
100
101        let animations = self.count_complex_animations();
102        if animations > 100 {
103            score = score.saturating_sub(10);
104        } else if animations > 50 {
105            score = score.saturating_sub(5);
106        }
107
108        let large_fonts = self.count_large_fonts();
109        if large_fonts > 10 {
110            score = score.saturating_sub(5);
111        }
112
113        score
114    }
115}