use std::io::Read;
use ironcalc_base::types::{Table, TableColumn, TableStyleInfo};
use roxmltree::Node;
use crate::error::XlsxError;
use super::util::{get_bool, get_bool_false};
pub(crate) fn load_table<R: Read + std::io::Seek>(
archive: &mut zip::read::ZipArchive<R>,
path: &str,
sheet_name: &str,
) -> Result<Table, XlsxError> {
let mut file = archive.by_name(path)?;
let mut text = String::new();
file.read_to_string(&mut text)?;
let document = roxmltree::Document::parse(&text)?;
let table = document
.root()
.first_child()
.ok_or_else(|| XlsxError::Xml("Corrupt XML structure".to_string()))?;
let name = table
.attribute("name")
.ok_or_else(|| XlsxError::Xml("Corrupt XML structure: missing table name".to_string()))?
.to_string();
let display_name = table
.attribute("name")
.ok_or_else(|| {
XlsxError::Xml("Corrupt XML structure: missing table display name".to_string())
})?
.to_string();
let reference = table
.attribute("ref")
.ok_or_else(|| XlsxError::Xml("Corrupt XML structure: missing table ref".to_string()))?
.to_string();
let totals_row_count = match table.attribute("totalsRowCount") {
Some(s) => s.parse::<u32>().map_err(|_| {
XlsxError::Xml("Corrupt XML structure: Invalid totalsRowCount".to_string())
})?,
None => 0,
};
let header_row_count = match table.attribute("headerRowCount") {
Some(s) => s.parse::<u32>().map_err(|_| {
XlsxError::Xml("Corrupt XML structure: Invalid headerRowCount".to_string())
})?,
None => 1,
};
let header_row_dxf_id = if let Some(index_str) = table.attribute("headerRowDxfId") {
index_str.parse::<u32>().ok()
} else {
None
};
let data_dxf_id = if let Some(index_str) = table.attribute("headerRowDxfId") {
index_str.parse::<u32>().ok()
} else {
None
};
let totals_row_dxf_id = if let Some(index_str) = table.attribute("totalsRowDxfId") {
index_str.parse::<u32>().ok()
} else {
None
};
let auto_filter = table
.descendants()
.filter(|n| n.has_tag_name("autoFilter"))
.collect::<Vec<Node>>();
let has_filters = if let Some(filter) = auto_filter.first() {
filter.children().count() > 0
} else {
false
};
let table_column = table
.descendants()
.filter(|n| n.has_tag_name("tableColumn"))
.collect::<Vec<Node>>();
let mut columns = Vec::new();
for table_column in table_column {
let column_name = table_column.attribute("name").ok_or_else(|| {
XlsxError::Xml("Corrupt XML structure: missing column name".to_string())
})?;
let id = table_column.attribute("id").ok_or_else(|| {
XlsxError::Xml("Corrupt XML structure: missing column id".to_string())
})?;
let id = id
.parse::<u32>()
.map_err(|_| XlsxError::Xml("Corrupt XML structure: invalid id".to_string()))?;
let header_row_dxf_id = if let Some(index_str) = table_column.attribute("headerRowDxfId") {
index_str.parse::<u32>().ok()
} else {
None
};
let data_dxf_id = if let Some(index_str) = table_column.attribute("headerRowDxfId") {
index_str.parse::<u32>().ok()
} else {
None
};
let totals_row_dxf_id = if let Some(index_str) = table_column.attribute("totalsRowDxfId") {
index_str.parse::<u32>().ok()
} else {
None
};
columns.push(TableColumn {
id,
name: column_name.to_string(),
totals_row_label: None,
header_row_dxf_id,
data_dxf_id,
totals_row_function: None,
totals_row_dxf_id,
});
}
let table_info = table
.descendants()
.filter(|n| n.has_tag_name("tableInfo"))
.collect::<Vec<Node>>();
let style_info = match table_info.first() {
Some(node) => {
let name = node.attribute("name").map(|s| s.to_string());
TableStyleInfo {
name,
show_first_column: get_bool_false(*node, "showFirstColumn"),
show_last_column: get_bool_false(*node, "showLastColumn"),
show_row_stripes: get_bool(*node, "showRowStripes"),
show_column_stripes: get_bool_false(*node, "showColumnStripes"),
}
}
None => TableStyleInfo {
name: None,
show_first_column: false,
show_last_column: false,
show_row_stripes: true,
show_column_stripes: false,
},
};
Ok(Table {
name,
display_name,
reference,
totals_row_count,
header_row_count,
header_row_dxf_id,
data_dxf_id,
totals_row_dxf_id,
columns,
style_info,
has_filters,
sheet_name: sheet_name.to_string(),
})
}