1use alloc::{string::String};
8use alloc::format;
9use alloc::string::ToString;
10use crate::session::Session;
11use crate::tools::do_divition;
12use core::ops::Deref;
13
14use crate::config::SmartCalcConfig;
15use crate::types::{SmartCalcAstType};
16use crate::constants::MonthInfo;
17
18pub const MINUTE: i64 = 60;
19pub const HOUR: i64 = MINUTE * 60;
20pub const DAY: i64 = HOUR * 24;
21pub const WEEK: i64 = DAY * 7;
22pub const MONTH: i64 = DAY * 30;
23pub const YEAR: i64 = DAY * 365;
24
25fn fract_information(f: f64) -> u64 {
26 let eps = 1e-4;
27 let mut f = f.abs().fract();
28 if f == 0.0 { return 0; }
29
30 while (f.round() - f).abs() <= eps {
31 f *= 10.0;
32 }
33
34 while (f.round() - f).abs() > eps {
35 f *= 10.0;
36 }
37
38 f.round() as u64
39}
40
41pub fn left_padding(number: i64, size: usize) -> String {
42 format!("{:0width$}", &number, width = size)
43}
44
45pub fn format_number(number: f64, thousands_separator: String, decimal_separator: String, decimal_digits: u8, remove_fract_if_zero: bool, use_fract_rounding: bool) -> String {
46 let divider = 10_u32.pow(decimal_digits.into());
47 let fract_number = do_divition((number * divider as f64).round(), divider as f64);
48 let trunc_part = fract_number.trunc().abs().to_string();
49
50 let formated_number = match use_fract_rounding {
51 true => format!("{:.width$}", &number.abs(), width = decimal_digits.into()),
52 false => format!("{}", &number.abs())
53 };
54
55 let fract_part = fract_information(fract_number.fract());
56 let trunc_size = trunc_part.len();
57 let mut trunc_dot_index = 3 - (trunc_part.len() % 3);
58 let mut trunc_formated = String::new();
59
60
61 if number < 0.0 {
62 trunc_formated.push('-');
63 }
64
65 for index in 0..trunc_size {
66 trunc_formated.push(formated_number.chars().nth(index).unwrap());
67 trunc_dot_index += 1;
68 if trunc_size != (index + 1) && trunc_dot_index % 3 == 0 {
69 trunc_formated.push_str(&thousands_separator);
70 }
71 }
72
73 if (fract_part > 0 || !remove_fract_if_zero) && trunc_size != formated_number.len() {
74 trunc_formated.push_str(&decimal_separator);
75
76 for index in (trunc_size+1)..formated_number.len() {
77 trunc_formated.push(formated_number.chars().nth(index).unwrap());
78 }
79 }
80
81 trunc_formated
82}
83
84pub fn get_month_info(config: &SmartCalcConfig, language: &'_ str, month: u8) -> Option<MonthInfo> {
85 match config.month_regex.get(language) {
86 Some(month_list) => month_list.get((month - 1) as usize).map(|(_, month)| month.clone()),
87 None => None
88 }
89}
90
91pub fn uppercase_first_letter(s: &'_ str) -> String {
92 let mut c = s.chars();
93 match c.next() {
94 None => String::new(),
95 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
96 }
97}
98
99pub fn format_result(config: &SmartCalcConfig, session: &Session, result: alloc::rc::Rc<SmartCalcAstType>) -> String {
100 match result.deref() {
101 SmartCalcAstType::Item(item) => item.print(config, session),
102 _ => "".to_string()
103 }
104}
105
106#[cfg(test)]
107#[test]
108fn get_frac_test() {
109 assert_eq!(fract_information(0.1234567), 1234567);
110 assert_eq!(fract_information(987654321.987), 987);
111}
112
113#[cfg(test)]
114#[test]
115fn format_number_test() {
116 assert_eq!(format_number(123.0, ",".to_string(), ".".to_string(), 2, false, true), "123.00".to_string());
117 assert_eq!(format_number(123.1, ",".to_string(), ".".to_string(), 2, false, true), "123.10".to_string());
118 assert_eq!(format_number(123.01, ",".to_string(), ".".to_string(), 2, false, true), "123.01".to_string());
119 assert_eq!(format_number(1234.01, ",".to_string(), ".".to_string(), 2, false, true), "1,234.01".to_string());
120 assert_eq!(format_number(123456.01, ",".to_string(), ".".to_string(), 2, false, true), "123,456.01".to_string());
121 assert_eq!(format_number(123456.123456789, ",".to_string(), ".".to_string(), 2, false, true), "123,456.12".to_string());
122 assert_eq!(format_number(123456.1, ",".to_string(), ".".to_string(), 2, false, true), "123,456.10".to_string());
123 assert_eq!(format_number(-123456.1, ",".to_string(), ".".to_string(), 2, false, true), "-123,456.10".to_string());
124
125 assert_eq!(format_number(123.0, ",".to_string(), ".".to_string(), 2, true, false), "123".to_string());
126 assert_eq!(format_number(123.0000, ",".to_string(), ".".to_string(), 2, true, false), "123".to_string());
127 assert_eq!(format_number(123.1, ",".to_string(), ".".to_string(), 2, false, false), "123.1".to_string());
128 assert_eq!(format_number(123.01, ",".to_string(), ".".to_string(), 2, false, false), "123.01".to_string());
129 assert_eq!(format_number(1234.01, ",".to_string(), ".".to_string(), 2, false, false), "1,234.01".to_string());
130 assert_eq!(format_number(123456.01, ",".to_string(), ".".to_string(), 2, false, false), "123,456.01".to_string());
131 assert_eq!(format_number(123456.123456789, ",".to_string(), ".".to_string(), 2, false, false), "123,456.123456789".to_string());
132 assert_eq!(format_number(123456.1, ",".to_string(), ".".to_string(), 2, false, false), "123,456.1".to_string());
133 assert_eq!(format_number(-123456.1, ",".to_string(), ".".to_string(), 2, false, false), "-123,456.1".to_string());
134}
135
136#[cfg(test)]
137#[test]
138fn format_result_test() {
139 use alloc::rc::Rc;
140 use crate::compiler::DataItem;
141 use crate::compiler::number::NumberItem;
142 use crate::compiler::time::TimeItem;
143 use crate::config::SmartCalcConfig;
144 use crate::types::NumberType;
145 let config = SmartCalcConfig::default();
146
147 let mut session = Session::default();
148 session.set_language("en".to_string());
149 assert_eq!(NumberItem(123456.123456789, NumberType::Decimal).print(&config, &session), "123.456,12".to_string());
150 assert_eq!(NumberItem(1.123456789, NumberType::Decimal).print(&config, &session), "1,12".to_string());
151 assert_eq!(NumberItem(2.0, NumberType::Hexadecimal).print(&config, &session), "0x2".to_string());
152
153 assert_eq!(format_result(&config, &session, Rc::new(SmartCalcAstType::Item(Rc::new(TimeItem(chrono::Utc::today().and_hms(11, 30, 0).naive_utc(), config.get_time_offset()))))), "11:30:00 UTC".to_string());
154 assert_eq!(format_result(&config, &session, Rc::new(SmartCalcAstType::Item(Rc::new(TimeItem(chrono::Utc::today().and_hms(0, 0, 0).naive_utc(), config.get_time_offset()))))), "00:00:00 UTC".to_string());
155}