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
116
117
118
119
120
121
122
123
124
125
126
use alloc::vec::Vec;
use calc_common::{Button, Character, ExtendedCharacter, GetButton, MetaButton};
use calc_parser::lexer::Lexer;

use crate::{
    drawing::{self, ScreenBuffer},
    math::{self, CalcEvaluator},
};

#[derive(Default)]
struct CalcExpression {
    pub expression: Vec<Character>,
    pub answer: Option<Vec<Character>>,
}

impl CalcExpression {
    pub fn draw(&self, map: &mut ScreenBuffer) {
        let expression: &[Character] = &self.expression;

        drawing::draw_text_at(map, expression, 1, 1);

        drawing::draw_hline(map, 128, 0, 10);

        if let Some(answer) = &self.answer {
            drawing::draw_text_at(
                map,
                answer,
                (128 - drawing::get_text_width(answer)) as u16,
                1,
            );
        }
    }
}

pub struct EvaluationMenuPersistentData {
    cursor_position: usize,
    current_expression: CalcExpression,
}

#[derive(Default)]
pub struct EvaluationMenuState;

impl Default for EvaluationMenuPersistentData {
    fn default() -> Self {
        let cursor_position = 0;
        let current_expression = Default::default();

        Self {
            cursor_position,
            current_expression,
        }
    }
}

impl EvaluationMenuState {
    pub fn draw(&self, screen: &mut ScreenBuffer, persistent_data: &EvaluationMenuPersistentData) {
        screen.clear();
        drawing::draw_sprite_at(
            screen,
            ExtendedCharacter::Cursor,
            (&persistent_data.cursor_position * 5) as u16,
            1,
        );

        persistent_data.current_expression.draw(screen);
    }
}

impl EvaluationMenuState {
    pub fn on_button_press(
        &mut self,
        screen: &mut ScreenBuffer,
        button: Button,
        persistent_data: &mut EvaluationMenuPersistentData,
    ) {
        match button.get() {
            GetButton::Character(char) => {
                persistent_data
                    .current_expression
                    .expression
                    .insert(persistent_data.cursor_position, char);
                persistent_data.cursor_position += 1
            }
            GetButton::Meta(MetaButton::Enter) => {
                let mut lexer = Lexer::<CalcEvaluator, _>::new(
                    persistent_data
                        .current_expression
                        .expression
                        .iter()
                        .copied(),
                );
                let res = calc_parser::parse_and_evaluate::<CalcEvaluator, _>(&mut lexer);
                match res {
                    Ok(ok) => {
                        persistent_data.current_expression.answer = Some(math::number_to_chars(ok))
                    }
                    Err(_err) => todo!("Calculator error handling todo"),
                };
            }
            GetButton::Meta(MetaButton::Back) => {
                if persistent_data.cursor_position != 0 {
                    persistent_data
                        .current_expression
                        .expression
                        .remove(persistent_data.cursor_position - 1);
                    persistent_data.cursor_position -= 1;
                }
            }
            GetButton::Meta(MetaButton::Left) => {
                persistent_data.cursor_position = persistent_data.cursor_position.saturating_sub(1);
            }
            GetButton::Meta(MetaButton::Right) => {
                persistent_data.cursor_position = (persistent_data.cursor_position + 1)
                    .min(persistent_data.current_expression.expression.len());
            }
            GetButton::Meta(MetaButton::Clear) => {
                persistent_data.current_expression.expression.clear();
                persistent_data.current_expression.answer = None;
                persistent_data.cursor_position = 0;
            }
            _ => todo!(),
        }

        self.draw(screen, persistent_data)
    }
}