import win32com.client
# 导入 win32com.client 模块，用于操作 PowerPoint 的 COM 接口

import datetime
# 导入 datetime 模块，用于生成时间戳

import os
# 导入 os 模块，用于路径操作


def start_powerpoint():
    """
    启动 PowerPoint 应用程序并返回应用程序对象。
    
    思路:
        1. 使用 win32com.client.Dispatch 创建 PowerPoint.Application 对象。
        2. 捕获可能的异常，如果启动失败则打印错误信息。

    使用的方法和属性:
        - win32com.client.Dispatch(): 创建 PowerPoint 应用程序对象。
    """
    try:
        Application = win32com.client.Dispatch("PowerPoint.Application")
        # 创建 PowerPoint 应用程序对象
        return Application
        # 返回应用程序对象
    except Exception as e:
        # 捕获异常
        print(f"启动 PowerPoint 失败: {e}")
        # 打印错误信息
        return None
        # 返回 None


def create_new_presentation(app):
    """
    创建一个新的 PowerPoint 演示文稿并返回演示文稿对象。
    
    思路:
        1. 调用 PowerPoint 应用程序的 Presentations.Add 方法。
        2. 捕获可能的异常并打印错误信息。

    使用的方法和属性:
        - app.Presentations.Add(): 创建新的演示文稿对象。
    """
    if app:
        try:
            Presentation = app.Presentations.Add()
            # 创建新的演示文稿对象
            return Presentation
            # 返回演示文稿对象
        except Exception as e:
            # 捕获异常
            print(f"创建新的演示文稿失败: {e}")
            # 打印错误信息
            return None
            # 返回 None
    return None
    # 如果应用程序对象为空，直接返回 None


def add_slide_content(presentation, title_text, content_text):
    """
    向演示文稿添加一张幻灯片并设置标题和内容。
    
    思路:
        1. 使用 Slides.Add 方法添加新幻灯片。
        2. 遍历幻灯片的 Shapes 集合，设置标题和内容。
        3. 捕获可能的异常并打印错误信息。

    使用的方法和属性:
        - presentation.Slides.Add(): 添加新幻灯片。
        - slide.Shapes: 获取幻灯片的形状集合。
        - shape.TextFrame.Text: 设置形状的文本内容。
    """
    if presentation:
        try:
            Slide = presentation.Slides.Add(1, 12)
            # 添加一张新幻灯片，使用标题和内容版式
            
            for shape in Slide.Shapes:
                # 遍历幻灯片的形状集合
                
                if shape.Type == 1:
                    # 如果形状类型是标题框
                    shape.TextFrame.Text = title_text
                    # 设置标题文本
                    
                elif shape.Type == 2:
                    # 如果形状类型是内容框
                    shape.TextFrame.Text = content_text
                    # 设置内容文本
            
            return True
            # 返回 True 表示成功
        except Exception as e:
            # 捕获异常
            print(f"添加幻灯片内容失败: {e}")
            # 打印错误信息
            return False
            # 返回 False 表示失败
    return False
    # 如果演示文稿对象为空，直接返回 False


def add_page_numbers(presentation):
    """
    向演示文稿的所有幻灯片添加页码。
    
    思路:
        1. 遍历演示文稿中的每张幻灯片。
        2. 启用页眉页脚中的 SlideNumber 属性。
        3. 捕获可能的异常并打印错误信息。

    使用的方法和属性:
        - presentation.Slides: 获取所有幻灯片的集合。
        - slide.HeadersFooters.SlideNumber.Visible: 设置页码的可见性。
    """
    if presentation:
        try:
            for i in range(1, presentation.Slides.Count + 1):
                # 遍历演示文稿中的每张幻灯片
                
                slide = presentation.Slides(i)
                # 获取当前幻灯片
                
                headers_footers = slide.HeadersFooters
                # 获取页眉页脚对象
                
                headers_footers.SlideNumber.Visible = True
                # 启用页码的可见性
            
            return True
            # 返回 True 表示成功
        except Exception as e:
            # 捕获异常
            print(f"添加页码失败: {e}")
            # 打印错误信息
            return False
            # 返回 False 表示失败
    return False
    # 如果演示文稿对象为空，直接返回 False


def show_presentation(app):
    """
    在前台显示 PowerPoint 应用程序。
    
    思路:
        1. 设置 PowerPoint 应用程序的 Visible 属性为 True。
        2. 捕获可能的异常并打印错误信息。

    使用的方法和属性:
        - app.Visible: 设置 PowerPoint 应用程序的可见性。
    """
    if app:
        try:
            app.Visible = True
            # 设置应用程序为可见状态
            return True
            # 返回 True 表示成功
        except Exception as e:
            # 捕获异常
            print(f"显示 PowerPoint 失败: {e}")
            # 打印错误信息
            return False
            # 返回 False 表示失败
    return False
    # 如果应用程序对象为空，直接返回 False


def generate_filename(save_path):
    """
    生成带有时间戳的文件名。
    
    思路:
        1. 获取当前系统时间并格式化为时间戳。
        2. 拼接文件名和保存路径。

    使用的方法和属性:
        - datetime.datetime.now().strftime(): 格式化当前时间。
        - os.path.join(): 拼接路径和文件名。
    """
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    # 获取当前时间并格式化为时间戳
    
    filename = f"ppt_{timestamp}.pptx"
    # 生成文件名
    
    full_path = os.path.join(save_path, filename)
    # 拼接完整路径
    
    return full_path
    # 返回完整路径


def save_presentation(presentation, save_path):
    """
    保存演示文稿到指定路径，文件名包含时间戳。
    
    思路:
        1. 检查保存路径是否存在，不存在则创建。
        2. 调用 SaveAs 方法保存演示文稿。
        3. 捕获可能的异常并打印错误信息。

    使用的方法和属性:
        - os.makedirs(): 创建目录。
        - presentation.SaveAs(): 保存演示文稿。
    """
    if presentation:
        try:
            if not os.path.exists(save_path):
                # 检查保存路径是否存在
                os.makedirs(save_path)
                # 如果不存在则创建路径
            
            full_path = generate_filename(save_path)
            # 生成带时间戳的文件名
            
            presentation.SaveAs(full_path)
            # 保存演示文稿
            
            print(f"演示文稿已保存到: {full_path}")
            # 打印保存路径
            
            return True
            # 返回 True 表示成功
        except Exception as e:
            # 捕获异常
            print(f"保存演示文稿失败: {e}")
            # 打印错误信息
            return False
            # 返回 False 表示失败
    return False
    # 如果演示文稿对象为空，直接返回 False


def close_powerpoint(app, presentation=None):
    """
    关闭演示文稿并退出 PowerPoint 应用程序。
    
    思路:
        1. 如果演示文稿对象存在，调用 Close 方法关闭。
        2. 如果 PowerPoint 应用程序对象存在，调用 Quit 方法退出。
        3. 捕获可能的异常并打印错误信息。

    使用的方法和属性:
        - presentation.Close(): 关闭演示文稿。
        - app.Quit(): 退出 PowerPoint 应用程序。
    """
    if presentation:
        try:
            presentation.Close()
            # 关闭演示文稿
        except Exception as e:
            # 捕获异常
            print(f"关闭演示文稿失败: {e}")
            # 打印错误信息
    
    if app:
        try:
            app.Quit()
            # 退出 PowerPoint 应用程序
        except Exception as e:
            # 捕获异常
            print(f"退出 PowerPoint 失败: {e}")
            # 打印错误信息


def main():
    """
    主函数，协调各个模块完成创建和保存 PowerPoint 演示文稿的操作。
    
    思路:
        1. 启动 PowerPoint 应用程序。
        2. 创建新的演示文稿。
        3. 添加幻灯片和内容。
        4. 启用页码功能。
        5. 在前台显示 PowerPoint。
        6. 保存演示文稿到指定目录。
        7. 确保资源在操作完成后释放。

    使用的方法和属性:
        - start_powerpoint(): 启动 PowerPoint 应用程序。
        - create_new_presentation(): 创建新演示文稿。
        - add_slide_content(): 添加幻灯片内容。
        - add_page_numbers(): 启用页码功能。
        - show_presentation(): 显示 PowerPoint 应用程序。
        - save_presentation(): 保存演示文稿。
        - close_powerpoint(): 关闭 PowerPoint 和释放资源。
    """
    save_path = r"T:\ppt"
    # 设置保存路径
    
    title = "12345"
    # 设置幻灯片标题
    
    content = "45678"
    # 设置幻灯片内容

    app = start_powerpoint()
    # 启动 PowerPoint 应用程序

    if not app:
        return
        # 如果启动失败，退出程序

    presentation = create_new_presentation(app)
    # 创建新的演示文稿

    if not presentation:
        close_powerpoint(app)
        # 如果创建失败，释放资源
        return

    if not add_slide_content(presentation, title, content):
        close_powerpoint(app, presentation)
        # 如果添加幻灯片内容失败，释放资源
        return

    if not add_page_numbers(presentation):
        close_powerpoint(app, presentation)
        # 如果添加页码失败，释放资源
        return

    if not show_presentation(app):
        close_powerpoint(app, presentation)
        # 如果显示失败，释放资源
        return

    if not save_presentation(presentation, save_path):
        close_powerpoint(app, presentation)
        # 如果保存失败，释放资源
        return

    #close_powerpoint(app, presentation)
    # 关闭 PowerPoint 和释放资源（注释掉以保持演示文稿打开）


if __name__ == "__main__":
    main()
    # 程序入口，调用主函数