use std::io::Read;
use anyhow::bail;
use quick_xml::events::{BytesStart, Event};
use crate::{
excel::XmlReader,
helper::{string_to_bool, string_to_float, string_to_unsignedint},
};
use super::cell::XlsxCell;
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxRow {
pub cells: Option<Vec<XlsxCell>>,
pub collapsed: Option<bool>,
pub custom_format: Option<bool>,
pub custom_height: Option<bool>,
pub dy_descent: Option<f64>,
pub height: Option<f64>,
pub hidden: Option<bool>,
pub outline_level: Option<u64>,
pub row_index: Option<u64>,
pub show_phonetic: Option<bool>,
pub spans: Option<(u64, u64)>,
pub style: Option<u64>,
pub thick_bottom: Option<bool>,
pub thick_top: Option<bool>,
}
impl XlsxRow {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let mut row = Self {
cells: None,
collapsed: None,
custom_format: None,
custom_height: None,
dy_descent: None,
height: None,
hidden: None,
outline_level: None,
row_index: None,
show_phonetic: None,
spans: None,
style: None,
thick_bottom: None,
thick_top: None,
};
let mut cells: Vec<XlsxCell> = vec![];
let attributes = e.attributes();
for a in attributes {
match a {
Ok(a) => {
let string_value = String::from_utf8(a.value.to_vec())?;
match a.key.local_name().as_ref() {
b"collapsed" => {
row.collapsed = string_to_bool(&string_value);
}
b"customFormat" => {
row.custom_format = string_to_bool(&string_value);
}
b"customHeight" => {
row.custom_height = string_to_bool(&string_value);
}
b"dyDescent" => {
row.dy_descent = string_to_float(&string_value);
}
b"ht" => {
row.height = string_to_float(&string_value);
}
b"hidden" => {
row.hidden = string_to_bool(&string_value);
}
b"outlineLevel" => {
row.outline_level = string_to_unsignedint(&string_value);
}
b"r" => {
row.row_index = string_to_unsignedint(&string_value);
}
b"ph" => {
row.show_phonetic = string_to_bool(&string_value);
}
b"spans" => {
let parts: Vec<&str> = string_value.split(|c| c == ':').collect();
if parts.len() == 2 {
let r = string_to_unsignedint(parts[0]);
let c = string_to_unsignedint(parts[1]);
if r.is_some() && c.is_some() {
row.spans = Some((r.unwrap(), c.unwrap()))
}
}
}
b"s" => {
row.style = string_to_unsignedint(&string_value);
}
b"thickBot" => {
row.thick_bottom = string_to_bool(&string_value);
}
b"thickTop" => {
row.thick_top = string_to_bool(&string_value);
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
let mut buf: Vec<u8> = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"extLst" => {
let _ = reader.read_to_end_into(e.to_end().to_owned().name(), &mut Vec::new());
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"c" => {
cells.push(XlsxCell::load(reader, e)?);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"row" => break,
Ok(Event::Eof) => bail!("unexpected end of file at `row`."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
if row.row_index.is_none() {
bail!("row of unknwon index.")
}
row.cells = Some(cells);
return Ok(row);
}
}