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
/*
 * smartcalc v1.0.7
 * Copyright (c) Erhan BARIS (Ruslan Ognyanov Asenov)
 * Licensed under the GNU General Public License v2.0.
 */

use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use alloc::borrow::ToOwned;
use chrono::NaiveDateTime;
use chrono::Utc;

use crate::config::SmartCalcConfig;
use crate::types::*;
use crate::tokinizer::Tokinizer;
use chrono::NaiveTime;
use regex::Regex;

pub fn get_atom(config: &SmartCalcConfig, data: &str, group_item: &[Regex]) -> Vec<(usize, usize, Option<TokenType>, String)> {
    let mut atoms = Vec::new();

    for re in group_item.iter() {
        for capture in re.captures_iter(data) {
            let atom_type = capture.name("ATOM").unwrap().as_str();
            let data      = capture.name("DATA").unwrap().as_str();

            let token_type = match atom_type {
                "TIME" => {
                    let seconds = data.parse::<u32>().unwrap();
                    let date = Utc::now().naive_local().date();
                    let time = NaiveTime::from_num_seconds_from_midnight(seconds, 0);
                    let date_time = NaiveDateTime::new(date, time);
                    
                    TokenType::Time(date_time, config.get_time_offset())
                },
                "MONEY" => {
                    let splited_data: Vec<&str> = data.split(';').collect();
                    match config.get_currency(splited_data[1].to_string()) {
                        Some(currency_info) => TokenType::Money(splited_data[0].parse::<f64>().unwrap(), currency_info.clone()),
                        None => {
                            log::info!("Currency information not found, {}", splited_data[1]);
                            continue
                        }
                    }
                },
                "NUMBER" => {
                    let number = data.parse::<f64>().unwrap();
                    TokenType::Number(number, NumberType::Decimal)
                },
                "PERCENT" => {
                    let number = data.parse::<f64>().unwrap();
                    TokenType::Percent(number)
                },
                "OPERATOR" => TokenType::Operator(data.chars().next().unwrap()),
                _ => {
                    log::info!("Atom type not found, {}", atom_type);
                    continue
                }
            };

            atoms.push((capture.get(0).unwrap().start(), capture.get(0).unwrap().end(), Some(token_type), capture.get(0).unwrap().as_str().to_string()))
        }
    }
    atoms
}


pub fn atom_regex_parser(config: &SmartCalcConfig, tokinizer: &mut Tokinizer, group_item: &[Regex]) {
    let atoms =  get_atom(config, &tokinizer.data.to_owned(), group_item);
    for (start, end, token_type, text) in atoms {
        tokinizer.add_token_location(start, end, token_type, text);
    }
}

#[cfg(test)]
#[test]
fn operator_test() {
    use core::ops::Deref;
    use crate::tokinizer::regex_tokinizer;
    use crate::tokinizer::test::setup_tokinizer;
    use crate::config::SmartCalcConfig;
    use crate::session::Session;
    let mut session = Session::new();
    let config = SmartCalcConfig::default();
    let mut tokinizer_mut = setup_tokinizer("[OPERATOR:+] [PERCENT:-29.1] [TIME:44100]  [NUMBER:-222.333] [MONEY:200;try]".to_string(), &mut session, &config);

    regex_tokinizer(&mut tokinizer_mut);
    let tokens = &tokinizer_mut.token_infos;

    assert_eq!(tokens.len(), 5);
    assert_eq!(tokens[0].start, 0);
    assert_eq!(tokens[0].end, 12);
    assert_eq!(tokens[0].token_type.borrow().deref(), &Some(TokenType::Operator('+')));

    assert_eq!(tokens[1].start, 13);
    assert_eq!(tokens[1].end, 28);
    assert_eq!(tokens[1].token_type.borrow().deref(), &Some(TokenType::Percent(-29.1)));

    assert_eq!(tokens[2].start, 29);
    assert_eq!(tokens[2].end, 41);
    assert_eq!(tokens[2].token_type.borrow().deref(), &Some(TokenType::Time(chrono::Utc::today().and_hms(12, 15, 0).naive_utc(), config.get_time_offset())));

    assert_eq!(tokens[3].start, 43);
    assert_eq!(tokens[3].end, 60);
    assert_eq!(tokens[3].token_type.borrow().deref(), &Some(TokenType::Number(-222.333, NumberType::Decimal)));

    assert_eq!(tokens[4].start, 61);
    assert_eq!(tokens[4].end, 76);
    assert_eq!(tokens[4].token_type.borrow().deref(), &Some(TokenType::Money(200.0, config.get_currency("try".to_string()).unwrap())));
}