use crate::writer::{Result, XmlWriter};
use std::io::Write;
use xlsbye_core::types::{SheetVisibility, WorkbookMeta};
use xlsbye_core::xml_names::{RELATIONSHIPS_NS, SPREADSHEET_NS};
pub fn write_workbook(writer: impl Write, meta: &WorkbookMeta, is_xlsm: bool) -> Result<()> {
let mut writer = XmlWriter::new(writer);
let defined_names = filtered_defined_names(meta);
writer.write_xml_declaration()?;
writer.write_start_element_with_ns(
"workbook",
[("", SPREADSHEET_NS), ("r", RELATIONSHIPS_NS)],
std::iter::empty::<(&str, &str)>(),
)?;
let date1904 = if meta.date1904 { "true" } else { "false" };
let mut workbook_pr_attrs = vec![("date1904".to_string(), date1904.to_string())];
if is_xlsm || meta.has_vba {
workbook_pr_attrs.push(("codeName".to_string(), "ThisWorkbook".to_string()));
}
writer.write_empty_element("workbookPr", workbook_pr_attrs)?;
writer.write_start_element("sheets", std::iter::empty::<(&str, &str)>())?;
for sheet in &meta.sheets {
let mut attrs = vec![
("name".to_string(), sheet.name.clone()),
("sheetId".to_string(), sheet.sheet_id.to_string()),
("r:id".to_string(), sheet.rel_id.clone()),
];
match sheet.state {
SheetVisibility::Visible => {}
SheetVisibility::Hidden => attrs.push(("state".to_string(), "hidden".to_string())),
SheetVisibility::VeryHidden => {
attrs.push(("state".to_string(), "veryHidden".to_string()))
}
}
writer.write_empty_element("sheet", attrs)?;
}
writer.write_end_element("sheets")?;
if !defined_names.is_empty() {
writer.write_start_element("definedNames", std::iter::empty::<(&str, &str)>())?;
for defined_name in defined_names {
let mut attrs = vec![("name".to_string(), defined_name.name.clone())];
if let Some(sheet_index) = defined_name.sheet_index {
attrs.push(("localSheetId".to_string(), sheet_index.to_string()));
}
if defined_name.hidden {
attrs.push(("hidden".to_string(), "1".to_string()));
}
writer.write_text_element("definedName", attrs, &defined_name.formula)?;
}
writer.write_end_element("definedNames")?;
}
writer.write_end_element("workbook")?;
Ok(())
}
fn filtered_defined_names<'a>(meta: &'a WorkbookMeta) -> Vec<&'a xlsbye_core::types::DefinedName> {
meta.defined_names
.iter()
.filter(|defined_name| !defined_name.name.starts_with("_xlfn."))
.filter(|defined_name| !defined_name.formula.trim().is_empty())
.filter(|defined_name| match defined_name.sheet_index {
Some(sheet_index) => (sheet_index as usize) < meta.sheets.len(),
None => true,
})
.collect()
}