use crate::reader::driver::*;
use crate::writer::driver::*;
use md5::Digest;
use quick_xml::escape;
use quick_xml::events::BytesStart;
use quick_xml::Reader;
use quick_xml::Writer;
use std::collections::HashMap;
use std::io::Cursor;
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct NumberingFormat {
number_format_id: u32,
format_code: Box<str>,
is_build_in: bool,
}
impl Default for NumberingFormat {
#[inline]
fn default() -> Self {
Self {
number_format_id: 0,
format_code: NumberingFormat::FORMAT_GENERAL.into(),
is_build_in: true,
}
}
}
impl NumberingFormat {
pub const FORMAT_GENERAL: &'static str = "General";
pub const FORMAT_TEXT: &'static str = "@";
pub const FORMAT_NUMBER: &'static str = "0";
pub const FORMAT_NUMBER_00: &'static str = "0.00";
pub const FORMAT_NUMBER_COMMA_SEPARATED1: &'static str = "#,##0.00";
pub const FORMAT_NUMBER_COMMA_SEPARATED2: &'static str = "#,##0.00_-";
pub const FORMAT_PERCENTAGE: &'static str = "0%";
pub const FORMAT_PERCENTAGE_00: &'static str = "0.00%";
pub const FORMAT_DATE_YYYYMMDD2: &'static str = "yyyy-mm-dd";
pub const FORMAT_DATE_YYYYMMDD: &'static str = "yyyy-mm-dd";
pub const FORMAT_DATE_DDMMYYYY: &'static str = "dd-mm-yyyy";
pub const FORMAT_DATE_DDMMYYYYSLASH: &'static str = "dd/mm/yyyy";
pub const FORMAT_DATE_DMYSLASH: &'static str = "d/m/yy";
pub const FORMAT_DATE_DMYMINUS: &'static str = "d-m-yy";
pub const FORMAT_DATE_DMMINUS: &'static str = "d-m";
pub const FORMAT_DATE_MYMINUS: &'static str = "m-yy";
pub const FORMAT_DATE_XLSX14: &'static str = "mm-dd-yy";
pub const FORMAT_DATE_XLSX15: &'static str = "d-mmm-yy";
pub const FORMAT_DATE_XLSX16: &'static str = "d-mmm";
pub const FORMAT_DATE_XLSX17: &'static str = "mmm-yy";
pub const FORMAT_DATE_XLSX22: &'static str = "m/d/yy h:mm";
pub const FORMAT_DATE_DATETIME: &'static str = "d/m/yy h:mm";
pub const FORMAT_DATE_TIME1: &'static str = "h:mm AM/PM";
pub const FORMAT_DATE_TIME2: &'static str = "h:mm:ss AM/PM";
pub const FORMAT_DATE_TIME3: &'static str = "h:mm";
pub const FORMAT_DATE_TIME4: &'static str = "h:mm:ss";
pub const FORMAT_DATE_TIME5: &'static str = "mm:ss";
pub const FORMAT_DATE_TIME6: &'static str = "h:mm:ss";
pub const FORMAT_DATE_TIME8: &'static str = "h:mm:ss;@";
pub const FORMAT_DATE_YYYYMMDDSLASH: &'static str = "yyyy/mm/dd;@";
pub const FORMAT_CURRENCY_USD_SIMPLE: &'static str = r##""$"#,##0.00_-"##;
pub const FORMAT_CURRENCY_USD: &'static str = r###"$#,##0_-"###;
pub const FORMAT_CURRENCY_EUR_SIMPLE: &'static str = r#"#,##0.00_-"€""#;
pub const FORMAT_CURRENCY_EUR: &'static str = r#"#,##0_-"€""#;
pub const FORMAT_ACCOUNTING_USD: &'static str =
r#"_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)"#;
pub const FORMAT_ACCOUNTING_EUR: &'static str =
r#"_("€"* #,##0.00_);_("€"* \(#,##0.00\);_("€"* "-"??_);_(@_)"#;
#[inline]
pub fn get_number_format_id(&self) -> &u32 {
&self.number_format_id
}
pub fn set_number_format_id(&mut self, value: u32) -> &mut Self {
let format_code_result = FILL_BUILT_IN_FORMAT_CODES.iter().find_map(|(key, val)| {
if key == &value {
Some(val.clone())
} else {
None
}
});
self.format_code = format_code_result
.expect("Not Found NumberFormatId.")
.into_boxed_str();
self.number_format_id = value;
self.is_build_in = true;
self
}
#[inline]
pub(crate) fn set_number_format_id_crate(&mut self, value: u32) -> &mut Self {
self.number_format_id = value;
self
}
pub fn set_format_code<S: Into<String>>(&mut self, value: S) -> &mut Self {
self.format_code = value.into().into_boxed_str();
for (index, format) in FILL_BUILT_IN_FORMAT_CODES.iter() {
if &*self.format_code == format {
self.number_format_id = *index;
self.is_build_in = true;
return self;
}
}
self.number_format_id = 999999;
self.is_build_in = false;
self
}
#[inline]
pub(crate) fn set_format_code_crate<S: Into<String>>(&mut self, value: S) -> &mut Self {
self.format_code = value.into().into_boxed_str();
self
}
#[inline]
pub fn get_format_code(&self) -> &str {
&self.format_code
}
#[inline]
pub(crate) fn get_is_build_in(&self) -> &bool {
&self.is_build_in
}
#[inline]
pub(crate) fn get_hash_code(&self) -> String {
format!("{:x}", md5::Md5::digest(&*self.format_code))
}
pub(crate) fn set_attributes<R: std::io::BufRead>(
&mut self,
_reader: &mut Reader<R>,
e: &BytesStart,
) {
self.number_format_id = get_attribute(e, b"numFmtId")
.unwrap()
.parse::<u32>()
.unwrap();
self.format_code = escape::unescape(get_attribute(e, b"formatCode").unwrap().as_str())
.unwrap()
.to_string()
.into_boxed_str();
self.is_build_in = false;
}
pub(crate) fn write_to(&self, writer: &mut Writer<Cursor<Vec<u8>>>, number_format_id: &u32) {
write_start_tag(
writer,
"numFmt",
vec![
("numFmtId", &number_format_id.to_string()),
("formatCode", &self.format_code),
],
true,
);
}
}
lazy_static! {
pub(crate) static ref FILL_BUILT_IN_FORMAT_CODES: HashMap<u32, String> = {
let mut map:HashMap<u32, String> = HashMap::new();
map.insert(0, NumberingFormat::FORMAT_GENERAL.to_string());
map.insert(1, "0".to_string());
map.insert(2, "0.00".to_string());
map.insert(3, "#,##0".to_string());
map.insert(4, "#,##0.00".to_string());
map.insert(9, "0%".to_string());
map.insert(10, "0.00%".to_string());
map.insert(11, "0.00E+00".to_string());
map.insert(12, "# ?/?".to_string());
map.insert(13, "# ??/??".to_string());
map.insert(14, "m/d/yyyy".to_string()); map.insert(15, "d-mmm-yy".to_string());
map.insert(16, "d-mmm".to_string());
map.insert(17, "mmm-yy".to_string());
map.insert(18, "h:mm AM/PM".to_string());
map.insert(19, "h:mm:ss AM/PM".to_string());
map.insert(20, "h:mm".to_string());
map.insert(21, "h:mm:ss".to_string());
map.insert(22, "m/d/yyyy h:mm".to_string());
map.insert(37, "#,##0_);(#,##0)".to_string()); map.insert(38, "#,##0_);[Red](#,##0)".to_string()); map.insert(39, "#,##0.00_);(#,##0.00)".to_string()); map.insert(40, "#,##0.00_);[Red](#,##0.00)".to_string());
map.insert(44, r#"_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)"#.to_string());
map.insert(45, "mm:ss".to_string());
map.insert(46, "[h]:mm:ss".to_string());
map.insert(47, "mm:ss.0".to_string()); map.insert(48, "##0.0E+0".to_string());
map.insert(49, "@".to_string());
map.insert(27, "[$-404]e/m/d".to_string());
map.insert(30, "m/d/yy".to_string());
map.insert(36, "[$-404]e/m/d".to_string());
map.insert(50, "[$-404]e/m/d".to_string());
map.insert(57, "[$-404]e/m/d".to_string());
map.insert(59, "t0".to_string());
map.insert(60, "t0.00".to_string());
map.insert(61, "t#,##0".to_string());
map.insert(62, "t#,##0.00".to_string());
map.insert(67, "t0%".to_string());
map.insert(68, "t0.00%".to_string());
map.insert(69, "t# ?/?".to_string());
map.insert(70, "t# ??/??".to_string());
map.insert(28, r#"[$-411]ggge"年"m"月"d"日""#.to_string());
map.insert(29, r#"[$-411]ggge"年"m"月"d"日""#.to_string());
map.insert(31, r#"yyyy"年"m"月"d"日""#.to_string());
map.insert(32, r#"h"時"mm"分""#.to_string());
map.insert(33, r#"h"時"mm"分"ss"秒""#.to_string());
map.insert(34, r#"yyyy"年"m"月""#.to_string());
map.insert(35, r#"m"月"d"日""#.to_string());
map.insert(51, r#"[$-411]ggge"年"m"月"d"日""#.to_string());
map.insert(52, r#"yyyy"年"m"月""#.to_string());
map.insert(53, r#"m"月"d"日""#.to_string());
map.insert(54, r#"[$-411]ggge"年"m"月"d"日""#.to_string());
map.insert(55, r#"yyyy"年"m"月""#.to_string());
map.insert(56, r#"m"月"d"日""#.to_string());
map.insert(58, r#"[$-411]ggge"年"m"月"d"日""#.to_string());
map
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn set_number_format_id() {
let mut obj = NumberingFormat::default();
obj.set_number_format_id(0);
assert_eq!(obj.get_format_code(), "General");
obj.set_number_format_id(1);
assert_eq!(obj.get_format_code(), "0");
}
}