use chrono::prelude::*;
use pest::Parser;
use rust_decimal::Decimal;
use crate::errors::{AmountParseError, DateParseError};
use crate::MT940Parser;
use crate::Rule;
pub fn decimal_from_mt940_amount(s: &str) -> Result<Decimal, AmountParseError> {
let split_decimal_str: Vec<&str> = s.split(',').collect();
if split_decimal_str.len() == 1 {
return Err(AmountParseError::NoComma(s.to_string()));
} else if split_decimal_str.len() > 2 {
return Err(AmountParseError::TooManyCommas(s.to_string()));
}
let (int_part, frac_part) = (split_decimal_str[0], split_decimal_str[1]);
let whole_number: i64 = format!("{int_part}{frac_part}")
.parse()
.map_err(AmountParseError::IntParseError)?;
Ok(Decimal::new(whole_number, frac_part.len() as u32))
}
pub fn date_from_mt940_date(s: &str) -> Result<NaiveDate, DateParseError> {
let parsed_date = MT940Parser::parse(Rule::date, s)?
.next()
.unwrap()
.into_inner();
let mut year = None;
let mut month = None;
let mut day = None;
for p in parsed_date {
match p.as_rule() {
Rule::year => year = Some(format!("20{}", p.as_str())),
Rule::month => month = Some(p.as_str()),
Rule::day => day = Some(p.as_str()),
_ => unreachable!(),
}
}
NaiveDate::from_ymd_opt(
year.clone().unwrap().parse().unwrap(),
month.unwrap().parse().unwrap(),
day.unwrap().parse().unwrap(),
)
.ok_or_else(|| DateParseError::OutOfRange {
year: year.unwrap(),
month: month.unwrap().to_string(),
day: day.unwrap().to_string(),
})
}