use crate::ooxml::opc::{OpcPackage, PackURI};
use crate::sheet::{Workbook as WorkbookTrait, Worksheet as WorksheetTrait, WorksheetIterator, Result as SheetResult};
use crate::ooxml::xlsx::{SharedStrings, Styles};
use super::worksheet::{Worksheet, WorksheetInfo, WorksheetIterator as XlsxWorksheetIterator};
use super::parsers::{workbook_parser, styles_parser};
pub struct Workbook {
package: OpcPackage,
worksheets: Vec<WorksheetInfo>,
active_sheet_index: usize,
shared_strings: SharedStrings,
styles: Styles,
}
impl Workbook {
pub fn new(package: OpcPackage) -> SheetResult<Self> {
let mut workbook = Workbook {
package,
worksheets: Vec::new(),
active_sheet_index: 0,
shared_strings: SharedStrings::new(),
styles: Styles::new(),
};
workbook.load_workbook_info()?;
workbook.load_shared_strings()?;
workbook.load_styles()?;
Ok(workbook)
}
fn load_workbook_info(&mut self) -> SheetResult<()> {
let workbook_uri = PackURI::new("/xl/workbook.xml")?;
let workbook_part = self.package.get_part(&workbook_uri)?;
let content = std::str::from_utf8(workbook_part.blob())?;
let (worksheets, active_sheet_index) = workbook_parser::parse_workbook_xml(content)?;
self.worksheets = worksheets;
self.active_sheet_index = active_sheet_index;
Ok(())
}
fn load_shared_strings(&mut self) -> SheetResult<()> {
let shared_strings_uri = PackURI::new("/xl/sharedStrings.xml")?;
if let Ok(shared_strings_part) = self.package.get_part(&shared_strings_uri) {
let content = std::str::from_utf8(shared_strings_part.blob())?;
self.shared_strings = SharedStrings::parse(content)?;
}
Ok(())
}
fn load_styles(&mut self) -> SheetResult<()> {
let styles_uri = PackURI::new("/xl/styles.xml")?;
if let Ok(styles_part) = self.package.get_part(&styles_uri) {
let content = std::str::from_utf8(styles_part.blob())?;
self.styles = styles_parser::parse_styles_xml(content)?;
}
Ok(())
}
fn get_worksheet(&self, index: usize) -> SheetResult<Worksheet<'_>> {
if index >= self.worksheets.len() {
return Err("Worksheet index out of bounds".into());
}
let info = &self.worksheets[index];
let mut worksheet = Worksheet::new(self, info.clone());
worksheet.load_data()?;
Ok(worksheet)
}
pub(crate) fn package(&self) -> &OpcPackage {
&self.package
}
pub(crate) fn shared_strings(&self) -> &SharedStrings {
&self.shared_strings
}
}
impl WorkbookTrait for Workbook {
fn active_worksheet(&self) -> SheetResult<Box<dyn WorksheetTrait + '_>> {
let worksheet = self.get_worksheet(self.active_sheet_index)?;
Ok(Box::new(worksheet))
}
fn worksheet_names(&self) -> Vec<String> {
self.worksheets.iter().map(|ws| ws.name.clone()).collect()
}
fn worksheet_by_name(&self, name: &str) -> SheetResult<Box<dyn WorksheetTrait + '_>> {
for (index, ws_info) in self.worksheets.iter().enumerate() {
if ws_info.name == name {
let worksheet = self.get_worksheet(index)?;
return Ok(Box::new(worksheet));
}
}
Err(format!("Worksheet '{}' not found", name).into())
}
fn worksheet_by_index(&self, index: usize) -> SheetResult<Box<dyn WorksheetTrait + '_>> {
let worksheet = self.get_worksheet(index)?;
Ok(Box::new(worksheet))
}
fn worksheets(&self) -> Box<dyn WorksheetIterator<'_> + '_> {
Box::new(XlsxWorksheetIterator::new(self.worksheets.clone(), self))
}
fn worksheet_count(&self) -> usize {
self.worksheets.len()
}
fn active_sheet_index(&self) -> usize {
self.active_sheet_index
}
}