office-rs 0.1.1

A Rust library for reading and writing XML Office files
Documentation
use quick_xml::Error as XmlError;
use serde_json::Error as JsonError;
use std::error::Error;
use std::io;
use thiserror::Error;
use zip::result::ZipError;

pub use category::ErrorCategory;
pub use category::ErrorSeverity;
pub use format::file::FileError;
pub use format::parse::ParseError;
pub use format::xlsx::XlsxError;
pub use format::docx::DocxError;
pub use format::pptx::PptxError;

use crate::code::RecoverySuggestion;
use crate::error::code::*; // 导入所有错误码类型
use crate::error::monitor::{ ErrorMonitor, ErrorStats };
use crate::error::code::RecoveryAction;
use crate::error::context::ErrorContext;
use crate::error::monitor::error_monitor;

pub mod mod_backup;
pub mod category;
pub mod format;
pub mod code;
pub mod context;
pub mod monitor;

/// 带上下文的文档错误类型
#[derive(Error, Debug)]
pub enum OfficeError {
    /// IO错误
    #[error("IO错误: {0}")]
    Io(#[from] io::Error),

    /// ZIP文件错误
    #[error("ZIP文件错误: {0}")]
    Zip(#[from] ZipError),

    /// XML解析错误
    #[error("XML解析错误: {0}")]
    Xml(#[from] XmlError),

    /// JSON序列化错误
    #[error("JSON错误: {0}")]
    Json(#[from] JsonError),

    /// 编码错误
    #[error("编码错误: {0}")]
    Encoding(#[from] std::string::FromUtf8Error),

    /// 文件相关错误
    #[error("文件错误: {0}")]
    File(#[from] FileError),

    /// 解析相关错误
    #[error("解析错误: {0}")]
    Parse(#[from] ParseError),

    /// Excel特定错误
    #[error("Excel错误: {0}")]
    Xlsx(#[from] XlsxError),

    /// Word特定错误
    #[error("Word错误: {0}")]
    Docx(#[from] DocxError),

    /// PowerPoint特定错误
    #[error("PowerPoint错误: {0}")]
    Pptx(#[from] PptxError),

    /// 格式错误
    #[error("格式错误: {0}")]
    Format(String),

    /// 不支持的文件类型
    #[error("不支持的文件类型: {0}")]
    UnsupportedFormat(String),

    /// 文档结构错误
    #[error("文档结构错误: {0}")]
    Structure(String),

    /// 其他错误
    #[error("其他错误: {0}")]
    Other(String),

    /// 带上下文的错误
    #[error("{error}\n上下文: {context:?}")]
    WithContext {
        error: Box<OfficeError>,
        context: ErrorContext,
    },
}

impl OfficeError {
    /// 创建带上下文的文件未找到错误
    pub fn file_not_found_with_context(path: String, context: ErrorContext) -> Self {
        Self::File(FileError::NotFound { path }).with_context(context)
    }

    /// 创建带上下文的解析错误
    pub fn parse_error_with_context(element: String, context: ErrorContext) -> Self {
        Self::Parse(ParseError::MissingElement { element }).with_context(context)
    }

    /// 创建带上下文的Excel错误
    pub fn xlsx_error_with_context(name: String, context: ErrorContext) -> Self {
        Self::Xlsx(XlsxError::WorksheetNotFound { name }).with_context(context)
    }

    /// 记录错误到监控器
    pub fn record(&self) -> &Self {
        error_monitor().record_error(self);
        self
    }

    /// 创建错误并自动记录
    pub fn new_and_record(error: OfficeError) -> Self {
        error_monitor().record_error(&error);
        error
    }
    /// 获取错误严重程度
    pub fn severity(&self) -> ErrorSeverity {
        match self {
            Self::Io(_) => ErrorSeverity::Fatal,
            Self::Zip(_) => ErrorSeverity::Fatal,
            Self::Xml(_) => ErrorSeverity::Error,
            Self::Json(_) => ErrorSeverity::Error,
            Self::Encoding(_) => ErrorSeverity::Error,
            Self::File(FileError::NotFound { .. }) => ErrorSeverity::Fatal,
            Self::File(FileError::PermissionDenied { .. }) => ErrorSeverity::Fatal,
            Self::File(FileError::Corrupted { .. }) => ErrorSeverity::Fatal,
            Self::File(FileError::InvalidFormat { .. }) => ErrorSeverity::Error,
            Self::Parse(_) => ErrorSeverity::Error,
            Self::Xlsx(_) => ErrorSeverity::Error,
            Self::Docx(_) => ErrorSeverity::Error,
            Self::Pptx(_) => ErrorSeverity::Error,
            Self::Format(_) => ErrorSeverity::Error,
            Self::UnsupportedFormat(_) => ErrorSeverity::Fatal,
            Self::Structure(_) => ErrorSeverity::Warning,
            Self::Other(_) => ErrorSeverity::Error,
            Self::WithContext { error, .. } => error.severity(),
        }
    }

    /// 获取错误分类
    pub fn category(&self) -> ErrorCategory {
        match self {
            Self::Io(_) | Self::File(_) => ErrorCategory::FileSystem,
            Self::Zip(_) => ErrorCategory::FileSystem,
            Self::Xml(_) | Self::Json(_) | Self::Encoding(_) => ErrorCategory::Parsing,
            Self::Parse(_) => ErrorCategory::Parsing,
            Self::Xlsx(_) | Self::Docx(_) | Self::Pptx(_) => ErrorCategory::Validation,
            Self::Format(_) | Self::Structure(_) => ErrorCategory::Validation,
            Self::UnsupportedFormat(_) => ErrorCategory::Parsing,
            Self::Other(_) => ErrorCategory::Internal,
            Self::WithContext { error, .. } => error.category(),
        }
    }

    /// 获取错误码
    pub fn error_code(&self) -> ErrorCode {
        match self {
            // 系统级错误(IO、文件系统等)
            Self::Io(_) => ErrorCode::System(SystemErrorCode::IoError),
            Self::Zip(_) => ErrorCode::System(SystemErrorCode::ZipError),
            Self::File(FileError::NotFound { .. }) => ErrorCode::System(SystemErrorCode::NotFound),
            Self::File(FileError::PermissionDenied { .. }) =>
                ErrorCode::System(SystemErrorCode::PermissionDenied),
            Self::File(FileError::Corrupted { .. }) =>
                ErrorCode::System(SystemErrorCode::Corrupted),
            Self::File(FileError::InvalidFormat { .. }) =>
                ErrorCode::Format(FormatErrorCode::InvalidFormat),

            // 解析错误
            Self::Xml(_) => ErrorCode::Parse(ParseErrorCode::Xml),
            Self::Json(_) => ErrorCode::Parse(ParseErrorCode::Json),
            Self::Encoding(_) => ErrorCode::Parse(ParseErrorCode::Encoding),
            Self::Parse(parse_err) =>
                match parse_err {
                    ParseError::MissingElement { .. } =>
                        ErrorCode::Parse(ParseErrorCode::MissingElement),
                    ParseError::InvalidAttribute { .. } =>
                        ErrorCode::Parse(ParseErrorCode::InvalidAttribute),
                    ParseError::UnsupportedVersion { .. } =>
                        ErrorCode::Parse(ParseErrorCode::UnsupportedVersion),
                    ParseError::InvalidNamespace { .. } =>
                        ErrorCode::Parse(ParseErrorCode::InvalidNamespace),
                }

            // Excel相关错误
            Self::Xlsx(xlsx_err) =>
                match xlsx_err {
                    XlsxError::WorksheetNotFound { .. } =>
                        ErrorCode::Document(DocumentErrorCode::XlsxWorksheetNotFound),
                    XlsxError::InvalidCellReference { .. } =>
                        ErrorCode::Document(DocumentErrorCode::XlsxInvalidCellReference),
                    XlsxError::InvalidFormula { .. } =>
                        ErrorCode::Document(DocumentErrorCode::XlsxInvalidFormula),
                    XlsxError::InvalidStyleId { .. } =>
                        ErrorCode::Document(DocumentErrorCode::XlsxInvalidStyle),
                    XlsxError::SharedStringIndexOutOfRange { .. } =>
                        ErrorCode::Format(FormatErrorCode::OutOfRange),
                    XlsxError::WorksheetCreationFailed { .. } =>
                        ErrorCode::Document(DocumentErrorCode::XlsxWorksheetNotFound),
                }

            // Word相关错误
            Self::Docx(docx_err) =>
                match docx_err {
                    DocxError::StyleNotFound { .. } =>
                        ErrorCode::Document(DocumentErrorCode::DocxStyleNotFound),
                    DocxError::InvalidTableStructure =>
                        ErrorCode::Document(DocumentErrorCode::DocxInvalidTableStructure),
                    DocxError::InvalidParagraphFormat { .. } =>
                        ErrorCode::Document(DocumentErrorCode::DocxInvalidParagraph),
                    DocxError::BookmarkNotFound { .. } =>
                        ErrorCode::Document(DocumentErrorCode::DocxBookmarkNotFound),
                }

            // PowerPoint相关错误
            Self::Pptx(_) => ErrorCode::Document(DocumentErrorCode::PptxInvalidPresentation),

            // 通用错误
            Self::Format(_) => ErrorCode::Format(FormatErrorCode::InvalidFormat),
            Self::UnsupportedFormat(_) => ErrorCode::Format(FormatErrorCode::UnsupportedFormat),
            Self::Structure(_) => ErrorCode::Common(CommonErrorCode::InvalidOperation),
            Self::Other(_) => ErrorCode::Common(CommonErrorCode::UnknownError),

            // 带上下文的错误
            Self::WithContext { error, .. } => error.error_code(),
        }
    }

    /// 判断错误是否可恢复
    pub fn is_recoverable(&self) -> bool {
        matches!(self.severity(), ErrorSeverity::Warning | ErrorSeverity::Error)
    }

    /// 添加错误上下文
    pub fn with_context(self, context: ErrorContext) -> Self {
        let error_with_context = Self::WithContext {
            error: Box::new(self),
            context,
        };
        // 记录带上下文的错误
        error_monitor().record_error(&error_with_context);
        error_with_context
    }

    /// 获取错误上下文
    pub fn context(&self) -> Option<&ErrorContext> {
        match self {
            Self::WithContext { context, .. } => Some(context),
            _ => None,
        }
    }

    /// 获取根错误(去除上下文包装)
    pub fn root_error(&self) -> &OfficeError {
        match self {
            Self::WithContext { error, .. } => error.root_error(),
            _ => self,
        }
    }

    /// 获取错误恢复建议
    pub fn recovery_suggestion(&self) -> Option<RecoverySuggestion> {
        match self.root_error() {
            Self::File(FileError::NotFound { path }) =>
                Some(RecoverySuggestion {
                    message: format!("检查文件路径是否正确: {}", path),
                    action: RecoveryAction::UserInput("请提供正确的文件路径".to_string()),
                }),
            Self::File(FileError::PermissionDenied { path }) =>
                Some(RecoverySuggestion {
                    message: format!("检查文件权限: {}", path),
                    action: RecoveryAction::UserInput("请确保有足够的文件访问权限".to_string()),
                }),
            Self::Xlsx(XlsxError::WorksheetNotFound { name }) =>
                Some(RecoverySuggestion {
                    message: format!("工作表 '{}' 不存在,可以使用默认工作表", name),
                    action: RecoveryAction::UseDefault,
                }),
            Self::Xlsx(XlsxError::InvalidCellReference { reference }) =>
                Some(RecoverySuggestion {
                    message: format!("单元格引用 '{}' 无效,跳过此单元格", reference),
                    action: RecoveryAction::SkipElement,
                }),
            Self::Docx(DocxError::StyleNotFound { style_id }) =>
                Some(RecoverySuggestion {
                    message: format!("样式 '{}' 不存在,使用默认样式", style_id),
                    action: RecoveryAction::UseDefault,
                }),
            Self::Pptx(PptxError::SlideNotFound { slide_id }) =>
                Some(RecoverySuggestion {
                    message: format!("幻灯片 '{}' 不存在,跳过此幻灯片", slide_id),
                    action: RecoveryAction::SkipElement,
                }),
            Self::Structure(_) =>
                Some(RecoverySuggestion {
                    message: "文档结构异常,但可以继续处理".to_string(),
                    action: RecoveryAction::SkipElement,
                }),
            Self::Io(_) | Self::Zip(_) | Self::UnsupportedFormat(_) =>
                Some(RecoverySuggestion {
                    message: "致命错误,无法恢复".to_string(),
                    action: RecoveryAction::None,
                }),
            _ =>
                Some(RecoverySuggestion {
                    message: "可以重试操作".to_string(),
                    action: RecoveryAction::Retry(3),
                }),
        }
    }

    /// 获取错误链
    pub fn error_chain(&self) -> Vec<&dyn std::error::Error> {
        let mut chain = vec![self as &dyn std::error::Error];
        let mut source = self.source();
        while let Some(err) = source {
            chain.push(err);
            source = err.source();
        }
        chain
    }

    /// 获取根因错误
    pub fn root_cause(&self) -> &dyn std::error::Error {
        self.error_chain().into_iter().last().unwrap()
    }

    pub fn try_recover(&self, strategy: RecoveryStrategy) -> Result<()> {
        // 实现恢复逻辑

        match strategy.operation {
            RecoveryAction::Retry(times) => {
                for _ in 0..times {
                    // 尝试重试操作
                    if self.is_recoverable() {
                        return Ok(());
                    }
                }
                Err(Self::Other("重试失败".to_string()))
            }
            RecoveryAction::Fallback(fallback) => {
                // 执行降级方案
                println!("执行降级方案: {}", fallback);
                todo!("Implement fallback logic");
                Ok(())
            }
            RecoveryAction::Ignore => Ok(()),
            _ => { Ok(()) }
        }
    }
}

/// 简化的结果类型
pub type Result<T> = std::result::Result<T, OfficeError>;