import tkinter as tk
from tkinter import scrolledtext, messagebox, filedialog
import re

class TokenManager:
    def __init__(self, root):
        self.root = root
        self.root.title("C++ Tokenizer Manager (Pro)")
        self.root.geometry("1000x900")
        self.root.configure(bg="#f5f5f5")

        self.tokens = []

        # --- Секция 1: Ввод и Загрузка ---
        top_frame = tk.Frame(root, bg="#f5f5f5")
        top_frame.pack(fill=tk.X, padx=15, pady=10)

        tk.Label(top_frame, text="1. Управление токенами:", font=('Arial', 10, 'bold'), bg="#f5f5f5").pack(side=tk.LEFT)
        
        btn_load_file = tk.Button(top_frame, text="📥 Загрузить и разбить датасет (.txt)", 
                                  command=self.load_dataset_file, bg="#FF9800", fg="white", font=('Arial', 9, 'bold'))
        btn_load_file.pack(side=tk.RIGHT, padx=5)

        self.input_area = scrolledtext.ScrolledText(root, height=6, font=('Consolas', 10))
        self.input_area.pack(padx=15, pady=5, fill=tk.X)
        self.input_area.insert(tk.END, "// Вставьте старый код конструктора сюда или используйте кнопку загрузки файла...")

        btn_parse = tk.Button(root, text="Извлечь токены из кода выше", command=self.parse_input, bg="#2196F3", fg="white")
        btn_parse.pack(pady=5)

        # --- Секция 2: Средняя часть (Добавление и Список) ---
        middle_frame = tk.Frame(root, bg="#f5f5f5")
        middle_frame.pack(padx=15, pady=10, fill=tk.BOTH, expand=True)

        # Левая колонка: Добавление
        left_col = tk.LabelFrame(middle_frame, text="Добавить вручную", padx=10, pady=10)
        left_col.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))

        self.new_token_entry = tk.Entry(left_col, font=('Arial', 11))
        self.new_token_entry.pack(fill=tk.X, pady=5)
        self.new_token_entry.bind('<Return>', lambda e: self.add_single_token())

        tk.Button(left_col, text="Добавить в список", command=self.add_single_token, bg="#4CAF50", fg="white").pack(fill=tk.X, pady=5)

        # Правая колонка: Просмотр
        self.right_col = tk.LabelFrame(middle_frame, text="Текущий список (0 токенов)", padx=10, pady=10)
        self.right_col.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        list_scroll = tk.Scrollbar(self.right_col)
        list_scroll.pack(side=tk.RIGHT, fill=tk.Y)

        self.token_listbox = tk.Listbox(self.right_col, font=('Arial', 10), yscrollcommand=list_scroll.set, selectmode=tk.EXTENDED)
        self.token_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        list_scroll.config(command=self.token_listbox.yview)

        tk.Button(self.right_col, text="Удалить выбранные", command=self.delete_selected, bg="#F44336", fg="white").pack(fill=tk.X, pady=(5,0))

        # --- Секция 3: Вывод результата ---
        tk.Label(root, text="3. Готовый код для C++ (token.cpp):", font=('Arial', 10, 'bold'), bg="#f5f5f5").pack(pady=(10,0))
        self.output_area = scrolledtext.ScrolledText(root, height=15, bg="#fafafa", font=('Consolas', 10), fg="#2e7d32")
        self.output_area.pack(padx=15, pady=5, fill=tk.X)

        # Нижняя панель
        bottom_frame = tk.Frame(root, bg="#f5f5f5")
        bottom_frame.pack(fill=tk.X, padx=15, pady=10)

        self.status_label = tk.Label(bottom_frame, text="Количество токенов: 0", font=('Arial', 11, 'bold'), bg="#f5f5f5")
        self.status_label.pack(side=tk.LEFT)

        tk.Button(bottom_frame, text="📋 Копировать код", command=self.copy_to_clipboard, bg="#9E9E9E", fg="white", font=('Arial', 10, 'bold')).pack(side=tk.RIGHT)

    def load_dataset_file(self):
        """Открывает файл и разбивает его на токены согласно правилам"""
        file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt"), ("All files", "*.*")])
        if not file_path:
            return

        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()

            # РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ:
            # [a-zA-Zа-яА-Я0-9ёЁ-]+  --> Слова (включая цифры и дефисы внутри типа "что-то")
            # [^\w\s]                --> Любой символ, который не буква и не пробел (знаки препинания)
            pattern = r"[a-zA-Zа-яА-Я0-9ёЁ-]+|[^\w\s]"
            raw_tokens = re.findall(pattern, content)

            new_count = 0
            for t in raw_tokens:
                if t not in self.tokens:
                    self.tokens.append(t)
                    new_count += 1
            
            self.refresh_ui()
            messagebox.showinfo("Загрузка завершена", f"Всего токенов найдено: {len(raw_tokens)}\nДобавлено новых уникальных: {new_count}")
        
        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось прочитать файл:\n{str(e)}")

    def parse_input(self):
        text = self.input_area.get("1.0", tk.END)
        found = re.findall(r'add\("(.*?)"\);', text)
        if not found:
            messagebox.showwarning("Внимание", "Используйте формат add(\"слово\");")
            return
        added = 0
        for t in found:
            if t not in self.tokens:
                self.tokens.append(t)
                added += 1
        self.refresh_ui()

    def add_single_token(self):
        raw_input = self.new_token_entry.get().strip()
        if not raw_input: return
        if raw_input not in self.tokens:
            self.tokens.append(raw_input)
            self.refresh_ui()
        self.new_token_entry.delete(0, tk.END)

    def delete_selected(self):
        indices = self.token_listbox.curselection()
        to_remove = [self.token_listbox.get(i) for i in indices]
        for val in to_remove:
            self.tokens.remove(val)
        self.refresh_ui()

    def refresh_ui(self):
        self.token_listbox.delete(0, tk.END)
        for t in self.tokens:
            self.token_listbox.insert(tk.END, t)
        
        self.right_col.config(text=f"Текущий список ({len(self.tokens)} токенов)")
        
        self.output_area.delete("1.0", tk.END)
        code = "Tokenizer() {\n"
        # Группируем по 6 для красоты в C++
        for i in range(0, len(self.tokens), 6):
            line = self.tokens[i:i+6]
            code += "        " + " ".join([f'add("{t}");' for t in line]) + "\n"
        code += "    }"
        self.output_area.insert(tk.END, code)
        self.status_label.config(text=f"Количество токенов: {len(self.tokens)}")

    def copy_to_clipboard(self):
        self.root.clipboard_clear()
        self.root.clipboard_append(self.output_area.get("1.0", tk.END))
        messagebox.showinfo("ОК", "Код скопирован")

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