use crate::format::{LineLexer, LineToken, Token};
use chrono::{DateTime, FixedOffset as Offset, NaiveDate};
use std::collections::BTreeMap;
use std::iter::Iterator;
#[derive(Debug)]
pub enum LineCfg {
Header(BTreeMap<String, String>),
Start(Option<DateTime<Offset>>),
Stop(Option<DateTime<Offset>>),
Invoice(Option<NaiveDate>),
#[doc(hidden)]
Ignore,
}
impl LineCfg {
pub(crate) fn valid(&self) -> bool {
match self {
LineCfg::Ignore => false,
_ => true,
}
}
}
pub(crate) fn parse<'l>(lex: LineLexer<'l>) -> LineCfg {
use LineCfg::*;
use Token as T;
#[cfg_attr(rustfmt, rustfmt_skip)]
lex.get_all().into_iter().fold(Ignore, |cfg, tok| match (cfg, tok) {
(Ignore, LineToken { tt: T::Comment, .. }, ) => Ignore,
(Ignore, LineToken { tt: T::Header, .. }) => Header(Default::default()),
(Ignore, LineToken { tt: T::Start, .. }) => Start(None),
(Ignore, LineToken { tt: T::Stop, .. }) => Stop(None),
(Ignore, LineToken { tt: T::Invoice, .. }) => Invoice(None),
(Header(map), LineToken { tt: T::HeaderData, slice }) => Header(append_data(map, slice)),
(Start(_), LineToken { tt: T::Date, slice }) => Start(parse_datetime(slice)),
(Stop(_), LineToken { tt: T::Date, slice }) => Stop(parse_datetime(slice)),
(Invoice(_), LineToken { tt: T::Date, slice }) => Invoice(parse_date(slice)),
(Empty, _) => Empty,
_ => Ignore,
})
}
fn append_data(mut map: BTreeMap<String, String>, slice: &str) -> BTreeMap<String, String> {
let split = slice.split("=").collect::<Vec<_>>();
map.insert(split[0].into(), split[1].into());
map
}
fn parse_datetime(slice: &str) -> Option<DateTime<Offset>> {
Some(
DateTime::parse_from_str(slice, "%Y-%m-%d %H:%M:%S%:z")
.expect("Failed to parse date; invalid format!"),
)
}
fn parse_date(slice: &str) -> Option<NaiveDate> {
Some(
NaiveDate::parse_from_str(slice, "%Y-%m-%d")
.expect("Failed to parse date; invalid format!"),
)
}