office-rs 0.1.1

A Rust library for reading and writing XML Office files
Documentation
//! Excel工作表模块
//! 提供工作表管理、单元格操作等功能

use crate::error::{ OfficeError, Result, XlsxError };
use crate::xlsx::cell::{ Cell, CellReference, CellValue };
use std::collections::HashMap;

/// 工作表维度信息
#[derive(Debug, Clone, PartialEq)]
pub struct WorksheetDimension {
    /// 最小行索引(0开始)
    pub min_row: u32,
    /// 最大行索引(0开始)
    pub max_row: u32,
    /// 最小列索引(0开始)
    pub min_column: u32,
    /// 最大列索引(0开始)
    pub max_column: u32,
}

/// 工作表属性
#[derive(Debug, Clone)]
pub struct WorksheetProperties {
    /// 工作表名称
    pub name: String,
    /// 是否隐藏
    pub hidden: bool,
    /// 选中状态
    pub selected: bool,
    /// 激活状态
    pub active: bool,
    /// 标签颜色
    pub tab_color: Option<String>,
}

/// Excel工作表
#[derive(Debug, Clone)]
pub struct Worksheet {
    /// 工作表属性
    pub properties: WorksheetProperties,
    /// 单元格数据(使用HashMap存储稀疏矩阵)
    cells: HashMap<(u32, u32), Cell>,
    /// 工作表维度
    dimension: Option<WorksheetDimension>,
    /// 共享字符串表索引
    shared_strings: Vec<String>,
}

impl WorksheetDimension {
    /// 创建新的维度信息
    pub fn new(min_row: u32, max_row: u32, min_column: u32, max_column: u32) -> Self {
        Self {
            min_row,
            max_row,
            min_column,
            max_column,
        }
    }

    /// 获取行数
    pub fn row_count(&self) -> u32 {
        if self.max_row >= self.min_row { self.max_row - self.min_row + 1 } else { 0 }
    }

    /// 获取列数
    pub fn column_count(&self) -> u32 {
        if self.max_column >= self.min_column { self.max_column - self.min_column + 1 } else { 0 }
    }

    /// 检查坐标是否在范围内
    pub fn contains(&self, row: u32, column: u32) -> bool {
        row >= self.min_row &&
            row <= self.max_row &&
            column >= self.min_column &&
            column <= self.max_column
    }
}

impl WorksheetProperties {
    /// 创建新的工作表属性
    pub fn new(name: String) -> Self {
        Self {
            name,
            hidden: false,
            selected: false,
            active: false,
            tab_color: None,
        }
    }

    /// 设置隐藏状态
    pub fn with_hidden(mut self, hidden: bool) -> Self {
        self.hidden = hidden;
        self
    }

    /// 设置选中状态
    pub fn with_selected(mut self, selected: bool) -> Self {
        self.selected = selected;
        self
    }

    /// 设置激活状态
    pub fn with_active(mut self, active: bool) -> Self {
        self.active = active;
        self
    }

    /// 设置标签颜色
    pub fn with_tab_color(mut self, color: String) -> Self {
        self.tab_color = Some(color);
        self
    }
}

impl Worksheet {
    /// 创建新的工作表
    pub fn new(name: String) -> Self {
        Self {
            properties: WorksheetProperties::new(name),
            cells: HashMap::new(),
            dimension: None,
            shared_strings: Vec::new(),
        }
    }

    /// 获取工作表名称
    pub fn name(&self) -> &str {
        &self.properties.name
    }

    /// 设置工作表名称
    pub fn set_name(&mut self, name: String) {
        self.properties.name = name;
    }

    /// 获取单元格
    pub fn get_cell(&self, row: u32, column: u32) -> Option<&Cell> {
        self.cells.get(&(row, column))
    }

    /// 获取单元格
    pub fn get_cell_mut(&mut self, row: u32, column: u32) -> Option<&mut Cell> {
        self.cells.get_mut(&(row, column))
    }

    /// 获取单元格(通过引用)
    pub fn get_cell_by_reference(&self, reference: &CellReference) -> Option<&Cell> {
        self.get_cell(reference.row, reference.column)
    }

    /// 设置单元格
    pub fn set_cell(&mut self, cell: Cell) {
        let row = cell.reference.row;
        let column = cell.reference.column;

        // 更新维度信息
        self.update_dimension(row, column);

        self.cells.insert((row, column), cell);
    }

    /// 设置单元格值
    pub fn set_cell_value(&mut self, row: u32, column: u32, value: CellValue) {
        let reference = CellReference::new(column, row);
        let cell = Cell::new(reference, value);
        self.set_cell(cell);
    }

    /// 设置单元格值(通过A1引用)
    pub fn set_cell_value_by_reference(&mut self, reference: &str, value: CellValue) -> Result<()> {
        let cell_ref = CellReference::from_a1(reference)?;
        self.set_cell_value(cell_ref.row, cell_ref.column, value);
        Ok(())
    }

    /// 删除单元格
    pub fn remove_cell(&mut self, row: u32, column: u32) -> Option<Cell> {
        let removed = self.cells.remove(&(row, column));

        // 如果删除了单元格,可能需要重新计算维度
        if removed.is_some() {
            self.recalculate_dimension();
        }

        removed
    }

    /// 获取所有单元格
    pub fn cells(&self) -> impl Iterator<Item = &Cell> {
        self.cells.values()
    }

    /// 获取指定行的所有单元格
    pub fn get_row(&self, row: u32) -> Vec<&Cell> {
        self.cells
            .values()
            .filter(|cell| cell.reference.row == row)
            .collect()
    }

    /// 获取指定列的所有单元格
    pub fn get_column(&self, column: u32) -> Vec<&Cell> {
        self.cells
            .values()
            .filter(|cell| cell.reference.column == column)
            .collect()
    }

    /// 获取工作表维度
    pub fn dimension(&self) -> Option<&WorksheetDimension> {
        self.dimension.as_ref()
    }

    /// 获取使用的行数
    pub fn used_row_count(&self) -> u32 {
        self.dimension.as_ref().map_or(0, |d| d.row_count())
    }

    /// 获取使用的列数
    pub fn used_column_count(&self) -> u32 {
        self.dimension.as_ref().map_or(0, |d| d.column_count())
    }

    /// 检查工作表是否为空
    pub fn is_empty(&self) -> bool {
        self.cells.is_empty()
    }

    /// 清空工作表
    pub fn clear(&mut self) {
        self.cells.clear();
        self.dimension = None;
    }

    /// 获取单元格数量
    pub fn cell_count(&self) -> usize {
        self.cells.len()
    }

    /// 更新维度信息
    fn update_dimension(&mut self, row: u32, column: u32) {
        match &mut self.dimension {
            Some(dim) => {
                dim.min_row = dim.min_row.min(row);
                dim.max_row = dim.max_row.max(row);
                dim.min_column = dim.min_column.min(column);
                dim.max_column = dim.max_column.max(column);
            }
            None => {
                self.dimension = Some(WorksheetDimension::new(row, row, column, column));
            }
        }
    }

    /// 重新计算维度信息
    fn recalculate_dimension(&mut self) {
        if self.cells.is_empty() {
            self.dimension = None;
            return;
        }

        let mut min_row = u32::MAX;
        let mut max_row = 0;
        let mut min_column = u32::MAX;
        let mut max_column = 0;

        for cell in self.cells.values() {
            min_row = min_row.min(cell.reference.row);
            max_row = max_row.max(cell.reference.row);
            min_column = min_column.min(cell.reference.column);
            max_column = max_column.max(cell.reference.column);
        }

        self.dimension = Some(WorksheetDimension::new(min_row, max_row, min_column, max_column));
    }

    /// 添加共享字符串
    pub fn add_shared_string(&mut self, text: String) -> usize {
        // 检查是否已存在
        if let Some(index) = self.shared_strings.iter().position(|s| s == &text) {
            return index;
        }

        // 添加新的共享字符串
        self.shared_strings.push(text);
        self.shared_strings.len() - 1
    }

    /// 获取共享字符串
    pub fn get_shared_string(&self, index: usize) -> Result<&str> {
        self.shared_strings
            .get(index)
            .map(|s| s.as_str())
            .ok_or_else(|| OfficeError::Xlsx(XlsxError::SharedStringIndexOutOfRange { index }))
    }

    /// 获取所有共享字符串
    pub fn shared_strings(&self) -> &[String] {
        &self.shared_strings
    }
}

impl Default for Worksheet {
    fn default() -> Self {
        Self::new("Sheet1".to_string())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::xlsx::cell::CellReference;

    #[test]
    fn test_worksheet_basic_operations() {
        let mut worksheet = Worksheet::new("Test Sheet".to_string());

        // 测试设置单元格值
        worksheet.set_cell_value(0, 0, CellValue::Text("Hello".to_string()));
        worksheet.set_cell_value(1, 1, CellValue::Number(42.0));

        // 测试获取单元格
        let cell = worksheet.get_cell(0, 0).unwrap();
        assert_eq!(cell.value, CellValue::Text("Hello".to_string()));

        // 测试维度
        let dim = worksheet.dimension().unwrap();
        assert_eq!(dim.min_row, 0);
        assert_eq!(dim.max_row, 1);
        assert_eq!(dim.min_column, 0);
        assert_eq!(dim.max_column, 1);
    }

    #[test]
    fn test_worksheet_a1_reference() {
        let mut worksheet = Worksheet::new("Test".to_string());

        // 使用A1引用设置值
        worksheet.set_cell_value_by_reference("A1", CellValue::Text("Test".to_string())).unwrap();
        worksheet.set_cell_value_by_reference("B2", CellValue::Number(100.0)).unwrap();

        // 验证值
        let cell_a1 = worksheet.get_cell(0, 0).unwrap();
        assert_eq!(cell_a1.value, CellValue::Text("Test".to_string()));

        let cell_b2 = worksheet.get_cell(1, 1).unwrap();
        assert_eq!(cell_b2.value, CellValue::Number(100.0));
    }

    #[test]
    fn test_shared_strings() {
        let mut worksheet = Worksheet::new("Test".to_string());

        // 添加共享字符串
        let index1 = worksheet.add_shared_string("Hello".to_string());
        let index2 = worksheet.add_shared_string("World".to_string());
        let index3 = worksheet.add_shared_string("Hello".to_string()); // 重复

        assert_eq!(index1, 0);
        assert_eq!(index2, 1);
        assert_eq!(index3, 0); // 应该返回已存在的索引

        // 获取共享字符串
        assert_eq!(worksheet.get_shared_string(0).unwrap(), "Hello");
        assert_eq!(worksheet.get_shared_string(1).unwrap(), "World");
    }
}