#!/usr/bin/env python3
import sys
import xml.etree.ElementTree as ET
import re
import math

def remove_namespaces(xml_string):
    xml_string = re.sub(r'\sxmlns(:\w+)?=(["\']).*?\2', '', xml_string, flags=re.DOTALL)
    xml_string = re.sub(r'<(/?)[A-Za-z0-9_\-]+:', r'<\1', xml_string)
    xml_string = re.sub(r'(\s)[A-Za-z0-9_\-]+:([A-Za-z0-9_\-]+=)', r'\1\2', xml_string)
    return xml_string

def bmk_prefix(bmk):
    if ":" in bmk:
        return bmk.split(":", 1)[0]
    return bmk

def safe_int(value):
    try:
        return int(float(value))
    except:
        return 0

def assign_new_numbers(sorted_klemmen):
    new_bmk_list = []
    prefix_counts = {}
    for _, original_bmk, *_ in sorted_klemmen:
        if ":" in original_bmk:
            prefix, rest = [s.strip() for s in original_bmk.split(":", 1)]
            try:
                int(rest)
                prefix_counts[prefix] = prefix_counts.get(prefix, 0) + 1
                new_num = prefix_counts[prefix]
                new_bmk = f"{prefix}:{new_num}"
                new_bmk_list.append(new_bmk)
            except ValueError:
                new_bmk_list.append(original_bmk)
        else:
            new_bmk_list.append(original_bmk)
    return new_bmk_list

def adjust_text_position(old_text, new_text, x_str, y_str, rotation_str, alignment, font_str):
    """
    Berechnet die neuen X/Y Koordinaten, um den Ankerpunkt basierend
    auf Textlängenänderung, Ausrichtung und Rotation zu verschieben.
    """
    try:
        x = float(x_str)
        y = float(y_str)
        rotation = float(rotation_str) if rotation_str else 0.0
    except ValueError:
        return x_str, y_str

    delta_len = len(new_text) - len(old_text)
    if delta_len == 0:
        return x_str, y_str

    # Schriftgröße extrahieren (z.B. "Sans Serif,6,-1,5...")
    font_size = 6.0
    if font_str:
        parts = font_str.split(',')
        if len(parts) > 1:
            try:
                font_size = float(parts[1])
            except ValueError:
                pass

    # Durchschnittliche Zeichenbreite in Pixeln schätzen (ca. 60% der Schriftgröße)
    char_width = font_size * 0.6
    delta_px = delta_len * char_width

    shift = 0
    if alignment == "AlignRight":
        shift = delta_px
    elif alignment in ("AlignHCenter", "AlignCenter"):
        shift = delta_px / 2.0

    if shift != 0:
        # Geometrische Verschiebung (Trigonometrie für alle Winkel)
        # In Qt: +X ist rechts, +Y ist unten.
        # Rotation: positiv ist im Uhrzeigersinn.
        rad = math.radians(rotation)
        x -= shift * math.cos(rad)
        y -= shift * math.sin(rad)

    # Formatieren (Schneidet unnötige Nullen ab, um das XML sauber zu halten)
    def format_coord(val):
        formatted = f"{val:.4f}".rstrip('0').rstrip('.')
        return formatted if formatted else "0"

    return format_coord(x), format_coord(y)


def update_qet_file(input_file, output_file):
    try:
        with open(input_file, "r", encoding="utf-8") as f:
            xml_data = f.read()
        xml_data = remove_namespaces(xml_data)
        root = ET.fromstring(xml_data)
    except Exception as e:
        print(f"Fehler beim Parsen der Datei '{input_file}': {e}")
        sys.exit(1)

    klemmen_items = []
    for diagram in root.findall(".//diagram"):
        seite = diagram.get("order", "").strip()
        for elem in diagram.findall(".//element"):
            prop = elem.find("properties/element_type")
            if prop is None or not prop.get("terminal_type"):
                continue

            bmk = ""
            infos = elem.find("elementInformations")
            if infos is not None:
                for info in infos.findall("elementInformation"):
                    if info.get("name", "").lower() == "label" and info.text:
                        bmk = info.text.strip()
                        break
            if not bmk:
                continue

            x_position = elem.get("x", "").strip()
            y_position = elem.get("y", "").strip()
            klemmen_items.append((elem, bmk, seite, x_position, y_position))

    sorted_items = sorted(
        klemmen_items,
        key=lambda item: (
            bmk_prefix(item[1]).lower(),
            safe_int(item[2]),
            safe_int(item[3]),
            safe_int(item[4])
        )
    )

    new_bmk_list = assign_new_numbers(sorted_items)

    for idx, (elem_obj, old_bmk_full, *_ ) in enumerate(sorted_items):
        new_bmk = new_bmk_list[idx]

        # 1. Update der Metadaten
        infos = elem_obj.find("elementInformations")
        if infos is not None:
            for info in infos.findall("elementInformation"):
                if info.get("name", "").lower() == "label":
                    info.text = new_bmk

        # 2. Update der visuellen Texte (mit Geometrie-Korrektur)
        dynamic_texts = elem_obj.find("dynamic_texts")
        if dynamic_texts is not None:
            for dyn_text in dynamic_texts.findall("dynamic_elmt_text"):
                info_name = dyn_text.find("info_name")

                if info_name is not None and info_name.text == "label":
                    text_node = dyn_text.find("text")
                    if text_node is not None:
                        old_text = text_node.text or old_bmk_full

                        # Attribute für die Berechnung auslesen
                        x_attr = dyn_text.get("x", "0")
                        y_attr = dyn_text.get("y", "0")
                        rotation_attr = dyn_text.get("rotation", "0")
                        align_attr = dyn_text.get("Halignment", "AlignLeft")
                        font_attr = dyn_text.get("font", "")

                        # X/Y neu berechnen
                        new_x, new_y = adjust_text_position(
                            old_text, new_bmk, x_attr, y_attr, rotation_attr, align_attr, font_attr
                        )

                        # Neue Koordinaten setzen
                        dyn_text.set("x", new_x)
                        dyn_text.set("y", new_y)

                        # Text aktualisieren
                        text_node.text = new_bmk

    try:
        tree = ET.ElementTree(root)
        tree.write(output_file, encoding="utf-8", xml_declaration=True)
        print(f"Datei erfolgreich aktualisiert und gespeichert in '{output_file}'")
    except Exception as e:
        print(f"Fehler beim Schreiben der aktualisierten Datei: {e}")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Verwendung: python3 Update_Klemmen.py <Input-QET-Datei> <Output-QET-Datei>")
        sys.exit(1)
    update_qet_file(sys.argv[1], sys.argv[2])
