import tkinter as tk
from tkinter import ttk, messagebox
import re

# 数学公式数据库（结构化存储）
MATH_FORMULAS = {
    "代数": [
        {
            "名称": "一元二次方程求根公式",
            "公式": "x = [-b ± √(b² - 4ac)] / 2a",
            "说明": "对于ax² + bx + c = 0（a≠0），Δ = b² - 4ac 为判别式"
        },
        {
            "名称": "平方差公式",
            "公式": "a² - b² = (a + b)(a - b)",
            "说明": "两个数的平方差等于这两个数的和与差的积"
        },
        {
            "名称": "完全平方公式",
            "公式": "(a ± b)² = a² ± 2ab + b²",
            "说明": "两数和（差）的平方等于它们的平方和加上（减去）它们积的2倍"
        },
        {
            "名称": "立方和公式",
            "公式": "a³ + b³ = (a + b)(a² - ab + b²)",
            "说明": "两个数的立方和分解公式"
        },
        {
            "名称": "立方差公式",
            "公式": "a³ - b³ = (a - b)(a² + ab + b²)",
            "说明": "两个数的立方差分解公式"
        }
    ],
    "几何": [
        {
            "名称": "圆的周长与面积",
            "公式": "周长 C = 2πr，面积 S = πr²",
            "说明": "r为圆的半径，π≈3.1415926"
        },
        {
            "名称": "三角形面积",
            "公式": "S = (1/2)ah 或 S = √[p(p-a)(p-b)(p-c)]",
            "说明": "a为底，h为高；p=(a+b+c)/2（海伦公式）"
        },
        {
            "名称": "勾股定理",
            "公式": "a² + b² = c²",
            "说明": "直角三角形两直角边的平方和等于斜边的平方"
        },
        {
            "名称": "长方体体积与表面积",
            "公式": "体积 V = abc，表面积 S = 2(ab + bc + ac)",
            "说明": "a、b、c分别为长、宽、高"
        },
        {
            "名称": "球体体积与表面积",
            "公式": "体积 V = (4/3)πr³，表面积 S = 4πr²",
            "说明": "r为球的半径"
        }
    ],
    "三角函数": [
        {
            "名称": "正弦定理",
            "公式": "a/sinA = b/sinB = c/sinC = 2R",
            "说明": "R为三角形外接圆半径"
        },
        {
            "名称": "余弦定理",
            "公式": "c² = a² + b² - 2ab cosC",
            "说明": "已知两边及夹角求第三边"
        },
        {
            "名称": "同角三角函数基本关系",
            "公式": "sin²θ + cos²θ = 1，tanθ = sinθ/cosθ",
            "说明": "θ≠π/2 + kπ（k∈Z）"
        },
        {
            "名称": "两角和差公式",
            "公式": "sin(α±β)=sinαcosβ±cosαsinβ，cos(α±β)=cosαcosβ∓sinαsinβ",
            "说明": "正弦同号，余弦异号"
        },
        {
            "名称": "二倍角公式",
            "公式": "sin2θ=2sinθcosθ，cos2θ=cos²θ-sin²θ=2cos²θ-1=1-2sin²θ",
            "说明": "倍角公式的三种表达形式"
        }
    ],
    "微积分": [
        {
            "名称": "导数定义",
            "公式": "f'(x) = lim(Δx→0) [f(x+Δx) - f(x)]/Δx",
            "说明": "函数在某点的导数即该点的瞬时变化率"
        },
        {
            "名称": "基本导数公式",
            "公式": "(xⁿ)' = nxⁿ⁻¹，(sinx)' = cosx，(cosx)' = -sinx",
            "说明": "常用基本初等函数的导数"
        },
        {
            "名称": "积分定义",
            "公式": "∫[a,b]f(x)dx = lim(n→∞)Σ[i=1,n]f(ξi)Δxi",
            "说明": "定积分是黎曼和的极限"
        },
        {
            "名称": "牛顿-莱布尼茨公式",
            "公式": "∫[a,b]f(x)dx = F(b) - F(a)",
            "说明": "F(x)是f(x)的一个原函数"
        },
        {
            "名称": "分部积分公式",
            "公式": "∫u dv = uv - ∫v du",
            "说明": "适用于不同类型函数乘积的积分"
        }
    ],
    "概率统计": [
        {
            "名称": "排列数公式",
            "公式": "Aₙᵐ = n!/(n-m)!",
            "说明": "从n个元素中取出m个元素的排列数"
        },
        {
            "名称": "组合数公式",
            "公式": "Cₙᵐ = n!/[m!(n-m)!] = Cₙⁿ⁻ᵐ",
            "说明": "组合数具有对称性"
        },
        {
            "名称": "期望公式",
            "公式": "E(X) = ΣxᵢP(X=xᵢ) 或 ∫xf(x)dx",
            "说明": "离散型/连续型随机变量的数学期望"
        },
        {
            "名称": "方差公式",
            "公式": "D(X) = E(X²) - [E(X)]²",
            "说明": "方差等于平方的期望减去期望的平方"
        },
        {
            "名称": "正态分布概率密度",
            "公式": "f(x) = [1/(σ√(2π))]e^[-(x-μ)²/(2σ²)]",
            "说明": "μ为均值，σ为标准差"
        }
    ]
}

class MathFormulaQuery:
    def __init__(self, root):
        self.root = root
        self.root.title("数学公式查询工具")
        self.root.geometry("900x600")
        self.root.resizable(True, True)
        
        # 当前选中的分类
        self.current_category = tk.StringVar(value="代数")
        # 搜索关键词
        self.search_keyword = tk.StringVar()
        
        # 创建界面
        self.create_widgets()
        # 初始化显示代数公式
        self.update_formula_list("代数")
    
    def create_widgets(self):
        """创建所有界面组件"""
        # ========== 顶部搜索栏 ==========
        top_frame = tk.Frame(self.root, bg="#f0f0f0", padx=10, pady=8)
        top_frame.pack(fill="x")
        
        # 搜索标签和输入框
        ttk.Label(top_frame, text="搜索公式：", font=("微软雅黑", 11)).pack(side="left", padx=5)
        search_entry = ttk.Entry(
            top_frame, textvariable=self.search_keyword, 
            font=("微软雅黑", 11), width=30
        )
        search_entry.pack(side="left", padx=5, fill="x", expand=True)
        
        # 搜索按钮
        search_btn = tk.Button(
            top_frame, text="搜索", font=("微软雅黑", 11),
            bg="#2196F3", fg="white", padx=15,
            command=self.search_formulas
        )
        search_btn.pack(side="left", padx=5)
        
        # 重置按钮
        reset_btn = tk.Button(
            top_frame, text="重置", font=("微软雅黑", 11),
            bg="#f44336", fg="white", padx=15,
            command=self.reset_search
        )
        reset_btn.pack(side="left", padx=5)
        
        # ========== 主体区域（左右分栏） ==========
        main_frame = tk.Frame(self.root)
        main_frame.pack(fill="both", expand=True, padx=10, pady=10)
        
        # 左侧分类导航
        left_frame = tk.Frame(main_frame, width=180)
        left_frame.pack(side="left", fill="y", padx=(0, 10))
        
        # 分类标题
        category_label = ttk.Label(
            left_frame, text="公式分类", 
            font=("微软雅黑", 14, "bold")
        )
        category_label.pack(pady=8)
        
        # 分类按钮组
        category_buttons = []
        for category in MATH_FORMULAS.keys():
            btn = tk.Button(
                left_frame, text=category, font=("微软雅黑", 12),
                bg="#e0e0e0", fg="black",
                command=lambda c=category: self.update_formula_list(c),
                relief="flat", padx=5, pady=8
            )
            btn.pack(fill="x", pady=2)
            category_buttons.append((btn, category))
            
            # 设置选中状态的样式
            if category == self.current_category.get():
                btn.config(bg="#2196F3", fg="white")
        
        # 保存分类按钮引用，用于切换样式
        self.category_buttons = category_buttons
        
        # ========== 右侧公式展示区 ==========
        right_frame = tk.Frame(main_frame)
        right_frame.pack(side="right", fill="both", expand=True)
        
        # 公式列表区域（带滚动条）
        list_frame = tk.Frame(right_frame)
        list_frame.pack(fill="both", expand=True)
        
        # 公式列表
        self.formula_listbox = tk.Listbox(
            list_frame, font=("微软雅黑", 11),
            selectmode="single", bg="#f8f8f8"
        )
        scrollbar_y = ttk.Scrollbar(
            list_frame, orient="vertical", 
            command=self.formula_listbox.yview
        )
        self.formula_listbox.config(yscrollcommand=scrollbar_y.set)
        
        # 布局列表和滚动条
        self.formula_listbox.pack(side="left", fill="both", expand=True)
        scrollbar_y.pack(side="right", fill="y")
        
        # 绑定列表选中事件
        self.formula_listbox.bind("<<ListboxSelect>>", self.show_formula_detail)
        
        # 公式详情展示区
        detail_frame = tk.Frame(right_frame, bg="white", relief="solid", bd=1)
        detail_frame.pack(fill="x", pady=10, ipady=10, padx=5)
        
        # 详情标题
        self.detail_title = ttk.Label(
            detail_frame, text="公式详情", 
            font=("微软雅黑", 14, "bold"),
            background="white"
        )
        self.detail_title.pack(anchor="w", padx=15, pady=(0, 10))
        
        # 公式内容（高亮显示）
        self.formula_display = tk.Label(
            detail_frame, text="", font=("微软雅黑", 13),
            bg="#fff8e1", fg="#e65100",
            padx=15, pady=8, wraplength=600
        )
        self.formula_display.pack(fill="x", padx=15, pady=(0, 10))
        
        # 公式说明
        self.formula_note = ttk.Label(
            detail_frame, text="", font=("微软雅黑", 11),
            background="white", wraplength=600,
            justify="left", foreground="#424242"
        )
        self.formula_note.pack(anchor="w", padx=15, pady=(0, 10))
        
        # 复制按钮
        copy_btn = tk.Button(
            detail_frame, text="复制公式", font=("微软雅黑", 11),
            bg="#4CAF50", fg="white", padx=10,
            command=self.copy_formula
        )
        copy_btn.pack(anchor="e", padx=15, pady=5)
        
        # 保存当前选中的公式内容
        self.current_formula_text = ""
    
    def update_category_style(self, selected_category):
        """更新分类按钮的选中样式"""
        for btn, category in self.category_buttons:
            if category == selected_category:
                btn.config(bg="#2196F3", fg="white")
            else:
                btn.config(bg="#e0e0e0", fg="black")
    
    def update_formula_list(self, category):
        """更新公式列表"""
        # 更新选中分类
        self.current_category.set(category)
        self.update_category_style(category)
        
        # 清空列表
        self.formula_listbox.delete(0, tk.END)
        
        # 填充公式名称
        formulas = MATH_FORMULAS[category]
        for idx, formula in enumerate(formulas):
            self.formula_listbox.insert(idx, formula["名称"])
        
        # 清空详情展示
        self.formula_display.config(text="")
        self.formula_note.config(text="")
        self.current_formula_text = ""
    
    def show_formula_detail(self, event):
        """显示选中公式的详情"""
        # 获取选中的索引
        selected_indices = self.formula_listbox.curselection()
        if not selected_indices:
            return
        
        idx = selected_indices[0]
        category = self.current_category.get()
        formula = MATH_FORMULAS[category][idx]
        
        # 更新详情展示
        self.detail_title.config(text=f"公式详情：{formula['名称']}")
        self.formula_display.config(text=formula["公式"])
        self.formula_note.config(text=f"说明：{formula['说明']}")
        
        # 保存当前公式文本，用于复制
        self.current_formula_text = formula["公式"]
    
    def search_formulas(self):
        """搜索公式"""
        keyword = self.search_keyword.get().strip()
        if not keyword:
            messagebox.showwarning("提示", "请输入搜索关键词！")
            return
        
        # 遍历所有公式，匹配关键词
        matched_formulas = []
        for category, formulas in MATH_FORMULAS.items():
            for formula in formulas:
                # 在名称、公式、说明中搜索
                if (keyword in formula["名称"] or 
                    keyword in formula["公式"] or 
                    keyword in formula["说明"]):
                    matched_formulas.append((category, formula))
        
        if not matched_formulas:
            messagebox.showinfo("提示", f"未找到包含「{keyword}」的公式")
            return
        
        # 更新列表显示搜索结果
        self.formula_listbox.delete(0, tk.END)
        for idx, (category, formula) in enumerate(matched_formulas):
            self.formula_listbox.insert(idx, f"[{category}] {formula['名称']}")
        
        # 保存搜索结果，用于详情展示
        self.search_results = matched_formulas
        # 清空详情展示
        self.formula_display.config(text="")
        self.formula_note.config(text="")
        self.current_formula_text = ""
        
        # 重置分类按钮样式
        self.update_category_style("")
    
    def reset_search(self):
        """重置搜索，恢复分类视图"""
        self.search_keyword.set("")
        # 恢复显示当前分类的公式
        self.update_formula_list(self.current_category.get())
    
    def copy_formula(self):
        """复制当前公式到剪贴板"""
        if not self.current_formula_text:
            messagebox.showwarning("提示", "请先选择一个公式！")
            return
        
        try:
            # 清空剪贴板并设置内容
            self.root.clipboard_clear()
            self.root.clipboard_append(self.current_formula_text)
            self.root.update()  # 确保剪贴板内容生效
            messagebox.showinfo("成功", "公式已复制到剪贴板！")
        except:
            messagebox.showerror("错误", "复制失败，请手动复制！")

if __name__ == "__main__":
    root = tk.Tk()
    app = MathFormulaQuery(root)
    root.mainloop()