Skip to main content

selfware/ui/demo/
runner.rs

1//! Demo Runner
2//!
3//! Orchestrates demo scenario execution with animation coordination.
4
5use super::{DemoConfig, DemoEvent};
6use crate::tui::animation::{
7    agent_avatar::{ActivityLevel, AgentAvatar, AgentRole},
8    message_flow::{MessageFlow, MessageFlowManager, MessageType},
9    particles::ParticleSystem,
10    progress::AnimatedProgressBar,
11    token_stream::TokenStream,
12    Animation, AnimationManager,
13};
14use std::collections::HashMap;
15use std::time::{Duration, Instant};
16
17/// Current state of the demo
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum DemoState {
20    /// Not yet started
21    Idle,
22    /// Running a scenario
23    Running,
24    /// Paused mid-execution
25    Paused,
26    /// Scenario completed
27    Completed,
28    /// Error occurred
29    Error(String),
30}
31
32/// Demo scenario trait
33pub trait DemoScenario: Send + Sync {
34    /// Get scenario name
35    fn name(&self) -> &str;
36
37    /// Get scenario description
38    fn description(&self) -> &str;
39
40    /// Get total number of stages
41    fn total_stages(&self) -> usize;
42
43    /// Initialize the scenario
44    fn initialize(&mut self, runner: &mut DemoRunner);
45
46    /// Execute the next stage
47    fn execute_stage(&mut self, stage: usize, runner: &mut DemoRunner) -> bool;
48
49    /// Clean up after completion
50    fn cleanup(&mut self, runner: &mut DemoRunner);
51}
52
53/// Demo runner that coordinates scenario execution
54pub struct DemoRunner {
55    /// Configuration
56    config: DemoConfig,
57    /// Current state
58    state: DemoState,
59    /// Current scenario name
60    scenario_name: Option<String>,
61    /// Current stage
62    current_stage: usize,
63    /// Total stages
64    total_stages: usize,
65    /// Start time
66    start_time: Option<Instant>,
67    /// Event history
68    events: Vec<DemoEvent>,
69    /// Animation manager
70    animation_manager: AnimationManager,
71    /// Particle system
72    particle_system: ParticleSystem,
73    /// Message flow manager
74    message_flow_manager: MessageFlowManager,
75    /// Token stream visualization
76    token_stream: TokenStream,
77    /// Progress bar
78    progress_bar: AnimatedProgressBar,
79    /// Agent avatars
80    agents: HashMap<String, AgentAvatar>,
81}
82
83impl DemoRunner {
84    /// Create a new demo runner
85    pub fn new(config: DemoConfig) -> Self {
86        Self {
87            config: config.clone(),
88            state: DemoState::Idle,
89            scenario_name: None,
90            current_stage: 0,
91            total_stages: 0,
92            start_time: None,
93            events: Vec::new(),
94            animation_manager: AnimationManager::new(),
95            particle_system: ParticleSystem::new(config.max_particles),
96            message_flow_manager: MessageFlowManager::new(),
97            token_stream: TokenStream::new(50),
98            progress_bar: AnimatedProgressBar::new(0.0),
99            agents: HashMap::new(),
100        }
101    }
102
103    /// Start a demo scenario
104    pub fn start(&mut self, scenario: &mut dyn DemoScenario) {
105        self.scenario_name = Some(scenario.name().to_string());
106        self.total_stages = scenario.total_stages();
107        self.current_stage = 0;
108        self.start_time = Some(Instant::now());
109        self.state = DemoState::Running;
110        self.events.clear();
111
112        self.emit_event(DemoEvent::ScenarioStarted {
113            name: scenario.name().to_string(),
114        });
115
116        scenario.initialize(self);
117    }
118
119    /// Execute the next stage
120    pub fn next_stage(&mut self, scenario: &mut dyn DemoScenario) -> bool {
121        if self.state != DemoState::Running {
122            return false;
123        }
124
125        if self.current_stage >= self.total_stages {
126            self.complete(scenario);
127            return false;
128        }
129
130        let success = scenario.execute_stage(self.current_stage, self);
131
132        if success {
133            self.emit_event(DemoEvent::StageCompleted {
134                stage: self.current_stage,
135                total: self.total_stages,
136            });
137
138            self.current_stage += 1;
139            self.progress_bar
140                .set_progress(self.current_stage as f32 / self.total_stages as f32);
141        }
142
143        success
144    }
145
146    /// Complete the scenario
147    fn complete(&mut self, scenario: &mut dyn DemoScenario) {
148        let duration = self
149            .start_time
150            .map(|t| t.elapsed().as_secs_f32())
151            .unwrap_or(0.0);
152
153        self.emit_event(DemoEvent::ScenarioCompleted {
154            duration_secs: duration,
155        });
156
157        scenario.cleanup(self);
158        self.state = DemoState::Completed;
159    }
160
161    /// Pause execution
162    pub fn pause(&mut self) {
163        if self.state == DemoState::Running {
164            self.state = DemoState::Paused;
165            self.animation_manager.toggle_pause();
166        }
167    }
168
169    /// Resume execution
170    pub fn resume(&mut self) {
171        if self.state == DemoState::Paused {
172            self.state = DemoState::Running;
173            self.animation_manager.toggle_pause();
174        }
175    }
176
177    /// Reset the runner
178    pub fn reset(&mut self) {
179        self.state = DemoState::Idle;
180        self.scenario_name = None;
181        self.current_stage = 0;
182        self.total_stages = 0;
183        self.start_time = None;
184        self.events.clear();
185        self.agents.clear();
186        self.particle_system.clear();
187        self.progress_bar.set_progress(0.0);
188    }
189
190    /// Update all animations
191    pub fn update(&mut self, delta_time: f32) {
192        let adjusted_delta = delta_time * self.config.speed_multiplier;
193
194        self.animation_manager.update(adjusted_delta);
195        self.particle_system.update(adjusted_delta);
196        self.message_flow_manager.update(adjusted_delta);
197        self.token_stream.update(adjusted_delta);
198        self.progress_bar.update(adjusted_delta);
199
200        for avatar in self.agents.values_mut() {
201            avatar.update(adjusted_delta);
202        }
203    }
204
205    // === Agent Management ===
206
207    /// Add an agent to the demo
208    pub fn add_agent(&mut self, id: &str, role: AgentRole) {
209        let avatar = AgentAvatar::new(role).with_name(id);
210        self.agents.insert(id.to_string(), avatar);
211    }
212
213    /// Set agent activity level
214    pub fn set_agent_activity(&mut self, id: &str, level: ActivityLevel) {
215        if let Some(avatar) = self.agents.get_mut(id) {
216            avatar.set_activity(level);
217        }
218    }
219
220    /// Add tokens to an agent
221    pub fn add_agent_tokens(&mut self, id: &str, tokens: u64) {
222        if let Some(avatar) = self.agents.get_mut(id) {
223            avatar.add_tokens(tokens);
224        }
225
226        self.emit_event(DemoEvent::TokensProcessed {
227            count: tokens,
228            rate: tokens as f64 / 0.016, // Assume 60fps
229        });
230    }
231
232    /// Get agent avatar reference
233    pub fn agent(&self, id: &str) -> Option<&AgentAvatar> {
234        self.agents.get(id)
235    }
236
237    // === Message Flow ===
238
239    /// Send a message between agents
240    pub fn send_message(
241        &mut self,
242        from: &str,
243        to: &str,
244        msg_type: MessageType,
245        from_pos: (f32, f32),
246        to_pos: (f32, f32),
247    ) {
248        let flow = MessageFlow::new(from_pos, to_pos, msg_type);
249        self.message_flow_manager.add(flow);
250
251        self.emit_event(DemoEvent::MessageSent {
252            from: from.to_string(),
253            to: to.to_string(),
254            msg_type: format!("{:?}", msg_type),
255        });
256    }
257
258    // === Particle Effects ===
259
260    /// Trigger a sparkle effect
261    pub fn sparkle(&mut self, x: f32, y: f32, count: usize) {
262        if self.config.particles_enabled {
263            self.particle_system.sparkle(x, y, count);
264            self.emit_event(DemoEvent::EffectTriggered {
265                effect_type: "sparkle".to_string(),
266                x,
267                y,
268            });
269        }
270    }
271
272    /// Trigger an explosion effect
273    pub fn explode(&mut self, x: f32, y: f32, count: usize) {
274        if self.config.particles_enabled {
275            self.particle_system.explode(x, y, count);
276            self.emit_event(DemoEvent::EffectTriggered {
277                effect_type: "explode".to_string(),
278                x,
279                y,
280            });
281        }
282    }
283
284    /// Trigger a celebration effect
285    pub fn celebrate(&mut self, x: f32, y: f32) {
286        if self.config.particles_enabled {
287            self.particle_system.celebrate(x, y);
288            self.emit_event(DemoEvent::EffectTriggered {
289                effect_type: "celebrate".to_string(),
290                x,
291                y,
292            });
293        }
294    }
295
296    // === Token Stream ===
297
298    /// Set token rate
299    pub fn set_token_rate(&mut self, rate: f64) {
300        self.token_stream.set_rate(rate);
301    }
302
303    /// Set total tokens
304    pub fn set_total_tokens(&mut self, total: u64) {
305        self.token_stream.set_total(total);
306    }
307
308    // === Event System ===
309
310    /// Emit a demo event
311    pub fn emit_event(&mut self, event: DemoEvent) {
312        self.events.push(event);
313    }
314
315    /// Get event history
316    pub fn events(&self) -> &[DemoEvent] {
317        &self.events
318    }
319
320    // === Accessors ===
321
322    pub fn state(&self) -> &DemoState {
323        &self.state
324    }
325
326    pub fn current_stage(&self) -> usize {
327        self.current_stage
328    }
329
330    pub fn total_stages(&self) -> usize {
331        self.total_stages
332    }
333
334    pub fn progress(&self) -> f32 {
335        if self.total_stages == 0 {
336            0.0
337        } else {
338            self.current_stage as f32 / self.total_stages as f32
339        }
340    }
341
342    pub fn elapsed(&self) -> Duration {
343        self.start_time.map(|t| t.elapsed()).unwrap_or_default()
344    }
345
346    pub fn particle_system(&self) -> &ParticleSystem {
347        &self.particle_system
348    }
349
350    pub fn message_flow_manager(&self) -> &MessageFlowManager {
351        &self.message_flow_manager
352    }
353
354    pub fn token_stream(&self) -> &TokenStream {
355        &self.token_stream
356    }
357
358    pub fn progress_bar(&self) -> &AnimatedProgressBar {
359        &self.progress_bar
360    }
361
362    pub fn agents(&self) -> &HashMap<String, AgentAvatar> {
363        &self.agents
364    }
365
366    pub fn config(&self) -> &DemoConfig {
367        &self.config
368    }
369}
370
371impl Default for DemoRunner {
372    fn default() -> Self {
373        Self::new(DemoConfig::default())
374    }
375}
376
377#[cfg(test)]
378mod tests {
379    use super::*;
380
381    struct TestScenario {
382        name: String,
383        stages: usize,
384        initialized: bool,
385        executed_stages: Vec<usize>,
386        cleaned_up: bool,
387    }
388
389    impl TestScenario {
390        fn new(stages: usize) -> Self {
391            Self {
392                name: "Test Scenario".to_string(),
393                stages,
394                initialized: false,
395                executed_stages: Vec::new(),
396                cleaned_up: false,
397            }
398        }
399    }
400
401    impl DemoScenario for TestScenario {
402        fn name(&self) -> &str {
403            &self.name
404        }
405
406        fn description(&self) -> &str {
407            "A test scenario"
408        }
409
410        fn total_stages(&self) -> usize {
411            self.stages
412        }
413
414        fn initialize(&mut self, _runner: &mut DemoRunner) {
415            self.initialized = true;
416        }
417
418        fn execute_stage(&mut self, stage: usize, _runner: &mut DemoRunner) -> bool {
419            self.executed_stages.push(stage);
420            true
421        }
422
423        fn cleanup(&mut self, _runner: &mut DemoRunner) {
424            self.cleaned_up = true;
425        }
426    }
427
428    #[test]
429    fn test_demo_runner_new() {
430        let runner = DemoRunner::new(DemoConfig::default());
431        assert_eq!(*runner.state(), DemoState::Idle);
432        assert_eq!(runner.current_stage(), 0);
433    }
434
435    #[test]
436    fn test_demo_runner_start() {
437        let mut runner = DemoRunner::new(DemoConfig::default());
438        let mut scenario = TestScenario::new(5);
439
440        runner.start(&mut scenario);
441
442        assert!(scenario.initialized);
443        assert_eq!(*runner.state(), DemoState::Running);
444        assert_eq!(runner.total_stages(), 5);
445    }
446
447    #[test]
448    fn test_demo_runner_stages() {
449        let mut runner = DemoRunner::new(DemoConfig::default());
450        let mut scenario = TestScenario::new(3);
451
452        runner.start(&mut scenario);
453
454        assert!(runner.next_stage(&mut scenario));
455        assert_eq!(runner.current_stage(), 1);
456
457        assert!(runner.next_stage(&mut scenario));
458        assert_eq!(runner.current_stage(), 2);
459
460        assert!(runner.next_stage(&mut scenario));
461        assert_eq!(runner.current_stage(), 3);
462
463        // Should complete and return false
464        assert!(!runner.next_stage(&mut scenario));
465        assert_eq!(*runner.state(), DemoState::Completed);
466        assert!(scenario.cleaned_up);
467    }
468
469    #[test]
470    fn test_demo_runner_pause_resume() {
471        let mut runner = DemoRunner::new(DemoConfig::default());
472        let mut scenario = TestScenario::new(3);
473
474        runner.start(&mut scenario);
475        assert_eq!(*runner.state(), DemoState::Running);
476
477        runner.pause();
478        assert_eq!(*runner.state(), DemoState::Paused);
479
480        runner.resume();
481        assert_eq!(*runner.state(), DemoState::Running);
482    }
483
484    #[test]
485    fn test_demo_runner_agents() {
486        let mut runner = DemoRunner::new(DemoConfig::default());
487
488        runner.add_agent("coder-1", AgentRole::Coder);
489        runner.add_agent("tester-1", AgentRole::Tester);
490
491        assert_eq!(runner.agents().len(), 2);
492        assert!(runner.agent("coder-1").is_some());
493        assert!(runner.agent("unknown").is_none());
494    }
495
496    #[test]
497    fn test_demo_runner_effects() {
498        let mut runner = DemoRunner::new(DemoConfig::default());
499
500        runner.sparkle(10.0, 10.0, 5);
501        runner.explode(20.0, 20.0, 10);
502        runner.celebrate(30.0, 30.0);
503
504        assert_eq!(runner.events().len(), 3);
505    }
506}