use super::driver::*;
use super::XlsxError;
use crate::helper::const_str::*;
use crate::structs::Cell;
use crate::structs::SharedStringTable;
use crate::structs::Stylesheet;
use crate::structs::Worksheet;
use crate::structs::WriterManager;
use quick_xml::events::{BytesDecl, Event};
use quick_xml::Writer;
use std::collections::HashMap;
use std::io;
use std::sync::Arc;
use std::sync::RwLock;
pub(crate) fn write<W: io::Seek + io::Write>(
sheet_no: &i32,
worksheet: &Worksheet,
shared_string_table: &RwLock<SharedStringTable>,
stylesheet: &mut Stylesheet,
has_macros: bool,
writer_mng: &mut WriterManager<W>,
) -> Result<(), XlsxError> {
let mut writer = Writer::new(io::Cursor::new(Vec::new()));
writer.write_event(Event::Decl(BytesDecl::new(
"1.0",
Some("UTF-8"),
Some("yes"),
)));
write_new_line(&mut writer);
write_start_tag(
&mut writer,
"worksheet",
vec![
("xmlns", SHEET_MAIN_NS),
("xmlns:r", REL_OFC_NS),
("xmlns:xdr", SHEET_DRAWING_NS),
("xmlns:x14", SHEET_MS_MAIN_NS),
("xmlns:mc", MC_NS),
("mc:Ignorable", "x14ac"),
("xmlns:x14ac", SHEETML_AC_NS),
],
false,
);
let mut attributes: Vec<(&str, &str)> = Vec::new();
if has_macros {
let code_name = match worksheet.has_code_name() {
true => worksheet.get_code_name().as_ref().unwrap(),
false => worksheet.get_name(),
};
attributes.push(("codeName", code_name));
}
match worksheet.get_tab_color() {
Some(v) => {
write_start_tag(&mut writer, "sheetPr", attributes, false);
v.write_to_tab_color(&mut writer);
write_end_tag(&mut writer, "sheetPr");
}
None => {
if !attributes.is_empty() {
write_start_tag(&mut writer, "sheetPr", attributes, true);
}
}
}
write_start_tag(
&mut writer,
"dimension",
vec![("ref", &worksheet.calculate_worksheet_dimension())],
true,
);
worksheet.get_sheets_views().write_to(&mut writer);
worksheet
.get_sheet_format_properties()
.write_to(&mut writer);
let mut column_dimensions = worksheet.get_column_dimensions_crate().clone();
column_dimensions.calculation_auto_width(
worksheet.get_cell_collection_crate(),
worksheet.get_merge_cells_crate(),
);
column_dimensions.write_to(&mut writer, stylesheet);
let has_sheet_data = worksheet.has_sheet_data();
write_start_tag(&mut writer, "sheetData", vec![], !has_sheet_data);
let mut row_dimensions = worksheet.get_row_dimensions();
row_dimensions.sort_by(|a, b| a.get_row_num().cmp(b.get_row_num()));
let mut cells = worksheet.get_cell_collection_sorted();
let mut formula_shared_list: HashMap<&u32, (String, Option<String>)> = HashMap::new();
for cell in &cells {
if let Some(si) = cell.get_formula_shared_index() {
match formula_shared_list.get(si) {
Some((start_cell, _)) => {
formula_shared_list.insert(
si,
(
start_cell.clone(),
Some(cell.get_coordinate().get_coordinate()),
),
);
}
None => {
formula_shared_list.insert(si, (cell.get_coordinate().get_coordinate(), None));
}
}
}
}
let mut cells_iter = cells.iter().peekable();
for row in &row_dimensions {
let mut cells_in_row: Vec<&Cell> = Vec::new();
while let Some(cell) = cells_iter.peek() {
if row.get_row_num() != cell.get_coordinate().get_row_num() {
break;
}
cells_in_row.push(cells_iter.next().unwrap());
}
if cells_in_row.is_empty() {
let spans = "0:0";
row.write_to(&mut writer, stylesheet, spans, true);
} else {
let (first_num, last_num) = (
cells_in_row.first().unwrap().get_coordinate().get_col_num(),
cells_in_row.last().unwrap().get_coordinate().get_col_num(),
);
let spans = format!("{first_num}:{last_num}");
row.write_to(&mut writer, stylesheet, &spans, false);
for cell in cells_in_row {
cell.write_to(
&mut writer,
&shared_string_table,
stylesheet,
&formula_shared_list,
);
}
write_end_tag(&mut writer, "row");
}
}
if has_sheet_data {
write_end_tag(&mut writer, "sheetData");
}
if let Some(v) = worksheet.get_sheet_protection() {
v.write_to(&mut writer);
}
if let Some(v) = worksheet.get_auto_filter() {
write_start_tag(
&mut writer,
"autoFilter",
vec![("ref", &v.get_range().get_range())],
true,
);
}
worksheet.get_merge_cells_crate().write_to(&mut writer);
write_start_tag(&mut writer, "phoneticPr", vec![("fontId", "1")], true);
for conditional_formatting in worksheet.get_conditional_formatting_collection() {
conditional_formatting.write_to(&mut writer, stylesheet.get_differential_formats_mut());
}
if let Some(v) = worksheet.get_data_validations() {
v.write_to(&mut writer);
}
let mut r_id = 1;
if worksheet.has_hyperlink() {
write_start_tag(&mut writer, "hyperlinks", vec![], false);
for (coordition, hyperlink) in worksheet.get_hyperlink_collection() {
let r_id_str = format!("rId{}", &r_id);
let mut attributes: Vec<(&str, &str)> = Vec::new();
attributes.push(("ref", &coordition));
if *hyperlink.get_location() {
attributes.push(("location", hyperlink.get_url()));
} else {
attributes.push(("r:id", &r_id_str));
r_id += 1;
}
write_start_tag(&mut writer, "hyperlink", attributes, true);
}
write_end_tag(&mut writer, "hyperlinks");
}
worksheet.get_print_options().write_to(&mut writer);
worksheet.get_page_margins().write_to(&mut writer);
if worksheet.get_page_setup().has_param() {
worksheet.get_page_setup().write_to(&mut writer, &mut r_id);
}
worksheet.get_header_footer().write_to(&mut writer);
worksheet.get_row_breaks().write_to(&mut writer);
worksheet.get_column_breaks().write_to(&mut writer);
if worksheet.has_drawing_object() {
let r_id_str = format!("rId{}", &r_id);
write_start_tag(&mut writer, "drawing", vec![("r:id", &r_id_str)], true);
r_id += 1;
}
if worksheet.has_legacy_drawing() {
let r_id_str = format!("rId{}", &r_id);
write_start_tag(
&mut writer,
"legacyDrawing",
vec![("r:id", &r_id_str)],
true,
);
r_id += 1;
}
if worksheet.has_table() {
let tables = worksheet.get_tables();
write_start_tag(
&mut writer,
"tableParts",
vec![("count", &tables.len().to_string())],
false,
);
for table in worksheet.get_tables().iter() {
let r_id_str = format!("rId{}", &r_id);
write_start_tag(&mut writer, "tablePart", vec![("r:id", &r_id_str)], true);
r_id += 1;
}
write_end_tag(&mut writer, "tableParts");
}
let ole_id = 1000 + 25;
worksheet
.get_ole_objects()
.write_to(&mut writer, &r_id, &ole_id);
if worksheet.get_data_validations_2010().is_some() {
write_start_tag(&mut writer, "extLst", vec![], false);
match worksheet.get_data_validations_2010() {
Some(v) => {
v.write_to(&mut writer);
}
None => {}
}
write_end_tag(&mut writer, "extLst");
}
write_end_tag(&mut writer, "worksheet");
let target = format!("{PKG_SHEET}{}.xml", sheet_no);
writer_mng.add_writer(&target, writer)
}