#!/usr/bin/env python3
# qet_extract_gui.py
# GUI zum Extrahieren eines <diagram ... order="XX"> ... </diagram> Blocks aus einer .qet/.xml Datei
# Startet maximiert (Titelleiste bleibt sichtbar). F11 toggelt, Esc setzt Normalgröße.
# Linux / Python3 / Tkinter

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

VERSION = "1.2"

def extract_diagram_blocks(text, order_str):
    """Sucht alle <diagram\b ... order=...> ... </diagram> Blöcke.
       Liefert Liste von (start_index, end_index, block_text).
       Unterstützt order="67" oder order='67' oder order=67 (ohne quotes).
    """
    blocks = []
    open_re = re.compile(
        r'<diagram\b[^>]*\border\s*=\s*(?:["\']\s*' + re.escape(order_str) + r'\s*["\']|' + re.escape(order_str) + r')[^>]*>',
        re.IGNORECASE | re.DOTALL
    )
    close_re = re.compile(r'</diagram\s*>', re.IGNORECASE)

    for m in open_re.finditer(text):
        start = m.start()
        close_m = close_re.search(text, m.end())
        if not close_m:
            continue
        end = close_m.end()
        blocks.append((start, end, text[start:end]))
    return blocks

class QETExtractorApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title(f"QET Diagram Extractor v{VERSION}")

        # --- statt echtes Fullscreen: beim Start maximieren (Titelleiste bleibt)
        self._zoomed = True
        self._maximize_window()

        # Esc setzt auf Normalgröße, F11 toggelt
        self.bind("<Escape>", lambda e: self.restore_normal())
        self.bind("<F11>", lambda e: self.toggle_maximize())

        # Fensterinhalt
        self._build_ui()

        # interne Zustände
        self.loaded_text = None
        self.blocks = []   # Liste (start,end,block)
        self.current_index = 0

    def _maximize_window(self):
        """Maximiert das Fenster (soweit vom WM unterstützt). Falls nicht möglich, verwendet Geometrie als Fallback."""
        try:
            # Try the common methods
            self.state('zoomed')          # häufig unter Windows / manchen WMs
            self.attributes('-zoomed', True)  # alternative
        except Exception:
            pass
        # Fallback: set geometry to screen size (Titelleiste bleibt normalerweise sichtbar)
        try:
            sw = self.winfo_screenwidth()
            sh = self.winfo_screenheight()
            self.geometry(f"{sw}x{sh}+0+0")
        except Exception:
            pass
        self._zoomed = True

    def restore_normal(self):
        """Setzt das Fenster in Normalgröße (nicht maximiert)."""
        try:
            self.state('normal')
            self.attributes('-zoomed', False)
        except Exception:
            pass
        # Optional: setze eine vernünftige Standardgröße
        self.geometry("1000x700")
        self._zoomed = False

    def toggle_maximize(self):
        if self._zoomed:
            self.restore_normal()
        else:
            self._maximize_window()

    def _build_ui(self):
        # Oberer Bereich
        top = tk.Frame(self)
        top.pack(fill="x", padx=8, pady=6)

        tk.Label(top, text="QET-Datei:").grid(row=0, column=0, sticky="w")
        self.file_entry = tk.Entry(top, width=70)
        self.file_entry.grid(row=0, column=1, padx=6)
        tk.Button(top, text="Datei wählen", command=self.select_file).grid(row=0, column=2, padx=4)
        tk.Button(top, text="Öffnen (Pfad verwenden)", command=self.open_file_from_entry).grid(row=0, column=3, padx=4)

        tk.Label(top, text="Order-Nummer:").grid(row=1, column=0, sticky="w", pady=(6,0))
        self.order_entry = tk.Entry(top, width=20)
        self.order_entry.grid(row=1, column=1, sticky="w", pady=(6,0))

        tk.Button(top, text="Finden & Extrahieren", command=self.find_and_extract).grid(row=1, column=2, padx=4, pady=(6,0))
        tk.Button(top, text="Speichern als .txt", command=self.save_extracted).grid(row=1, column=3, padx=4, pady=(6,0))

        # Mittlerer Bereich: Info + Navigation
        mid = tk.Frame(self)
        mid.pack(fill="x", padx=8, pady=6)

        self.info_label = tk.Label(mid, text="Keine Datei geladen", anchor="w")
        self.info_label.pack(fill="x")

        nav = tk.Frame(self)
        nav.pack(fill="x", padx=8)
        tk.Label(nav, text="Treffer:").pack(side="left")
        self.hit_var = tk.StringVar(value="0")
        self.hit_label = tk.Label(nav, textvariable=self.hit_var)
        self.hit_label.pack(side="left", padx=6)
        tk.Button(nav, text="Vorheriger", command=self.prev_hit).pack(side="right")
        tk.Button(nav, text="Nächster", command=self.next_hit).pack(side="right")

        # Textvorschau (scrollable)
        self.text_area = scrolledtext.ScrolledText(self, wrap="none", font=("Courier", 10))
        self.text_area.pack(fill="both", expand=True, padx=8, pady=6)

    def select_file(self):
        path = filedialog.askopenfilename(title="QET- oder XML-Datei wählen",
                                          filetypes=[("QET Dateien","*.qet"), ("XML Dateien","*.xml"), ("Alle Dateien","*.*")],
                                          initialdir=os.getcwd())
        if path:
            self.file_entry.delete(0, tk.END)
            self.file_entry.insert(0, path)
            self.open_file(path)

    def open_file_from_entry(self):
        path = self.file_entry.get().strip()
        if not path:
            messagebox.showwarning("Pfad fehlt", "Bitte Dateipfad eingeben oder 'Datei wählen' benutzen.")
            return
        if not os.path.isfile(path):
            messagebox.showerror("Datei nicht gefunden", f"Die Datei '{path}' existiert nicht.")
            return
        self.open_file(path)

    def open_file(self, path):
        try:
            with open(path, "rb") as f:
                raw = f.read()
            try:
                text = raw.decode("utf-8")
            except UnicodeDecodeError:
                text = raw.decode("utf-8", errors="replace")
            self.loaded_text = text
            self.blocks = []
            self.current_index = 0
            self.info_label.config(text=f"Datei geladen: {path} (Größe: {len(raw)} bytes)")
            self.text_area.delete("1.0", tk.END)
            self.text_area.insert(tk.END, f"Datei geladen. Bitte Order-Nummer eingeben und 'Finden & Extrahieren' drücken.\n\n")
            self.hit_var.set("0")
        except Exception as e:
            messagebox.showerror("Fehler beim Öffnen", str(e))

    def find_and_extract(self):
        if not self.loaded_text:
            messagebox.showwarning("Keine Datei", "Bitte zuerst eine Datei laden.")
            return
        order = self.order_entry.get().strip()
        if not order:
            messagebox.showwarning("Order fehlt", "Bitte eine Order-Nummer eingeben (z. B. 67).")
            return

        self.blocks = extract_diagram_blocks(self.loaded_text, order)
        if not self.blocks:
            messagebox.showinfo("Nicht gefunden", f"Kein <diagram ... order={order} ...> Block gefunden.")
            self.text_area.delete("1.0", tk.END)
            self.text_area.insert(tk.END, f"Kein Block mit order={order} gefunden.\n")
            self.hit_var.set("0")
            return

        count = len(self.blocks)
        self.current_index = 0
        self.hit_var.set(str(count))
        msg = f"{count} Treffer für order={order} gefunden. Anzeige Treffer 1."
        self.info_label.config(text=msg)
        self.show_current_block()

        if count > 1:
            messagebox.showinfo("Mehrere Treffer", f"{count} Treffer gefunden. Du kannst mit 'Nächster'/'Vorheriger' wechseln.")

    def show_current_block(self):
        if not self.blocks:
            return
        idx = self.current_index
        start, end, block = self.blocks[idx]
        header = f"--- Treffer {idx+1} / {len(self.blocks)} --- (Start: {start}, Länge: {end-start} Zeichen)\n\n"
        self.text_area.delete("1.0", tk.END)
        self.text_area.insert(tk.END, header)
        self.text_area.insert(tk.END, block)
        self.text_area.see("1.0")

    def next_hit(self):
        if not self.blocks:
            return
        self.current_index = (self.current_index + 1) % len(self.blocks)
        self.info_label.config(text=f"Treffer {self.current_index+1} / {len(self.blocks)}")
        self.show_current_block()

    def prev_hit(self):
        if not self.blocks:
            return
        self.current_index = (self.current_index - 1) % len(self.blocks)
        self.info_label.config(text=f"Treffer {self.current_index+1} / {len(self.blocks)}")
        self.show_current_block()

    def save_extracted(self):
        if not self.blocks:
            messagebox.showwarning("Nichts zu speichern", "Bitte zuerst extrahieren (Finden & Extrahieren).")
            return
        default_name = f"diagram_order_{self.order_entry.get().strip()}.txt"
        save_path = filedialog.asksaveasfilename(title="Extrakt speichern als",
                                                 defaultextension=".txt",
                                                 initialfile=default_name,
                                                 filetypes=[("Textdateien","*.txt"), ("Alle Dateien","*.*")],
                                                 initialdir=os.getcwd())
        if not save_path:
            return
        _, _, block = self.blocks[self.current_index]
        try:
            with open(save_path, "w", encoding="utf-8") as f:
                f.write(block)
            messagebox.showinfo("Gespeichert", f"Extrakt als:\n{save_path}\ngespeichert.")
        except Exception as e:
            messagebox.showerror("Fehler beim Speichern", str(e))


if __name__ == "__main__":
    app = QETExtractorApp()
    app.mainloop()
