import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, scrolledtext
import os
import argparse
import chardet # 文字コード判定用
from tkinterdnd2 import DND_FILES, TkinterDnD # TkinterDnD2 を全て小文字でインポート
import re # 正規表現モジュールをインポート

# --- INIファイル読み書き関数 (自前実装) ---
def read_ini(filepath):
    """INIファイルから設定を読み込む (key=val形式)"""
    settings = {}
    if not os.path.exists(filepath):
        return settings

    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if not line or line.startswith('#'): # 空行またはコメントをスキップ
                    continue
                if '=' in line:
                    key, value = line.split('=', 1)
                    settings[key.strip()] = value.strip()
    except Exception as e:
        print(f"Error reading INI file {filepath}: {e}")
        messagebox.showerror("INIファイル読み込みエラー", f"'{os.path.basename(filepath)}' の読み込み中にエラーが発生しました:\n{e}")
    return settings

def write_ini(filepath, settings):
    """INIファイルに設定を書き込む (key=val形式)"""
    try:
        with open(filepath, 'w', encoding='utf-8') as f:
            for key, value in settings.items():
                f.write(f"{key}={value}\n")
    except Exception as e:
        print(f"Error writing INI file {filepath}: {e}")
        messagebox.showerror("INIファイル書き込みエラー", f"'{os.path.basename(filepath)}' の書き込み中にエラーが発生しました:\n{e}")

# --- パーサー部分 (変更なし) ---
class SimpleTomlParser:
    """
    簡易的なTOML/INIパーサー。
    厳密なTOMLの仕様には対応していません。
    セクション ([section]) とキー = 値 の形式の行を扱います。
    [section].key のような形式もセクションとして扱います。
    """
    def __init__(self):
        self.data = {}
        self.sections = [] # (extracted_section_name, line_number, original_line_content)

    def parse(self, content):
        self.data = {}
        self.sections = []
        current_section = ""
        lines = content.splitlines()

        section_start_pattern = re.compile(r"^\s*\[")

        for i, line in enumerate(lines):
            stripped_line = line.strip()

            if stripped_line.startswith("#"):
                continue
            if not stripped_line:
                continue

            if section_start_pattern.match(stripped_line) and "=" not in stripped_line:
                extracted_section_name = stripped_line
                
                self.sections.append((extracted_section_name, i + 1, line))
                
                match_inner_section = re.match(r"^\[([^\]]+)\].*", stripped_line)
                if match_inner_section:
                    current_section = match_inner_section.group(1).strip()
                else:
                    current_section = "" 

                if current_section and current_section not in self.data:
                     self.data[current_section] = {}
                elif not current_section and "" not in self.data:
                    self.data[""] = {}


            elif "=" in stripped_line:
                try:
                    key, value = stripped_line.split("=", 1)
                    key = key.strip()
                    value = value.strip()
                    if current_section:
                        self.data[current_section][key] = value
                    else:
                        if "" not in self.data:
                            self.data[""] = {}
                        self.data[""][key] = value
                except ValueError:
                    pass
        return self.data, self.sections

# --- メインエディタクラス ---
class TomlEditor:
    def __init__(self, master, initial_file=None):
        self.master = master
        master.title("TOML Editor")
        master.geometry("800x600") # デフォルトサイズを設定

        self.current_file = initial_file
        self.file_encoding = "auto" 

        # ファイルパスの設定 (text.ini に変更)
        self.script_dir = os.path.dirname(os.path.abspath(__file__))
        self.config_filepath = os.path.join(self.script_dir, "iniedit.ini")
        self.text_ini_filepath = os.path.join(self.script_dir, "text.ini") # ここを text.ini に変更

        # 設定を読み込む
        self.settings = read_ini(self.config_filepath)
        self._apply_saved_settings() # 保存された設定を適用

        # text.ini のデータを読み込む
        self._load_text_ini_data() # 初期読み込み

        # --- Text Area ---
        self.text_area = scrolledtext.ScrolledText(master, wrap=tk.WORD, undo=True)
        self.text_area.pack(expand=True, fill="both")
        self.text_area.bind("<<Modified>>", self.on_text_modified)
        self.text_area.bind("<KeyRelease>", self.update_status_bar)
        self.text_area.bind("<ButtonRelease-1>", self.update_status_bar)

        # Drag & Drop の設定
        self.text_area.drop_target_register(DND_FILES)
        self.text_area.dnd_bind("<<Drop>>", self.handle_drop)
        
        # コンテキストメニューの設定
        self.context_menu = tk.Menu(self.text_area, tearoff=0)
        self.context_menu.add_command(label="切り取り", command=lambda: self.text_area.event_generate("<<Cut>>"))
        self.context_menu.add_command(label="コピー", command=lambda: self.text_area.event_generate("<<Copy>>"))
        self.context_menu.add_command(label="貼り付け", command=lambda: self.text_area.event_generate("<<Paste>>"))
        self.context_menu.add_separator()
        
        # text.ini挿入用のサブメニューを追加
        self.insert_ini_menu = tk.Menu(self.context_menu, tearoff=0)
        self.context_menu.add_cascade(label="text.iniから挿入", menu=self.insert_ini_menu)
        # 変更点: text.ini再読み込みメニューを追加
        self.context_menu.add_command(label="text.ini再読み込み", command=self._load_text_ini_data)
        
        self.text_area.bind("<Button-3>", self._show_context_menu) # 右クリックで表示

        # --- Menu Bar ---
        self.menubar = tk.Menu(master)
        master.config(menu=self.menubar)

        # File Menu
        file_menu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="ファイル", menu=file_menu)
        file_menu.add_command(label="新規", command=self.new_file)
        file_menu.add_command(label="開く", command=self.open_file)
        file_menu.add_command(label="保存", command=self.save_file)
        file_menu.add_command(label="名前を付けて保存...", command=self.save_file_as)
        file_menu.add_separator()

        # Encoding Submenu
        self.encoding_menu = tk.Menu(file_menu, tearoff=0)
        file_menu.add_cascade(label="文字コード", menu=self.encoding_menu)
        self.selected_encoding = tk.StringVar(value="auto") 
        self._add_encoding_options()

        file_menu.add_separator()
        file_menu.add_command(label="終了", command=master.quit)

        # Edit Menu (変更点: ジャンプ機能を追加)
        edit_menu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="編集", menu=edit_menu)
        edit_menu.add_command(label="検索", command=self.find_text)
        edit_menu.add_command(label="置換", command=self.replace_text)
        edit_menu.add_separator()
        edit_menu.add_command(label="元に戻す", command=self.text_area.edit_undo)
        edit_menu.add_command(label="やり直し", command=self.text_area.edit_redo)
        edit_menu.add_separator()
        edit_menu.add_command(label="文書先頭へジャンプ", command=self._jump_to_start)
        edit_menu.add_command(label="文書末へジャンプ", command=self._jump_to_end)
        edit_menu.add_command(label="行番号を指定してジャンプ", command=self._jump_to_line)
        edit_menu.add_separator()
        edit_menu.add_command(label="切り取り", command=lambda: self.text_area.event_generate("<<Cut>>"))
        edit_menu.add_command(label="コピー", command=lambda: self.text_area.event_generate("<<Copy>>"))
        edit_menu.add_command(label="貼り付け", command=lambda: self.text_area.event_generate("<<Paste>>"))

        # View Menu (変更なし)
        view_menu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="表示", menu=view_menu)
        self.word_wrap_var = tk.BooleanVar(value=True)
        view_menu.add_checkbutton(label="折り返し", onvalue=True, offvalue=False, variable=self.word_wrap_var, command=self.toggle_word_wrap)

        # Tools Menu (変更なし)
        tools_menu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="ツール", menu=tools_menu)
        tools_menu.add_command(label="セクションダイアログ", command=self.show_section_dialog)

        # --- Status Bar ---
        self.status_bar = tk.Label(master, text="行: 1, 桁: 1 | 文字コード: 自動判別", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        self.update_status_bar() # 初期ファイルが読み込まれる前に一度更新

        if self.current_file:
            self._load_initial_file(self.current_file)
        else:
            self.master.title("TOML Editor - 無題")
            self.status_bar.config(text=f"行: 1, 桁: 1 | 文字コード: 自動判別")
            
        # アプリケーション終了時の処理を登録
        self.master.protocol("WM_DELETE_WINDOW", self._on_closing)

    def _load_text_ini_data(self):
        """text.ini のデータを読み込み、self.test_ini_data に格納する"""
        self.test_ini_data = read_ini(self.text_ini_filepath)

    def _apply_saved_settings(self):
        """保存されたウィンドウ設定を適用する"""
        try:
            width = int(self.settings.get('main_width', 800))
            height = int(self.settings.get('main_height', 600))
            pos_x = int(self.settings.get('main_pos_x', 100))
            pos_y = int(self.settings.get('main_pos_y', 100))
            self.master.geometry(f"{width}x{height}+{pos_x}+{pos_y}")
        except ValueError:
            self.master.geometry("800x600+100+100")

    def _on_closing(self):
        """アプリケーション終了時の処理 (設定保存など)"""
        if self.text_area.edit_modified():
            if messagebox.askyesno("未保存の変更", "ファイルを保存しますか？"):
                self.save_file()
        
        # メインウィンドウの位置とサイズを記録
        self.settings['main_width'] = self.master.winfo_width()
        self.settings['main_height'] = self.master.winfo_height()
        self.settings['main_pos_x'] = self.master.winfo_x()
        self.settings['main_pos_y'] = self.master.winfo_y()

        write_ini(self.config_filepath, self.settings)
        self.master.destroy()

    def _show_context_menu(self, event):
        """右クリックでコンテキストメニューを表示する"""
        # サブメニューをクリアし、test.ini の内容で再生成する
        self.insert_ini_menu.delete(0, tk.END) 
        if self.test_ini_data:
            for key, value in self.test_ini_data.items():
                self.insert_ini_menu.add_command(label=key, command=lambda v=value: self._insert_value_from_ini(v))
        else:
            self.insert_ini_menu.add_command(label="text.iniが空か見つかりません", state=tk.DISABLED)

        self.context_menu.post(event.x_root, event.y_root)

    def _insert_value_from_ini(self, value):
        """text.ini から読み込んだ値を現在のカーソル位置に挿入する"""
        self.text_area.insert(tk.INSERT, value)
        self.text_area.edit_modified(True) # 変更フラグを立てる
        self.on_text_modified() # タイトルバーを更新

    # --- ジャンプ機能 ---
    def _jump_to_start(self):
        """文書の先頭へジャンプする"""
        self.text_area.mark_set(tk.INSERT, "1.0")
        self.text_area.see(tk.INSERT)
        self.update_status_bar()

    def _jump_to_end(self):
        """文書の末尾へジャンプする"""
        self.text_area.mark_set(tk.INSERT, tk.END)
        self.text_area.see(tk.INSERT)
        self.update_status_bar()

    def _jump_to_line(self):
        """行番号を指定してジャンプする"""
        line_str = simpledialog.askstring("行へジャンプ", "ジャンプする行番号を入力してください:", parent=self.master)
        if line_str:
            try:
                line_number = int(line_str)
                if line_number < 1:
                    line_number = 1
                
                # ドキュメントの最終行を取得
                last_line = int(self.text_area.index("end-1c").split('.')[0])
                if line_number > last_line:
                    line_number = last_line

                self.text_area.mark_set(tk.INSERT, f"{line_number}.0")
                self.text_area.see(tk.INSERT)
                self.update_status_bar()
            except ValueError:
                messagebox.showerror("入力エラー", "有効な行番号を入力してください。")


    def _add_encoding_options(self):
        encodings = ["utf-8", "shift_jis", "cp932", "euc_jp", "iso2022_jp"]
        self.encoding_menu.add_radiobutton(label="自動判別", value="auto",
                                            variable=self.selected_encoding,
                                            command=lambda: self._on_encoding_selected(is_auto=True))
        self.encoding_menu.add_separator()
        for enc in encodings:
            self.encoding_menu.add_radiobutton(label=enc.upper(), value=enc,
                                                variable=self.selected_encoding,
                                                command=self._on_encoding_selected)
    
    def _on_encoding_selected(self, is_auto=False):
        if not is_auto:
            self.file_encoding = self.selected_encoding.get()
        else:
            self.file_encoding = "auto"
        self.update_status_bar()


    def _load_initial_file(self, file_path):
        self.current_file = file_path
        self.selected_encoding.set("auto") # 強制的に'auto'に設定して読み込み
        self._read_file_with_encoding_detection(file_path)
        self.master.title(f"TOML Editor - {os.path.basename(file_path)}")
        self.text_area.edit_reset()
        self.update_status_bar()

    def _read_file_with_encoding_detection(self, file_path):
        try:
            with open(file_path, "rb") as f:
                raw_data = f.read()

            if self.selected_encoding.get() == "auto":
                result = chardet.detect(raw_data)
                detected_encoding = result['encoding']
                confidence = result['confidence']

                if detected_encoding and confidence > 0.8:
                    self.file_encoding = detected_encoding
                else:
                    self.file_encoding = "utf-8"
                    messagebox.showwarning("文字コード判別",
                                           f"文字コードを自動判別できませんでした。UTF-8で開きます。\n"
                                           f"検出結果: {detected_encoding} (確信度: {confidence:.2f})")
            else:
                self.file_encoding = self.selected_encoding.get()

            content = raw_data.decode(self.file_encoding)
            self.text_area.delete(1.0, tk.END)
            self.text_area.insert(tk.END, content)
            self.selected_encoding.set(self.file_encoding) 

        except UnicodeDecodeError:
            messagebox.showerror("文字コードエラー",
                                   f"選択された文字コード '{self.file_encoding}' でファイルをデコードできませんでした。\n"
                                   "別の文字コードを試してください。")
            self.text_area.delete(1.0, tk.END)
            self.file_encoding = "utf-8"
            self.selected_encoding.set(self.file_encoding)
        except Exception as e:
            messagebox.showerror("エラー", f"ファイルの読み込み中にエラーが発生しました:\n{e}")
            self.text_area.delete(1.0, tk.END)
            self.file_encoding = "utf-8"
            self.selected_encoding.set(self.file_encoding)


    def handle_drop(self, event):
        file_path = event.data.strip('{}')
        if ' ' in file_path and os.name == 'nt':
             file_paths = file_path.split('} {')
             file_path = file_paths[0].strip('{}')
        
        if os.path.isfile(file_path):
            if self.text_area.edit_modified():
                if messagebox.askyesno("未保存の変更", "現在のファイルを保存しますか？"):
                    self.save_file()
            self._load_initial_file(file_path)
        else:
            messagebox.showwarning("D&Dエラー", "ドロップされたファイルが無効です。")


    def new_file(self):
        if self.text_area.edit_modified():
            if not messagebox.askyesno("未保存の変更", "現在のファイルを保存しますか？"):
                self.text_area.delete(1.0, tk.END)
                self.current_file = None
                self.master.title("TOML Editor - 無題")
                self.text_area.edit_reset()
                self.file_encoding = "auto" 
                self.selected_encoding.set(self.file_encoding)
                self.update_status_bar()
                return

        self.text_area.delete(1.0, tk.END)
        self.current_file = None
        self.master.title("TOML Editor - 無題")
        self.text_area.edit_reset()
        self.file_encoding = "auto"
        self.selected_encoding.set(self.file_encoding)
        self.update_status_bar()


    def open_file(self):
        if self.text_area.edit_modified():
            if messagebox.askyesno("未保存の変更", "現在のファイルを保存しますか？"):
                self.save_file()

        file_types = [
            ("INI files", "*.ini"), # デフォルトをINIに
            ("TOML files", "*.toml"),
            ("Text files", "*.txt"),
            ("All files", "*.*")
        ]
        file_path = filedialog.askopenfilename(filetypes=file_types)
        if file_path:
            self._load_initial_file(file_path)
            self.current_file = file_path
            self.master.title(f"TOML Editor - {os.path.basename(file_path)}")
            self.text_area.edit_reset()
        self.update_status_bar()

    def save_file(self):
        if self.current_file:
            try:
                encoding_to_save = self.file_encoding if self.file_encoding != "auto" else "utf-8"
                with open(self.current_file, "w", encoding=encoding_to_save) as file:
                    file.write(self.text_area.get(1.0, tk.END))
                self.master.title(f"TOML Editor - {os.path.basename(self.current_file)}")
                self.text_area.edit_reset()
            except Exception as e:
                messagebox.showerror("エラー", f"ファイルの保存中にエラーが発生しました:\n{e}")
        else:
            self.save_file_as()
        self.update_status_bar()

    def save_file_as(self):
        file_types = [
            ("TOML files", "*.toml"), 
            ("INI files", "*.ini"),
            ("Text files", "*.txt"),
            ("All files", "*.*")
        ]
        file_path = filedialog.asksaveasfilename(defaultextension=".toml", filetypes=file_types)
        if file_path:
            try:
                encoding_to_save = self.file_encoding if self.file_encoding != "auto" else "utf-8"
                with open(file_path, "w", encoding=encoding_to_save) as file:
                    file.write(self.text_area.get(1.0, tk.END))
                self.current_file = file_path
                self.master.title(f"TOML Editor - {os.path.basename(file_path)}")
                self.text_area.edit_reset()
            except Exception as e:
                messagebox.showerror("エラー", f"ファイルの保存中にエラーが発生しました:\n{e}")
        self.update_status_bar()

    def find_text(self):
        self.find_dialog = tk.Toplevel(self.master)
        self.find_dialog.title("検索")
        self.find_dialog.transient(self.master)
        self.find_dialog.grab_set()
        self.find_dialog.resizable(False, False)

        tk.Label(self.find_dialog, text="検索:").grid(row=0, column=0, padx=5, pady=5)
        self.find_entry = tk.Entry(self.find_dialog)
        self.find_entry.grid(row=0, column=1, padx=5, pady=5)
        self.find_entry.focus_set()

        # 変更点: 正規表現チェックボックスを追加
        self.regex_var_find = tk.BooleanVar(value=False)
        tk.Checkbutton(self.find_dialog, text="正規表現", variable=self.regex_var_find).grid(row=1, column=1, sticky=tk.W, padx=5)

        tk.Button(self.find_dialog, text="次を検索", command=self._find_next).grid(row=0, column=2, padx=5, pady=5)
        tk.Button(self.find_dialog, text="閉じる", command=self.find_dialog.destroy).grid(row=1, column=2, padx=5, pady=5)

        self.find_entry.bind("<Return>", lambda event: self._find_next())

    def _find_next(self):
        search_text = self.find_entry.get()
        if not search_text:
            return

        is_regex = self.regex_var_find.get()
        
        start_index = self.text_area.index(tk.INSERT)
        self.text_area.tag_remove("found", "1.0", tk.END)

        try:
            # 変更点: 正規表現フラグに応じて検索方法を切り替える
            if is_regex:
                pos = self.text_area.search(search_text, start_index, stopindex=tk.END, regexp=True, nocase=True)
            else:
                pos = self.text_area.search(search_text, start_index, stopindex=tk.END, nocase=True)
            
            if pos:
                # 正規表現検索の場合、マッチしたテキストの長さをre.matchで取得
                if is_regex:
                    match_obj = re.match(search_text, self.text_area.get(pos, f"{pos} lineend"), re.IGNORECASE)
                    if match_obj:
                        match_length = match_obj.end() - match_obj.start()
                    else:
                        match_length = len(search_text) # マッチしない場合は通常の文字列長
                else:
                    match_length = len(search_text)

                end_pos = f"{pos}+{match_length}c"
                self.text_area.tag_add("found", pos, end_pos)
                self.text_area.tag_config("found", background="yellow")
                self.text_area.mark_set(tk.INSERT, end_pos)
                self.text_area.see(tk.INSERT)
            else:
                # 現在位置から見つからなかった場合、先頭から再検索
                if is_regex:
                    pos = self.text_area.search(search_text, "1.0", stopindex=tk.END, regexp=True, nocase=True)
                else:
                    pos = self.text_area.search(search_text, "1.0", stopindex=tk.END, nocase=True)
                    
                if pos:
                    if is_regex:
                        match_obj = re.match(search_text, self.text_area.get(pos, f"{pos} lineend"), re.IGNORECASE)
                        if match_obj:
                            match_length = match_obj.end() - match_obj.start()
                        else:
                            match_length = len(search_text)
                    else:
                        match_length = len(search_text)

                    end_pos = f"{pos}+{match_length}c"
                    self.text_area.tag_add("found", pos, end_pos)
                    self.text_area.tag_config("found", background="yellow")
                    self.text_area.mark_set(tk.INSERT, end_pos)
                    self.text_area.see(tk.INSERT)
                else:
                    messagebox.showinfo("検索", "テキストが見つかりませんでした。", parent=self.find_dialog)
        except re.error as e:
            messagebox.showerror("正規表現エラー", f"無効な正規表現です:\n{e}", parent=self.find_dialog)


    def replace_text(self):
        self.replace_dialog = tk.Toplevel(self.master)
        self.replace_dialog.title("置換")
        self.replace_dialog.transient(self.master)
        self.replace_dialog.grab_set()
        self.replace_dialog.resizable(False, False)

        tk.Label(self.replace_dialog, text="検索:").grid(row=0, column=0, padx=5, pady=5)
        self.replace_find_entry = tk.Entry(self.replace_dialog)
        self.replace_find_entry.grid(row=0, column=1, padx=5, pady=5)
        self.replace_find_entry.focus_set()

        tk.Label(self.replace_dialog, text="置換:").grid(row=1, column=0, padx=5, pady=5)
        self.replace_entry = tk.Entry(self.replace_dialog)
        self.replace_entry.grid(row=1, column=1, padx=5, pady=5)

        # 変更点: 正規表現チェックボックスを追加 (置換ダイアログにも)
        self.regex_var_replace = tk.BooleanVar(value=False)
        tk.Checkbutton(self.replace_dialog, text="正規表現", variable=self.regex_var_replace).grid(row=2, column=1, sticky=tk.W, padx=5)

        tk.Button(self.replace_dialog, text="次を検索", command=self._find_next_for_replace).grid(row=0, column=2, padx=5, pady=5)
        tk.Button(self.replace_dialog, text="置換", command=self._do_replace).grid(row=1, column=2, padx=5, pady=5)
        tk.Button(self.replace_dialog, text="すべて置換", command=self._do_replace_all).grid(row=2, column=2, padx=5, pady=5) # 行を変更
        tk.Button(self.replace_dialog, text="閉じる", command=self.replace_dialog.destroy).grid(row=3, column=2, padx=5, pady=5) # 行を変更

    def _find_next_for_replace(self):
        search_text = self.replace_find_entry.get()
        if not search_text:
            return

        is_regex = self.regex_var_replace.get()

        start_index = self.text_area.index(tk.INSERT)
        self.text_area.tag_remove("found", "1.0", tk.END)
        
        try:
            if is_regex:
                pos = self.text_area.search(search_text, start_index, stopindex=tk.END, regexp=True, nocase=True)
            else:
                pos = self.text_area.search(search_text, start_index, stopindex=tk.END, nocase=True)

            if pos:
                if is_regex:
                    match_obj = re.match(search_text, self.text_area.get(pos, f"{pos} lineend"), re.IGNORECASE)
                    if match_obj:
                        match_length = match_obj.end() - match_obj.start()
                    else:
                        match_length = len(search_text)
                else:
                    match_length = len(search_text)

                end_pos = f"{pos}+{match_length}c"
                self.text_area.tag_add("found", pos, end_pos)
                self.text_area.tag_config("found", background="yellow")
                self.text_area.mark_set(tk.INSERT, end_pos)
                self.text_area.see(tk.INSERT)
            else:
                if is_regex:
                    pos = self.text_area.search(search_text, "1.0", stopindex=tk.END, regexp=True, nocase=True)
                else:
                    pos = self.text_area.search(search_text, "1.0", stopindex=tk.END, nocase=True)

                if pos:
                    if is_regex:
                        match_obj = re.match(search_text, self.text_area.get(pos, f"{pos} lineend"), re.IGNORECASE)
                        if match_obj:
                            match_length = match_obj.end() - match_obj.start()
                        else:
                            match_length = len(search_text)
                    else:
                        match_length = len(search_text)

                    end_pos = f"{pos}+{match_length}c"
                    self.text_area.tag_add("found", pos, end_pos)
                    self.text_area.tag_config("found", background="yellow")
                    self.text_area.mark_set(tk.INSERT, end_pos)
                    self.text_area.see(tk.INSERT)
                else:
                    messagebox.showinfo("検索", "テキストが見つかりませんでした。", parent=self.replace_dialog)
        except re.error as e:
            messagebox.showerror("正規表現エラー", f"無効な正規表現です:\n{e}", parent=self.replace_dialog)

    def _do_replace(self):
        search_text = self.replace_find_entry.get()
        replace_with = self.replace_entry.get()
        if not search_text:
            return

        is_regex = self.regex_var_replace.get()

        current_selection_start = self.text_area.index(tk.SEL_FIRST) if self.text_area.tag_ranges(tk.SEL) else None
        current_selection_end = self.text_area.index(tk.SEL_LAST) if self.text_area.tag_ranges(tk.SEL) else None

        try:
            if current_selection_start:
                selected_text = self.text_area.get(current_selection_start, current_selection_end)
                
                match = None
                if is_regex:
                    # 正規表現の場合、選択範囲のテキスト全体に対してマッチを試みる
                    match = re.fullmatch(search_text, selected_text, re.IGNORECASE)
                else:
                    # 通常検索の場合、選択テキストが検索テキストと完全に一致するか確認
                    if selected_text.lower() == search_text.lower():
                        match = True # 単純な一致として扱う

                if match:
                    # 置換処理
                    self.text_area.replace(current_selection_start, current_selection_end, replace_with)
                    self.text_area.tag_remove("found", "1.0", tk.END)
                    # 置換後、次の出現箇所を検索
                    # 置換後のテキストの長さを考慮してカーソル位置を設定
                    self.text_area.mark_set(tk.INSERT, f"{current_selection_start}+{len(replace_with)}c")
                    self.text_area.see(tk.INSERT)
                    self.text_area.edit_modified(True)
                    self.on_text_modified()
                    self._find_next_for_replace() # 次を検索
                    return
            
            # 選択範囲がなかったり、選択範囲が検索文字列と一致しない場合は、まず検索
            self._find_next_for_replace()

        except re.error as e:
            messagebox.showerror("正規表現エラー", f"無効な正規表現です:\n{e}", parent=self.replace_dialog)


    def _do_replace_all(self):
        search_text = self.replace_find_entry.get()
        replace_with = self.replace_entry.get()
        if not search_text:
            return

        is_regex = self.regex_var_replace.get()
        
        self.text_area.edit_separator()

        count = 0
        start_pos = "1.0"
        
        try:
            while True:
                if is_regex:
                    pos = self.text_area.search(search_text, start_pos, stopindex=tk.END, regexp=True, nocase=True)
                else:
                    pos = self.text_area.search(search_text, start_pos, stopindex=tk.END, nocase=True)
                    
                if not pos:
                    break
                
                # 正規表現の場合、実際にマッチした部分の長さを取得して置換
                if is_regex:
                    match_obj = re.match(search_text, self.text_area.get(pos, f"{pos} lineend"), re.IGNORECASE)
                    if match_obj:
                        match_length = match_obj.end() - match_obj.start()
                    else:
                        match_length = len(search_text) # これが起こるべきではないが念のため
                else:
                    match_length = len(search_text)
                    
                end_pos = f"{pos}+{match_length}c"
                
                self.text_area.replace(pos, end_pos, replace_with)
                start_pos = f"{pos}+{len(replace_with)}c" # 置換後のテキストの後に検索を続ける
                count += 1
            
            self.text_area.tag_remove("found", "1.0", tk.END)
            if count > 0:
                self.text_area.edit_modified(True)
                self.on_text_modified()
            messagebox.showinfo("置換", f"{count} 件を置換しました。", parent=self.replace_dialog)
        except re.error as e:
            messagebox.showerror("正規表現エラー", f"無効な正規表現です:\n{e}", parent=self.replace_dialog)

    def toggle_word_wrap(self):
        if self.word_wrap_var.get():
            self.text_area.config(wrap=tk.WORD)
        else:
            self.text_area.config(wrap=tk.NONE)

    def on_text_modified(self, event=None):
        if self.text_area.edit_modified():
            if self.current_file:
                self.master.title(f"TOML Editor - {os.path.basename(self.current_file)}*")
            else:
                self.master.title("TOML Editor - 無題*")
        else:
            if self.current_file:
                self.master.title(f"TOML Editor - {os.path.basename(self.current_file)}")
            else:
                self.master.title("TOML Editor - 無題")
        self.text_area.edit_modified(False)

    def update_status_bar(self, event=None):
        line, char = self.text_area.index(tk.INSERT).split('.')
        encoding_display = self.file_encoding.upper() if self.file_encoding != "auto" else "自動判別"
        self.status_bar.config(text=f"行: {line}, 桁: {int(char) + 1} | 文字コード: {encoding_display}")

    def show_section_dialog(self):
        self.section_dialog = tk.Toplevel(self.master)
        self.section_dialog.title("セクション")

        try:
            width = int(self.settings.get('section_dialog_width', 300))
            height = int(self.settings.get('section_dialog_height', 400))
            self.section_dialog.geometry(f"{width}x{height}")
        except ValueError:
            self.section_dialog.geometry("300x400")

        self.section_listbox = tk.Listbox(self.section_dialog)
        self.section_listbox.pack(expand=True, fill="both", padx=10, pady=10)
        self.section_listbox.bind("<<ListboxSelect>>", self._on_section_select)

        self._populate_sections()

        close_button = tk.Button(self.section_dialog, text="閉じる", command=self._on_section_dialog_closing)
        close_button.pack(pady=5)

        self.section_dialog.protocol("WM_DELETE_WINDOW", self._on_section_dialog_closing)

    def _on_section_dialog_closing(self):
        """セクションダイアログ終了時の処理 (サイズ記録など)"""
        self.settings['section_dialog_width'] = self.section_dialog.winfo_width()
        self.settings['section_dialog_height'] = self.section_dialog.winfo_height()
        write_ini(self.config_filepath, self.settings)
        self.section_dialog.destroy()


    def _populate_sections(self):
        self.section_listbox.delete(0, tk.END)
        content = self.text_area.get(1.0, tk.END)
        parser = SimpleTomlParser()
        _, sections = parser.parse(content)
        self.parsed_sections = sections

        for extracted_section_name, _, _ in self.parsed_sections:
            self.section_listbox.insert(tk.END, extracted_section_name.strip())

    def _on_section_select(self, event):
        selected_indices = self.section_listbox.curselection()
        if selected_indices:
            index = selected_indices[0]
            extracted_section_name, line_number, original_line_content = self.parsed_sections[index]

            search_text = original_line_content.strip()

            self.text_area.tag_remove("found_section", "1.0", tk.END)

            start_index = f"{line_number}.0"
            end_index = f"{line_number}.end"

            pos = self.text_area.search(search_text, start_index, stopindex=end_index, nocase=True)

            if pos:
                end_pos = f"{pos}+{len(search_text)}c"
                self.text_area.tag_add("found_section", pos, end_pos)
                self.text_area.tag_config("found_section", background="lightblue")
                self.text_area.mark_set(tk.INSERT, pos)
                self.text_area.see(tk.INSERT)
            else:
                self.text_area.mark_set(tk.INSERT, f"{line_number}.0")
                self.text_area.see(tk.INSERT)
                messagebox.showwarning("検索失敗", "セクションの元の行内容が見つかりませんでした。", parent=self.section_dialog)

            self.update_status_bar()

def main():
    parser = argparse.ArgumentParser(description="簡易TOMLエディタ")
    parser.add_argument("input_file", nargs="?", default=None,
                        help="編集するTOMLファイルのパス (オプション)")
    args = parser.parse_args()

    root = TkinterDnD.Tk()
    editor = TomlEditor(root, initial_file=args.input_file)
    root.mainloop()

if __name__ == "__main__":
    main()