use std::collections::{BTreeMap, HashMap};
use gled_model::asset::midi_controller::MidiModeHighlight;
use gled_protocol::state::{GridLine, ModeSwitch, TouchedControl};
#[derive(Debug, Default)]
pub(super) struct Controllers {
modes: BTreeMap<String, u8>,
lines: HashMap<(String, u8), GridLine>,
last_switch: Option<ModeSwitch>,
touches: BTreeMap<String, TouchedControl>,
}
impl Controllers {
pub(super) fn switch(
&mut self,
port: String,
mode: u8,
highlight: Option<MidiModeHighlight>,
line: Option<GridLine>,
) -> Option<GridLine> {
let number = self.last_switch.map_or(1, |switch| switch.number + 1);
self.last_switch = Some(ModeSwitch { number, highlight });
let previous = self.modes.insert(port.clone(), mode).unwrap_or(0);
if previous == mode {
return line;
}
match line {
Some(line) => self.lines.insert((port.clone(), previous), line),
None => self.lines.remove(&(port.clone(), previous)),
};
self.lines.get(&(port, mode)).copied()
}
pub(super) fn modes(&self) -> &BTreeMap<String, u8> {
&self.modes
}
pub(super) fn last_switch(&self) -> Option<ModeSwitch> {
self.last_switch
}
pub(super) fn touch(&mut self, touch: String, control: Option<TouchedControl>) {
match control {
Some(control) => self.touches.insert(touch, control),
None => self.touches.remove(&touch),
};
}
pub(super) fn touched(&self) -> Vec<TouchedControl> {
self.touches.values().copied().collect()
}
pub(super) fn reset(&mut self) {
self.modes.clear();
self.lines.clear();
self.touches.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
const PORT: &str = "iCON P1-X1:iCON P1-X1 MIDI 1";
#[test]
fn a_mode_shows_its_line_again_when_the_controller_returns() {
let mut modes = Controllers::default();
let line = modes.switch(PORT.to_owned(), 1, None, Some(GridLine::Row));
assert_eq!(line, None);
let line = modes.switch(PORT.to_owned(), 0, None, line);
assert_eq!(line, Some(GridLine::Row));
assert_eq!(modes.modes().get(PORT), Some(&0));
}
#[test]
fn a_released_touch_is_gone() {
let mut controllers = Controllers::default();
controllers.touch("a".to_owned(), Some(TouchedControl::MainDimmer));
controllers.touch("b".to_owned(), Some(TouchedControl::MainDimmer));
controllers.touch("a".to_owned(), None);
assert_eq!(controllers.touched(), [TouchedControl::MainDimmer]);
}
#[test]
fn every_press_is_a_new_switch() {
let mut modes = Controllers::default();
let highlight = Some(MidiModeHighlight::SceneGrid);
let line = modes.switch(PORT.to_owned(), 0, highlight, Some(GridLine::Column));
assert_eq!(line, Some(GridLine::Column));
modes.switch(PORT.to_owned(), 0, highlight, line);
assert_eq!(
modes.last_switch(),
Some(ModeSwitch {
number: 2,
highlight
})
);
}
}