1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::{
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc, Mutex,
    },
    time::Duration,
};

use arci::{
    gamepad::{Button, Gamepad, GamepadEvent},
    Speaker,
};
use tokio::sync::Mutex as TokioMutex;
use tracing::{debug, warn};

use super::control_mode::ControlMode;

pub struct ControlModeSwitcher<S>
where
    S: Speaker,
{
    current_index: Arc<Mutex<usize>>,
    control_modes: Arc<TokioMutex<Vec<Arc<dyn ControlMode>>>>,
    speaker: S,
    is_running: Arc<AtomicBool>,
}

impl<S> ControlModeSwitcher<S>
where
    S: Speaker,
{
    #[track_caller]
    pub fn new(
        control_modes: Vec<Arc<dyn ControlMode>>,
        speaker: S,
        initial_mode_index: usize,
    ) -> Self {
        assert!(!control_modes.is_empty());
        Self {
            current_index: Arc::new(Mutex::new(initial_mode_index)),
            control_modes: Arc::new(TokioMutex::new(control_modes)),
            speaker,
            is_running: Arc::new(AtomicBool::new(false)),
        }
    }

    pub async fn increment_mode(&self) -> Result<(), arci::Error> {
        let len = self.control_modes.lock().await.len();
        {
            let mut index = self.current_index.lock().unwrap();
            *index = (*index + 1) % len;
        }
        self.speak_current_mode().await
    }

    pub async fn speak_current_mode(&self) -> Result<(), arci::Error> {
        let modes = self.control_modes.lock().await;
        let i = self.current_index();
        let mode = modes[i].mode();
        let submode = modes[i].submode();
        self.speaker.speak(&format!("{mode}{submode}"))?.await
    }

    fn current_index(&self) -> usize {
        *self.current_index.lock().unwrap()
    }

    fn is_running(&self) -> bool {
        self.is_running.load(Ordering::Relaxed)
    }

    pub fn stop(&self) {
        self.is_running.store(false, Ordering::Relaxed);
    }

    pub async fn main<G>(&self, gamepad: G)
    where
        G: 'static + Gamepad,
    {
        let modes = self.control_modes.clone();
        let index = self.current_index.clone();
        let is_running = self.is_running.clone();
        self.is_running.store(true, Ordering::Relaxed);
        self.speak_current_mode().await.unwrap();
        let gamepad = Arc::new(gamepad);
        let gamepad_cloned = gamepad.clone();
        tokio::spawn(async move {
            let mut interval = tokio::time::interval(Duration::from_millis(50));
            while is_running.load(Ordering::Relaxed) {
                debug!("tick");
                let mode = { modes.lock().await[*index.lock().unwrap()].clone() };
                mode.proc().await;
                interval.tick().await;
            }
            gamepad_cloned.stop();
        });
        while self.is_running() {
            let ev = gamepad.next_event().await;
            debug!("event: {ev:?}");
            match ev {
                GamepadEvent::ButtonPressed(Button::North) => {
                    self.increment_mode().await.unwrap();
                }
                GamepadEvent::Unknown => {
                    warn!("gamepad Unknown");
                    self.stop();
                }
                _ => {
                    let mode = { self.control_modes.lock().await[self.current_index()].clone() };
                    mode.handle_event(ev);
                }
            }
        }
    }
}