# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
import sys
import random
import json
import logging
from datetime import datetime

def resource_path(relative_path):
    """获取资源的绝对路径"""
    try:
        # PyInstaller创建临时文件夹,将路径存储在_MEIPASS中
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

class WinGUI(tk.Tk):
    def __init__(self):
        super().__init__()
        
        # 设置日志
        self.setup_logging()
        
        # 在__init__方法开头添加配置文件路径定义
        self.config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
        
        # 获取默认文件路径（优先使用上次的路径）
        default_file = self.get_last_file_path()
        
        # 先隐藏窗口
        self.withdraw()
        
        # 设置窗口属性
        self.title(f"RIME个性短语管理 - {default_file}")
        width = 900
        height = 600
        screenwidth = self.winfo_screenwidth()
        screenheight = self.winfo_screenheight()
        geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        self.geometry(geometry)
        self.resizable(width=True, height=True)
        self.minsize(900, 600)
        
        try:
            # 设置图标
            icon_path = "3232.ico"
            if hasattr(sys, '_MEIPASS'):
                icon_path = os.path.join(sys._MEIPASS, icon_path)
            self.iconbitmap(icon_path)
        except Exception as e:
            print(f"设置图标失败: {str(e)}")
        
        # 创建所有组件
        self.__init_components()
        
        # 加载五笔字典
        self.wubi_dict = self.load_wubi_dict()
        
        # 自动导入默认文件
        if os.path.exists(default_file):
            try:
                with open(default_file, 'r', encoding='utf-8') as file:
                    lines = file.readlines()
                    
                # 保存头部内容（前5行）
                self.header_lines = [
                    "# Rime table\n",
                    "# coding: utf-8\n",
                    "#@/db_name  custom_phrase.txt\n",
                    "#@/db_type\ttabledb\n",
                    "# no comment\n"
                ]
                
                # 处理短语（第6行开始）
                phrase_lines = lines[5:]
                # 使用集合去重
                unique_phrases = list(dict.fromkeys(phrase_lines))
                self.phrases = unique_phrases
                
                # 更新显示
                self.update_listbox()
                self.current_file = default_file
                self.title(f"RIME个性短语管理 - {default_file}")
                
                # 更新短语数量显示
                self.update_phrase_count()
            except Exception as e:
                messagebox.showerror("错误", f"自动导入文件时出错：{str(e)}")
        
        # 显示窗口
        self.deiconify()
        
        # 将窗口提到最前
        self.lift()
        self.focus_force()

    def setup_logging(self):
        """设置日志"""
        # 创建logs文件夹（如果不存在）
        log_dir = "logs"
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        
        # 生成日志文件名（使用当前日期）
        log_file = os.path.join(log_dir, f"rime_phrase_{datetime.now().strftime('%Y%m%d')}.log")
        
        # 配置日志
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file, encoding='utf-8'),
                logging.StreamHandler()
            ]
        )
        
        logging.info("程序启动")

    def __init_components(self):
        """初始化所有组件"""
        # 创建一个PanedWindow来替代原来的左右框架
        self.paned_window = ttk.PanedWindow(self, orient=tk.HORIZONTAL)
        self.paned_window.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建左右两个主框架
        self.left_frame = tk.Frame(self.paned_window)
        self.right_frame = tk.Frame(self.paned_window)
        
        # 将框架添加到PanedWindow
        self.paned_window.add(self.left_frame, weight=1)  # weight=1 表示拉伸时会调整大小
        self.paned_window.add(self.right_frame, weight=3)  # weight=3 表示右侧占比更大

        # 顶部按钮框架
        self.top_button_frame = tk.Frame(self.right_frame)
        self.top_button_frame.pack(side=tk.TOP, fill=tk.X, pady=(0, 10))
        
        # 初始化格式化模式
        self.current_format_mode = 1  # 默认值
        
        # 初始化组件
        self.__init_left_frame()
        self.__init_right_frame()
        
        # 加载格式化方案
        self.load_format_mode()

        # 存储导入的短语表
        self.phrases = []

        # 绑定按钮事件
        self.tk_button_m4dq9ipa.config(command=self.import_phrases)
        self.tk_button_m4dqam0l.config(command=self.save_phrases)
        self.tk_button_m4dqan02.config(command=self.save_as_phrases)
        self.tk_button_confirm.config(command=self.confirm_edit)
        self.tk_button_add.config(command=self.auto_recognize_2chars)
        self.tk_button_add3.config(command=self.auto_recognize_3chars)
        self.tk_button_add4.config(command=self.auto_recognize_4chars)
        self.tk_button_clear.config(command=self.clear_editor)
        self.tk_button_sort.config(command=self.sort_by_content)
        self.tk_button_add4_first.config(command=self.auto_recognize_4chars_first)
        self.tk_button_add_123.config(command=self.auto_recognize_123chars)
        self.tk_button_add_all.config(command=self.add_all_codes)

        # 创建右键菜单
        self.context_menu = tk.Menu(self, tearoff=0)
        self.context_menu.add_command(label="编辑", command=self.edit_phrase)
        self.context_menu.add_command(label="复制", command=self.copy_phrase)
        self.context_menu.add_command(label="删除", command=self.delete_phrase)
        
        # 绑定右键菜单事件
        self.tk_list_box_m4dq5pax.bind("<Button-3>", self.show_context_menu)

        # 在 __init__ 方法中添加一个变量来存储当前编辑的索引
        self.current_edit_index = None

        # 绑定文本框变化事件
        self.tk_text_m4dqbw6e.bind('<KeyRelease>', self.check_auto_fill_weight)
        self.tk_text_m4dqcl46.bind('<KeyRelease>', self.check_auto_fill_weight)
        
        # 绑定粘贴件
        self.tk_text_m4dqbw6e.bind('<<Paste>>', self.check_auto_fill_weight)
        self.tk_text_m4dqcl46.bind('<<Paste>>', self.check_auto_fill_weight)

        # 绑定双击事件
        self.tk_list_box_m4dq5pax.bind('<Double-Button-1>', self.on_double_click)

    def __init_left_frame(self):
        """初始化左侧框架"""
        # 左侧标签
        self.tk_label_m4dq7eub = tk.Label(self.left_frame, text="现在有的短语表", anchor="w")
        self.tk_label_m4dq7eub.pack(side=tk.TOP, fill=tk.X, pady=(0, 5))
        
        # 创建一个框架来容纳行号和列表框
        list_container = tk.Frame(self.left_frame)
        list_container.pack(fill=tk.BOTH, expand=True)
        
        # 创建行号列表框
        self.line_numbers = tk.Listbox(list_container,
                                      width=4,
                                      background="#f0f0f0",
                                      foreground="#606366",
                                      borderwidth=0,
                                      justify=tk.RIGHT,
                                      font=('TkFixedFont', 10),
                                      selectmode=tk.SINGLE,
                                      selectbackground='#0078D7',
                                      selectforeground='white')
        self.line_numbers.pack(side=tk.LEFT, fill=tk.Y)
        
        # 创建内容列表框
        self.tk_list_box_m4dq5pax = tk.Listbox(list_container,
                                              selectmode=tk.SINGLE,
                                              font=('TkFixedFont', 10),
                                              activestyle='none',
                                              exportselection=False,
                                              selectbackground='#0078D7',
                                              selectforeground='white')
        
        # 创建垂直滚动条
        scrollbar_y = ttk.Scrollbar(list_container, orient="vertical",
                                   command=self.on_scroll)
        
        # 设置列表框的滚动条
        self.tk_list_box_m4dq5pax.configure(yscrollcommand=scrollbar_y.set)
        self.line_numbers.configure(yscrollcommand=scrollbar_y.set)
        
        # 放置组件
        scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)
        self.tk_list_box_m4dq5pax.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # 绑定事件
        self.tk_list_box_m4dq5pax.bind('<<ListboxSelect>>', self.on_select)
        self.tk_list_box_m4dq5pax.bind('<Double-Button-1>', self.on_double_click)
        self.tk_list_box_m4dq5pax.bind('<Button-3>', self.show_context_menu)
        self.line_numbers.bind('<<ListboxSelect>>', lambda e: 'break')

    def on_scroll(self, *args):
        """同步滚动两个列表框"""
        self.tk_list_box_m4dq5pax.yview(*args)
        self.line_numbers.yview(*args)

    def update_line_numbers(self, event=None):
        """更新行号显示"""
        self.line_numbers.delete(0, tk.END)
        count = self.tk_list_box_m4dq5pax.size()
        
        # 更新行号
        for i in range(count):
            self.line_numbers.insert(tk.END, f" {str(i+1).rjust(3)}")
        
        # 同步选中状态
        selection = self.tk_list_box_m4dq5pax.curselection()
        if selection:
            self.line_numbers.selection_set(selection[0])

    def __init_right_frame(self):
        # 顶部按钮
        self.tk_button_m4dq9ipa = tk.Button(self.top_button_frame, text="导入", takefocus=False)
        self.tk_button_m4dq9ipa.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_m4dqam0l = tk.Button(self.top_button_frame, text="保存", takefocus=False)
        self.tk_button_m4dqam0l.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_m4dqan02 = tk.Button(self.top_button_frame, text="另存为", takefocus=False)
        self.tk_button_m4dqan02.pack(side=tk.LEFT, padx=5)
        
        # 添加格式化方案选择按钮
        self.format_var = tk.IntVar(value=1)  # 默认选中第一种方案
        
        format_frame = tk.Frame(self.top_button_frame)
        format_frame.pack(side=tk.LEFT, padx=20)
        
        self.rb_format1 = tk.Radiobutton(format_frame, text="所有行不加空格", 
                                        variable=self.format_var, value=1,
                                        command=self.change_format_mode)
        self.rb_format1.pack(side=tk.LEFT, padx=5)
        
        self.rb_format2 = tk.Radiobutton(format_frame, text="所有行前加空格", 
                                        variable=self.format_var, value=2,
                                        command=self.change_format_mode)
        self.rb_format2.pack(side=tk.LEFT, padx=5)
        
        self.rb_format3 = tk.Radiobutton(format_frame, text="首行以外加空格", 
                                        variable=self.format_var, value=3,
                                        command=self.change_format_mode)
        self.rb_format3.pack(side=tk.LEFT, padx=5)
        
        # 修改这部分：将确认修改、清空编辑和一键整理放在同一排
        control_frame = tk.Frame(self.right_frame)
        control_frame.pack(fill=tk.X, pady=10)
        
        # 左侧按钮组
        left_buttons = tk.Frame(control_frame)
        left_buttons.pack(side=tk.LEFT)
        
        self.tk_button_confirm = tk.Button(left_buttons, text="确认修改", takefocus=False)
        self.tk_button_confirm.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_clear = tk.Button(left_buttons, text="清空编辑", takefocus=False)
        self.tk_button_clear.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_sort = tk.Button(left_buttons, text="一键整理", takefocus=False)
        self.tk_button_sort.pack(side=tk.LEFT, padx=5)
        
        # 添加新按钮
        self.tk_button_add_all = tk.Button(left_buttons, text="添加本条所有键码", takefocus=False)
        self.tk_button_add_all.pack(side=tk.LEFT, padx=5)
        
        # 右侧状态显示
        self.status_label = tk.Label(control_frame, text="", font=("Segoe UI", 12))
        self.status_label.pack(side=tk.RIGHT, padx=5)
        
        self.tk_label_count = tk.Label(control_frame, text="共 0 条短语")
        self.tk_label_count.pack(side=tk.RIGHT)
        
        # 输入区域
        input_frame = tk.Frame(self.right_frame)
        input_frame.pack(fill=tk.X, pady=10)
        
        # 输入码和权重
        code_weight_frame = tk.Frame(input_frame)
        code_weight_frame.pack(fill=tk.X)
        
        # 输入码部分
        code_frame = tk.Frame(code_weight_frame)
        code_frame.pack(side=tk.LEFT, padx=(0, 20))
        self.tk_label_m4dqcua8 = tk.Label(code_frame, text="输入码")
        self.tk_label_m4dqcua8.pack(side=tk.LEFT)
        self.tk_text_m4dqcl46 = tk.Text(code_frame, height=1, width=15)
        self.tk_text_m4dqcl46.pack(side=tk.LEFT, padx=5)
        
        # 权重部分
        weight_frame = tk.Frame(code_weight_frame)
        weight_frame.pack(side=tk.LEFT)
        self.tk_label_m4dqdsho = tk.Label(weight_frame, text="权重")
        self.tk_label_m4dqdsho.pack(side=tk.LEFT)
        self.tk_text_m4dqdwff = tk.Text(weight_frame, height=1, width=15)
        self.tk_text_m4dqdwff.pack(side=tk.LEFT, padx=5)
        
        # 识别按钮组
        button_frame = tk.Frame(input_frame)
        button_frame.pack(fill=tk.X, pady=10)
        
        self.tk_button_add = tk.Button(button_frame, text="识别头2字4键", takefocus=False)
        self.tk_button_add.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_add3 = tk.Button(button_frame, text="识别头3字6键", takefocus=False)
        self.tk_button_add3.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_add4_first = tk.Button(button_frame, text="识别头4字4键", takefocus=False)
        self.tk_button_add4_first.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_add4 = tk.Button(button_frame, text="识别头4字8键", takefocus=False)
        self.tk_button_add4.pack(side=tk.LEFT, padx=5)
        
        self.tk_button_add_123 = tk.Button(button_frame, text="识别123码6键", takefocus=False)
        self.tk_button_add_123.pack(side=tk.LEFT, padx=5)
        
        # 大文本框
        text_frame = tk.Frame(self.right_frame)
        text_frame.pack(fill=tk.BOTH, expand=True)
        
        self.tk_text_m4dqbw6e = tk.Text(text_frame)
        scrollbar = ttk.Scrollbar(text_frame, orient="vertical", command=self.tk_text_m4dqbw6e.yview)
        
        self.tk_text_m4dqbw6e.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.tk_text_m4dqbw6e.configure(yscrollcommand=scrollbar.set)

    def scrollbar_autohide(self,vbar, hbar, widget):
        """自动隐藏动条"""
        def show():
            if vbar: vbar.lift(widget)
            if hbar: hbar.lift(widget)
        def hide():
            if vbar: vbar.lower(widget)
            if hbar: hbar.lower(widget)
        hide()
        widget.bind("<Enter>", lambda e: show())
        if vbar: vbar.bind("<Enter>", lambda e: show())
        if vbar: vbar.bind("<Leave>", lambda e: hide())
        if hbar: hbar.bind("<Enter>", lambda e: show())
        if hbar: hbar.bind("<Leave>", lambda e: hide())
        widget.bind("<Leave>", lambda e: hide())
    
    def v_scrollbar(self,vbar, widget, x, y, w, h, pw, ph):
        widget.configure(yscrollcommand=vbar.set)
        vbar.config(command=widget.yview)
        vbar.place(relx=(w + x) / pw, rely=y / ph, relheight=h / ph, anchor='ne')

    def h_scrollbar(self,hbar, widget, x, y, w, h, pw, ph):
        widget.configure(xscrollcommand=hbar.set)
        hbar.config(command=widget.xview)
        hbar.place(relx=x / pw, rely=(y + h) / ph, relwidth=w / pw, anchor='sw')

    def create_bar(self, master, widget, is_vbar, is_hbar, x, y, w, h, pw, ph):
        vbar, hbar = None, None
        if is_vbar:
            vbar = ttk.Scrollbar(master)
            self.v_scrollbar(vbar, widget, x, y, w, h, pw, ph)
        if is_hbar:
            hbar = ttk.Scrollbar(master, orient="horizontal")
            self.h_scrollbar(hbar, widget, x, y, w, h, pw, ph)
        self.scrollbar_autohide(vbar, hbar, widget)

    def import_phrases(self):
        """导入短语"""
        file_path = filedialog.askopenfilename(
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")])
        
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    lines = file.readlines()
                    
                # 保存头部内容（前5行）
                self.header_lines = [
                    "# Rime table\n",
                    "# coding: utf-8\n",
                    "#@/db_name  custom_phrase.txt\n",
                    "#@/db_type\ttabledb\n",
                    "# no comment\n"
                ]
                
                # 处理短语（第6行开始）
                phrase_lines = lines[5:]
                # 使用集合去重
                unique_phrases = list(dict.fromkeys(phrase_lines))
                self.phrases = unique_phrases
                
                # 更新显示
                self.update_listbox()
                self.current_file = file_path
                self.title(f"RIME个性短语管理 - {file_path}")
                
                # 更新短语数量显示
                self.update_phrase_count()
                
                messagebox.showinfo("成功", "短语导入成功！")
                
                logging.info(f"导入文件：{file_path}，共 {len(self.phrases)} 条短语")
                
            except Exception as e:
                error_msg = f"导入文件时出错：{str(e)}"
                logging.error(error_msg)
                messagebox.showerror("错误", error_msg)

    def remove_empty_lines(self):
        """删除多余行"""
        # 过滤掉空行只包含空白字符的行
        filtered_phrases = []
        for phrase in self.phrases:
            if phrase.strip():  # 如果行不空的或只包含空白字符
                filtered_phrases.append(phrase)
        self.phrases = filtered_phrases

    def remove_duplicates(self):
        """去除重复的输入码，保留最后一个"""
        # 创建一个字典来存储每个输入码对应的最后一个短语
        code_dict = {}
        for phrase in self.phrases:
            parts = phrase.strip().split('\t')
            if len(parts) == 3:
                text, code, weight = parts
                code_dict[code] = phrase  # 如果输入码重复，会覆盖之前的短语
        
        # 将字典中的短语换回列表
        self.phrases = list(code_dict.values())

    def save_phrases(self):
        """保存短语"""
        try:
            # 如果没有文件路径，调用另存为
            if not hasattr(self, 'current_file'):
                self.save_as_phrases()
                return
            
            # 除多余的空行
            self.remove_empty_lines()
            # 去除重复的输入码
            self.remove_duplicates()
            
            # 有当前文件路径则直接保存
            with open(self.current_file, 'w', encoding='utf-8') as file:
                # 写入头部信息
                file.writelines(self.header_lines)
                # 写入短语
                file.writelines(self.phrases)
            
            # 更新列表显示
            self.update_listbox()
            # 更新状态栏显示并显示成功图标
            self.update_phrase_count()
            self.show_status(True)
            
            # 保存成功后，更新配置文件
            self.save_last_file_path()
            
            logging.info(f"保存文件：{self.current_file}，共 {len(self.phrases)} 条短语")
            
        except Exception as e:
            # 显示错误信息失败图标
            messagebox.showerror("错误", f"保存文件时出错：{str(e)}")
            self.show_status(False)
            # 保存出错时也调用另存为
            self.save_as_phrases()

    def save_as_phrases(self):
        """另存为"""
        try:
            file_path = filedialog.asksaveasfilename(
                defaultextension=".txt",
                filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
            )
            
            if file_path:
                # 删除多余的行
                self.remove_empty_lines()
                # 去除重复的输入码
                self.remove_duplicates()
                
                with open(file_path, 'w', encoding='utf-8') as file:
                    # 写入头部信息
                    file.writelines(self.header_lines)
                    # 写入短语
                    file.writelines(self.phrases)
                
                # 更新当前文件路径
                self.current_file = file_path
                self.title(f"RIME个性短语管理 - {file_path}")
                # 更新列表显示
                self.update_listbox()
                # 更新状态栏显示并显示成功图标
                self.update_phrase_count()
                self.show_status(True)
                
                # 保存成功后，更新配置文件
                self.save_last_file_path()
                
        except Exception as e:
            messagebox.showerror("错误", f"保存文件时出错：{str(e)}")
            self.show_status(False)

    def update_listbox(self):
        """更新列表框显示"""
        self.tk_list_box_m4dq5pax.delete(0, tk.END)
        self.line_numbers.delete(0, tk.END)
        
        # 插入内容和行号
        for i, phrase in enumerate(self.phrases, 1):
            self.tk_list_box_m4dq5pax.insert(tk.END, phrase.strip())  # 去除多余的换行符
            self.line_numbers.insert(tk.END, f" {str(i).rjust(3)}")  # 左边加空格，数字右对齐

    def on_select(self, event):
        """处理单击事件 - 只高亮显示"""
        selection = self.tk_list_box_m4dq5pax.curselection()
        if selection:
            index = selection[0]
            
            # 高亮显示列表内容
            self.tk_list_box_m4dq5pax.selection_clear(0, tk.END)
            self.tk_list_box_m4dq5pax.selection_set(index)
            self.tk_list_box_m4dq5pax.see(index)
            
            # 高亮显示行号
            self.line_numbers.selection_clear(0, tk.END)
            self.line_numbers.selection_set(index)
            self.line_numbers.see(index)

    def highlight_line_number(self, index):
        """高亮显示选中行的行号"""
        self.line_numbers.configure(state='normal')
        # 清除所有标签
        self.line_numbers.tag_remove('highlight', '1.0', tk.END)
        
        # 计算行的位置
        start = f"{index + 1}.0"
        end = f"{index + 1}.end"
        
        # 添加高亮标签
        self.line_numbers.tag_add('highlight', start, end + '+1c')
        self.line_numbers.tag_config('highlight', 
                                   background='#0078D7',  # 与列表框选中颜色相同
                                   foreground='white')
        
        self.line_numbers.configure(state='disabled')

    def format_text(self, text):
        """格式化文本：根据前方案处理缩进和特殊字符"""
        if not text:
            return text
        
        # 先处理所有的空白字符
        text = text.strip()
        
        if not text:
            return ''
        
        # 查找最后一个数字作为权重
        parts = text.split()
        if parts and parts[-1].isdigit():
            text = ' '.join(parts[:-1])
        
        # 处理换行
        lines = text.split('\n')
        formatted_lines = []
        
        for i, line in enumerate(lines):
            line = line.strip()
            if line:
                if self.current_format_mode == 1:  # 所有行不加空格
                    formatted_lines.append(line)
                elif self.current_format_mode == 2:  # 所有行前加空格
                    formatted_lines.append('　　' + line)
                elif self.current_format_mode == 3:  # 首行以外加空格
                    if i == 0:
                        formatted_lines.append(line)
                    else:
                        formatted_lines.append('　　' + line)
        
        # 使用 U+2029 连接所有行
        text = '\u2029'.join(formatted_lines)
        
        # 处理行内空格
        text = text.replace('\t', '　')  # 制表符替换为全角空格
        text = text.replace('    ', '　')  # 4个半角空格替换为全角空格
        text = text.replace('  ', '　')  # 2个半角空格替换为全角空格
        
        return text

    def update_phrase_count(self):
        """更新短语数量显示"""
        total_count = len(self.phrases)
        
        # 统计不重复的文本内容数量
        unique_texts = set()
        for phrase in self.phrases:
            parts = phrase.strip().split('\t')
            if len(parts) >= 1:
                unique_texts.add(parts[0])  # 只添加文本内容部分
        
        unique_count = len(unique_texts)
        
        # 更新显示，同时显示总数和不重复内容数
        self.tk_label_count.config(text=f"共 {total_count} 条短语，不重复内容 {unique_count} 条")

    def show_context_menu(self, event):
        """显示右键菜单"""
        try:
            # 获取鼠标右键点击的置对应项目引
            index = self.tk_list_box_m4dq5pax.nearest(event.y)
            # 确保有选中项目
            if index >= 0:
                self.tk_list_box_m4dq5pax.selection_clear(0, tk.END)
                self.tk_list_box_m4dq5pax.selection_set(index)
                self.tk_list_box_m4dq5pax.activate(index)
                # 显示右键菜单
                self.context_menu.post(event.x_root, event.y_root)
        except:
            pass

    def edit_phrase(self):
        """编辑选中的短语"""
        selection = self.tk_list_box_m4dq5pax.curselection()
        if selection:
            # 保存当前编辑的
            self.current_edit_index = selection[0]
            phrase = self.phrases[self.current_edit_index]
            # 清空右侧文本
            self.tk_text_m4dqbw6e.delete(1.0, tk.END)
            self.tk_text_m4dqcl46.delete(1.0, tk.END)
            self.tk_text_m4dqdwff.delete(1.0, tk.END)
            
            # 解析短语格式（格式为text\tcode\tweight）
            parts = phrase.strip().split('\t')
            if len(parts) == 3:
                text, code, weight = parts
                self.tk_text_m4dqbw6e.insert(tk.END, text)  # 大文本框显示文本内容
                self.tk_text_m4dqcl46.insert(tk.END, code)  # 输入码本框显示打码
                self.tk_text_m4dqdwff.insert(tk.END, weight)  # 权重文本框显示权重
            else:
                # 解析失败，直接显示整个短语
                self.tk_text_m4dqbw6e.insert(tk.END, phrase)
                messagebox.showerror("错误", "短语格式不正确！")

    def delete_phrase(self):
        """删除选的短语"""
        selection = self.tk_list_box_m4dq5pax.curselection()
        if selection:
            index = selection[0]
            phrase = self.phrases[index].strip()
            del self.phrases[index]
            self.update_listbox()
            logging.info(f"删除短语：{phrase}")

    def check_auto_fill_weight(self, event=None):
        """检查并自动填充权重"""
        text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
        code = self.tk_text_m4dqcl46.get("1.0", "end-1c").strip()
        weight = self.tk_text_m4dqdwff.get("1.0", "end-1c").strip()
        
        # 如果文本和入码都有，但权重为空，则自动填入3
        if text and code and not weight:
            self.tk_text_m4dqdwff.delete("1.0", tk.END)
            self.tk_text_m4dqdwff.insert("1.0", "3")

    def get_valid_chars(self, text, count):
        """获取指定数量的有效字
        Args:
            text: 输入的文本
            count: 需要的汉字数量
        Returns:
            valid_chars: 有效的汉字列表
        """
        valid_chars = []
        for char in text:
            # 判断是否是汉字（Unicode范围：\u4e00-\u9fff）
            if '\u4e00' <= char <= '\u9fff':
                valid_chars.append(char)
                if len(valid_chars) == count:
                    break
        return valid_chars

    def auto_recognize_2chars(self):
        """识别前2个字的编码（每字取前2码）"""
        try:
            text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
            if not text:
                messagebox.showwarning("警告", "请先输入文本内容！")
                return

            # 获取2个有效汉字
            valid_chars = self.get_valid_chars(text, 2)
            if len(valid_chars) < 2:
                messagebox.showwarning("警告", "文本内容至少需要2个汉字")
                return

            # 获取这两个字的五笔码
            codes = []
            for char in valid_chars:
                if char in self.wubi_dict:
                    codes.append(self.wubi_dict[char])
                else:
                    messagebox.showwarning("警告", f"未找到字符 '{char}' 的五笔编码！")
                    return

            # 组合编码（每个字取前两码）
            combined_code = codes[0][:2] + codes[1][:2]

            # 填入输入码文本框
            self.tk_text_m4dqcl46.delete("1.0", tk.END)
            self.tk_text_m4dqcl46.insert("1.0", combined_code)

            # 自动填充权重3
            self.tk_text_m4dqdwff.delete("1.0", tk.END)
            self.tk_text_m4dqdwff.insert("1.0", "3")

        except Exception as e:
            messagebox.showerror("错误", f"自动识别失败：{str(e)}")

    def auto_recognize_3chars(self):
        """识别前3个字的编码（每字取前2码）"""
        try:
            text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
            if not text:
                messagebox.showwarning("警告", "请���输入文本内容！")
                return

            # 获取3个有效汉字
            valid_chars = self.get_valid_chars(text, 3)
            if len(valid_chars) < 3:
                messagebox.showwarning("警告", "文本内容至少需要3个汉字")
                return

            # 获取这三个字的五笔码
            codes = []
            for char in valid_chars:
                if char in self.wubi_dict:
                    codes.append(self.wubi_dict[char])
                else:
                    messagebox.showwarning("警告", f"未找到字符 '{char}' 的五笔编码！")
                    return

            # 组合编码（每个字取前两码）
            combined_code = codes[0][:2] + codes[1][:2] + codes[2][:2]

            # 填入输入码文本框
            self.tk_text_m4dqcl46.delete("1.0", tk.END)
            self.tk_text_m4dqcl46.insert("1.0", combined_code)

            # 自动填充权重3
            self.tk_text_m4dqdwff.delete("1.0", tk.END)
            self.tk_text_m4dqdwff.insert("1.0", "3")

        except Exception as e:
            messagebox.showerror("错误", f"自动识别失败：{str(e)}")

    def auto_recognize_4chars(self):
        """识别前4个字的编码（每字取前2码）"""
        try:
            text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
            if not text:
                messagebox.showwarning("警告", "请先输入文本内容！")
                return

            # 获取4个有效汉字
            valid_chars = self.get_valid_chars(text, 4)
            if len(valid_chars) < 4:
                messagebox.showwarning("警告", "文本内容至少需要4个汉字")
                return

            # 获取这四个字的五笔码
            codes = []
            for char in valid_chars:
                if char in self.wubi_dict:
                    codes.append(self.wubi_dict[char])
                else:
                    messagebox.showwarning("警告", f"未找到字符 '{char}' 的五笔编码！")
                    return

            # 组合编码（每个字取前两码）
            combined_code = codes[0][:2] + codes[1][:2] + codes[2][:2] + codes[3][:2]

            # 填入输入码文本框
            self.tk_text_m4dqcl46.delete("1.0", tk.END)
            self.tk_text_m4dqcl46.insert("1.0", combined_code)

            # 自动填充权重3
            self.tk_text_m4dqdwff.delete("1.0", tk.END)
            self.tk_text_m4dqdwff.insert("1.0", "3")

        except Exception as e:
            messagebox.showerror("错误", f"自动识别失败：{str(e)}")

    def auto_recognize_4chars_first(self):
        """识别前4个字的编码（每字取第1码）"""
        try:
            text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
            if not text:
                messagebox.showwarning("警告", "请先输入文本内容！")
                return

            # 获取4个有效汉字
            valid_chars = self.get_valid_chars(text, 4)
            if len(valid_chars) < 4:
                messagebox.showwarning("警告", "文本内容至少要4个汉字")
                return

            # 获取这四个字的五笔码
            codes = []
            for char in valid_chars:
                if char in self.wubi_dict:
                    codes.append(self.wubi_dict[char])
                else:
                    messagebox.showwarning("警告", f"未找到字符 '{char}' 的五笔编码！")
                    return

            # 组合编码（每个字取第一码）
            combined_code = codes[0][0] + codes[1][0] + codes[2][0] + codes[3][0]

            # 填入输入码文本框
            self.tk_text_m4dqcl46.delete("1.0", tk.END)
            self.tk_text_m4dqcl46.insert("1.0", combined_code)

            # 自动填充权重3
            self.tk_text_m4dqdwff.delete("1.0", tk.END)
            self.tk_text_m4dqdwff.insert("1.0", "3")

        except Exception as e:
            messagebox.showerror("错误", f"自动识别失败：{str(e)}")

    def auto_recognize_123chars(self):
        """识别前3个字的编码（第1字取1码，第2字取2码，第3字取3码）"""
        try:
            text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
            if not text:
                messagebox.showwarning("警告", "请先输入文本内容！")
                return

            # 获取3个有效汉字
            valid_chars = self.get_valid_chars(text, 3)
            if len(valid_chars) < 3:
                messagebox.showwarning("警告", "文本内容至少需要3个汉字")
                return

            # 获取这三个字的五笔码
            codes = []
            for char in valid_chars:
                if char in self.wubi_dict:
                    codes.append(self.wubi_dict[char])
                else:
                    messagebox.showwarning("警告", f"未找到字符 '{char}' 的五笔编码！")
                    return

            # 组合编码（第1字取1码，第2字取2码，第3字取3码）
            combined_code = (codes[0][0] +                # 第1字取1码
                        codes[1][:2] +                # 第2字取2码
                        codes[2][:3])                 # 第3字取3码

            # 填入输入码文本框
            self.tk_text_m4dqcl46.delete("1.0", tk.END)
            self.tk_text_m4dqcl46.insert("1.0", combined_code)

            # 自动填充权重3
            self.tk_text_m4dqdwff.delete("1.0", tk.END)
            self.tk_text_m4dqdwff.insert("1.0", "3")

        except Exception as e:
            messagebox.showerror("错误", f"自动识别失败：{str(e)}")

    def confirm_edit(self):
        """确认修改或添加"""
        try:
            # 获取输入内容
            text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
            code = self.tk_text_m4dqcl46.get("1.0", "end-1c").strip()
            weight = self.tk_text_m4dqdwff.get("1.0", "end-1c").strip()
            
            # 检查必要字段
            if not text or not code:
                messagebox.showerror("错误", "文本内容和输入码不能为空！")
                return
            
            # 格式化文本
            text = self.format_text(text)
            
            # 如果权重为空，自动填充为3
            if not weight:
                weight = "3"
            
            # 统一���用相同的格式，不管是修改还是新添加
            new_phrase = f"{text}\t{code}\t{weight}\n"
            
            if hasattr(self, 'current_edit_index') and self.current_edit_index is not None:
                # 修改现有短语
                self.phrases[self.current_edit_index] = new_phrase
                # 更新列表显示
                self.tk_list_box_m4dq5pax.delete(self.current_edit_index)
                self.tk_list_box_m4dq5pax.insert(self.current_edit_index, new_phrase)
                # 持选中状态
                self.tk_list_box_m4dq5pax.selection_set(self.current_edit_index)
                self.current_edit_index = None  # 重置编辑索引
                # 更新状态栏显示并显示成功图标
                self.tk_label_count.config(text=f"共 {len(self.phrases)} 条短语 - 修改成功")
                self.show_status(True)
                logging.info(f"修改短语：{text} -> {code} (权重：{weight})")
            else:
                # 添加新短语
                self.phrases.append(new_phrase)
                # 更新列表显示
                self.tk_list_box_m4dq5pax.insert(tk.END, new_phrase)
                # 更新状态显示并显示成功图标
                self.tk_label_count.config(text=f"共 {len(self.phrases)} 条短语 - 添加成��")
                self.show_status(True)
                logging.info(f"添加短语：{text} -> {code} (权重：{weight})")
            
            # 清空输入
            self.tk_text_m4dqbw6e.delete("1.0", tk.END)
            self.tk_text_m4dqcl46.delete("1.0", tk.END)
            self.tk_text_m4dqdwff.delete("1.0", tk.END)
            
            # 自动执行存功能
            self.save_phrases()
            
        except Exception as e:
            error_msg = f"操作失败：{str(e)}"
            logging.error(error_msg)
            messagebox.showerror("错误", error_msg)
            self.show_status(False)

    def clear_editor(self):
        """清空编辑器"""
        self.tk_text_m4dqbw6e.delete("1.0", tk.END)  # 清空文本容
        self.tk_text_m4dqcl46.delete("1.0", tk.END)  # 清输入码
        self.tk_text_m4dqdwff.delete("1.0", tk.END)  # 清空权重
        self.current_edit_index = None  # 重置编辑索引

    def on_double_click(self, event):
        """处理双击事件 - 高亮显示并加载到编辑区"""
        selection = self.tk_list_box_m4dq5pax.curselection()
        if selection:
            index = selection[0]
            self.current_edit_index = index
            
            # 高亮显示列表内容
            self.tk_list_box_m4dq5pax.selection_clear(0, tk.END)
            self.tk_list_box_m4dq5pax.selection_set(index)
            self.tk_list_box_m4dq5pax.see(index)
            
            # 高亮显示行号
            self.line_numbers.selection_clear(0, tk.END)
            self.line_numbers.selection_set(index)
            self.line_numbers.see(index)
            
            # 加载到编辑区
            phrase = self.phrases[index].strip()
            # 清空右侧文本
            self.tk_text_m4dqbw6e.delete(1.0, tk.END)
            self.tk_text_m4dqcl46.delete(1.0, tk.END)
            self.tk_text_m4dqdwff.delete(1.0, tk.END)
            
            # 分割短语
            parts = phrase.split('\t')
            if len(parts) >= 2:
                self.tk_text_m4dqbw6e.insert(1.0, parts[0])
                self.tk_text_m4dqcl46.insert(1.0, parts[1])
                if len(parts) >= 3:
                    self.tk_text_m4dqdwff.insert(1.0, parts[2].strip())

    def load_wubi_dict(self):
        """加载笔编码字典"""
        wubi_dict = {}
        try:
            # 获取五笔码表文件的路径（支持打包后的路径）
            wubi_path = "wubi86.txt"
            if hasattr(sys, '_MEIPASS'):
                wubi_path = os.path.join(sys._MEIPASS, "wubi86.txt")
            
            # 尝试文���加载五笔码表
            with open(wubi_path, 'r', encoding='utf-8') as f:
                for line in f:
                    # 跳过空和注释行
                    if not line.strip() or line.startswith('#'):
                        continue
                    
                    parts = line.strip().split('\t')
                    if len(parts) >= 2:  # 确保至少有字符和编码两列
                        char, code = parts[0], parts[1]  # 取第一列字和第二列编码
                        # 只存储单个汉字的码
                        if len(char) == 1 and '\u4e00' <= char <= '\u9fff':
                            wubi_dict[char] = code
            
            if not wubi_dict:
                messagebox.showwarning("警告", "五笔码表为空，请检查文件格式！")
            return wubi_dict
                    
        except Exception as e:
            print(f"加载五笔码表失败: {str(e)}")
            messagebox.showwarning("警告", "未加载五笔码表件，自识别功能可能无法正常工作。")
            return {}

    def show_status(self, success=True, duration=2000):
        """显示状态图标
        Args:
            success: True显示成功图标(✓)，False显示失败图标(✗)
            duration: 显示持续时间（毫秒��
        """
        # 置图标颜色和符
        if success:
            self.status_label.config(text="✓", fg="green")
        else:
            self.status_label.config(text="✗", fg="red")
        
        # 设置定时器清除图标
        self.after(duration, lambda: self.status_label.config(text=""))

    def get_last_file_path(self):
        """获取上次使用的文件路径，果没有则返回默认路径"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    last_path = config.get('last_file')
                    if last_path and os.path.exists(last_path):
                        return last_path
        except Exception as e:
            print(f"读取配置文件失败: {str(e)}")
        
        # 如果没有找到的路径，返回默认路径
        return os.path.join(os.environ['USERPROFILE'], "AppData", "Roaming", "Rime", "custom_phrase.txt")

    def save_last_file_path(self):
        """保存当前文件路径到配置文件"""
        try:
            config = {'last_file': self.current_file}
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存配置文件失败: {str(e)}")

    def copy_phrase(self):
        """复制中的短语"""
        selection = self.tk_list_box_m4dq5pax.curselection()
        if selection:
            # 清空编辑区
            self.clear_editor()
            
            # 获取选中的短语
            phrase = self.phrases[selection[0]]
            
            # 解析短语格式（格式为text\tcode\tweight）
            parts = phrase.strip().split('\t')
            if len(parts) == 3:
                text, code, weight = parts
                self.tk_text_m4dqbw6e.insert(tk.END, text)  # 大文本框显示文本内容
                self.tk_text_m4dqcl46.insert(tk.END, '')    # 输入码留空，等待用户输入新的编码
                self.tk_text_m4dqdwff.insert(tk.END, weight)  # 权重文本框显示权重
            else:
                # 如果解析失败，直接显示整个短语
                self.tk_text_m4dqbw6e.insert(tk.END, phrase)
                messagebox.showerror("错误", "短语格式不正确！")

    def sort_by_content(self):
        """一键整理：将相同文本内容的短语排列在一，并清理空行"""
        try:
            original_count = len(self.phrases)
            has_empty_lines = True
            
            # 循环处理直到没有空行
            while has_empty_lines:
                # 创建一个字典，key是本内容，value是包含该文本的所短语
                content_dict = {}
                for phrase in self.phrases:
                    parts = phrase.strip().split('\t')
                    if len(parts) == 3:
                        text, code, weight = parts
                        if text not in content_dict:
                            content_dict[text] = []
                        # 确保每个短语都以换行符结尾
                        if not phrase.endswith('\n'):
                            phrase = phrase + '\n'
                        content_dict[text].append(phrase)
                
                # 清空原有短语列表
                self.phrases = []
                
                # 按文本内容重新组织短语
                for text in sorted(content_dict.keys()):
                    self.phrases.extend(content_dict[text])
                
                # 检查是否还有空行
                has_empty_lines = False
                filtered_phrases = []
                for phrase in self.phrases:
                    if phrase.strip():  # 如果行不是空的
                        filtered_phrases.append(phrase)
                    else:
                        has_empty_lines = True  # 发空行，需要继续处理
                
                # 更新短语表
                self.phrases = filtered_phrases
                
                # 完全清空并重新加载列表显示
                self.tk_list_box_m4dq5pax.delete(0, tk.END)
                for phrase in self.phrases:
                    self.tk_list_box_m4dq5pax.insert(tk.END, phrase)
                
                # ��新界面
                self.update()
                
                # 短暂延迟以显示进度
                self.after(100)
            
            # 更新状态栏
            self.tk_label_count.config(text=f"共 {len(self.phrases)} 条短语 - 整理完成")
            self.show_status(True)
            
            # 自动保存
            self.save_phrases()
            
            # 记录日志
            logging.info(f"整理短语：原 {original_count} 条，整理后 {len(self.phrases)} 条，已清空行")
            
            # 最后再次刷新显示
            self.update_listbox()
            self.update()
            
        except Exception as e:
            error_msg = f"整理失败：{str(e)}"
            logging.error(error_msg)
            messagebox.showerror("错误", error_msg)

    def change_format_mode(self):
        """切换格式化方案"""
        mode = self.format_var.get()
        self.current_format_mode = mode
        logging.info(f"切换格式化方案为: {mode}")
        self.save_format_mode()  # 保存当前方案到配置文件

    def save_format_mode(self):
        """保存格式化方案到配置文件"""
        try:
            config = {}
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
            
            config['format_mode'] = self.current_format_mode
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存格式化方案失败: {str(e)}")

    def load_format_mode(self):
        """从配置文件加载格式化方案"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    mode = config.get('format_mode', 1)  # 默认使用第一种方案
                    self.format_var.set(mode)
                    self.current_format_mode = mode
        except Exception as e:
            print(f"加载格式化方案失败: {str(e)}")
            self.format_var.set(1)  # 出错时使用第一种方案
            self.current_format_mode = 1

    def add_all_codes(self):
        """为当前文本添加所有编码方式的短语"""
        try:
            # 获取当前文本
            text = self.tk_text_m4dqbw6e.get("1.0", "end-1c").strip()
            if not text:
                messagebox.showwarning("警告", "请先输入文本内容！")
                return

            # 格式化文本
            formatted_text = self.format_text(text)
            added_count = 0

            if len(text) >= 2:
                # 1. 识别头2字4键
                self.auto_recognize_2chars()
                code = self.tk_text_m4dqcl46.get("1.0", "end-1c").strip()
                if code:
                    new_phrase = f"{formatted_text}\t{code}\t3\n"
                    self.phrases.append(new_phrase)
                    added_count += 1

            if len(text) >= 3:
                # 2. 识别头3字6键
                self.auto_recognize_3chars()
                code = self.tk_text_m4dqcl46.get("1.0", "end-1c").strip()
                if code:
                    new_phrase = f"{formatted_text}\t{code}\t3\n"
                    self.phrases.append(new_phrase)
                    added_count += 1

            if len(text) >= 4:
                # 3. 识别头4字4键
                self.auto_recognize_4chars_first()
                code = self.tk_text_m4dqcl46.get("1.0", "end-1c").strip()
                if code:
                    new_phrase = f"{formatted_text}\t{code}\t3\n"
                    self.phrases.append(new_phrase)
                    added_count += 1

                # 4. 识别头4��8键
                self.auto_recognize_4chars()
                code = self.tk_text_m4dqcl46.get("1.0", "end-1c").strip()
                if code:
                    new_phrase = f"{formatted_text}\t{code}\t3\n"
                    self.phrases.append(new_phrase)
                    added_count += 1

            if len(text) >= 3:
                # 5. 识别123码6键
                self.auto_recognize_123chars()
                code = self.tk_text_m4dqcl46.get("1.0", "end-1c").strip()
                if code:
                    new_phrase = f"{formatted_text}\t{code}\t3\n"
                    self.phrases.append(new_phrase)
                    added_count += 1

            # 更新列表显示
            self.update_listbox()
            
            # 更新状态显示
            if added_count > 0:
                self.tk_label_count.config(text=f"共 {len(self.phrases)} 条短语 - 添加了 {added_count} 种编码")
                self.show_status(True)
                # 自动保存
                self.save_phrases()
                # 清空输入
                self.clear_editor()
                
                logging.info(f"为文本 '{text}' 添加了 {added_count} 种编码")
            else:
                messagebox.showwarning("警告", "没有可添加的编码！")
                self.show_status(False)

        except Exception as e:
            error_msg = f"添加所有编码失败：{str(e)}"
            logging.error(error_msg)
            messagebox.showerror("错误", error_msg)
            self.show_status(False)

if __name__ == "__main__":
    win = WinGUI()
    win.mainloop()
