;; ============================================================
;; OMNIFLO JSON-DATEN LADEN UND ABFRAGEN
;; Liest omniflo_boegen.json und omniflo_weichen.json ein.
;; Daten werden als Listen von Assoziationslisten gespeichert.
;;
;; Globale Variablen:
;;   *OMNI-BOEGEN*   - Liste aller Boegen-Eintraege
;;   *OMNI-WEICHEN*  - Liste aller Weichen-Eintraege
;;
;; Funktionen:
;;   (omni:load-data)            - Beide JSON-Dateien laden
;;   (omni:get-bogen sivasid)    - Bogen-Info zu einer SivasId
;;   (omni:get-weiche sivasid)   - Weichen-Info zu einer SivasId
;;   (omni:filter lst key wert)  - Eintraege nach Key/Wert filtern
;; ============================================================


;; --- Datei zeilenweise einlesen ---
(defun omni:read-file-lines (datei / f zeile ergebnis)
  (setq f (open datei "r"))
  (if (null f)
    (progn
      (princ (strcat "\n[OMNI] FEHLER: Datei nicht gefunden: " datei))
      nil
    )
    (progn
      (setq ergebnis nil)
      (while (setq zeile (read-line f))
        (setq ergebnis (cons zeile ergebnis))
      )
      (close f)
      (reverse ergebnis)
    )
  )
)


;; --- Whitespace und Komma am Ende einer Zeile entfernen ---
(defun omni:trim (s / len ch)
  (setq s (vl-string-trim " \t\r\n" s))
  (setq len (strlen s))
  (if (and (> len 0) (= (substr s len 1) ","))
    (setq s (substr s 1 (1- len)))
  )
  (vl-string-trim " \t\r\n" s)
)


;; --- JSON-Wert parsen (String, Zahl, null) ---
(defun omni:parse-value (val-str / len)
  (setq val-str (omni:trim val-str))
  (cond
    ((= val-str "null") nil)
    ((= (substr val-str 1 1) "\"")
      ;; String: Anfuehrungszeichen entfernen
      (setq len (strlen val-str))
      (if (and (> len 1) (= (substr val-str len 1) "\""))
        (substr val-str 2 (- len 2))
        val-str
      )
    )
    (T
      ;; Zahl
      (if (vl-string-search "." val-str)
        (atof val-str)
        (atoi val-str)
      )
    )
  )
)


;; --- Eine Key-Value-Zeile parsen -> dotted pair oder nil ---
(defun omni:parse-kv-line (zeile / pos key rest val)
  (setq zeile (omni:trim zeile))
  ;; Muss mit " beginnen (Key)
  (if (and (> (strlen zeile) 0) (= (substr zeile 1 1) "\""))
    (progn
      ;; Key extrahieren: zweites Anfuehrungszeichen finden
      ;; vl-string-search ist 0-basiert, substr ist 1-basiert
      (setq pos (vl-string-search "\"" zeile 1))
      (if pos
        (progn
          (setq key (substr zeile 2 (1- pos)))
          ;; Rest nach dem schliessenden " extrahieren
          (setq rest (substr zeile (+ pos 2)))
          ;; ":" im Rest finden
          (setq pos (vl-string-search ":" rest))
          (if pos
            (progn
              (setq val (substr rest (+ pos 2)))
              (cons key (omni:parse-value val))
            )
          )
        )
      )
    )
  )
)


;; --- JSON-Array von flachen Objekten parsen ---
(defun omni:parse-json-array (zeilen / in-obj obj ergebnis zeile kv trimmed)
  (setq in-obj nil
        obj    nil
        ergebnis nil
  )
  (foreach zeile zeilen
    (setq trimmed (omni:trim zeile))
    (cond
      ;; Objekt-Start
      ((= trimmed "{")
        (setq in-obj T
              obj    nil
        )
      )
      ;; Objekt-Ende
      ((or (= trimmed "}") (= trimmed "},"))
        (if (and in-obj obj)
          (setq ergebnis (cons (reverse obj) ergebnis))
        )
        (setq in-obj nil)
      )
      ;; Key-Value-Zeile innerhalb eines Objekts
      (in-obj
        (setq kv (omni:parse-kv-line zeile))
        (if kv (setq obj (cons kv obj)))
      )
    )
  )
  (reverse ergebnis)
)


;; --- JSON-Datei laden und als Liste von Alists zurueckgeben ---
(defun omni:load-json (datei / zeilen)
  (setq zeilen (omni:read-file-lines datei))
  (if zeilen
    (omni:parse-json-array zeilen)
  )
)


;; --- Beide Datensaetze laden ---
(defun omni:load-data ( / data-pfad f-boegen f-weichen)
  (setq data-pfad (getenv "DXFM_DATA"))
  (if (null data-pfad)
    (progn
      (princ "\n[OMNI] FEHLER: DXFM_DATA nicht gesetzt!")
      nil
    )
    (progn
      ;; Boegen laden
      (setq f-boegen (strcat data-pfad "/json/omniflo_boegen.json"))
      (setq *OMNI-BOEGEN* (omni:load-json f-boegen))
      (if *OMNI-BOEGEN*
        (princ (strcat "\n[OMNI] " (itoa (length *OMNI-BOEGEN*)) " Boegen geladen."))
        (princ (strcat "\n[OMNI] WARNUNG: Keine Boegen geladen aus " f-boegen))
      )
      ;; Weichen laden
      (setq f-weichen (strcat data-pfad "/json/omniflo_weichen.json"))
      (setq *OMNI-WEICHEN* (omni:load-json f-weichen))
      (if *OMNI-WEICHEN*
        (princ (strcat "\n[OMNI] " (itoa (length *OMNI-WEICHEN*)) " Weichen geladen."))
        (princ (strcat "\n[OMNI] WARNUNG: Keine Weichen geladen aus " f-weichen))
      )
      T
    )
  )
)


;; --- SivasId zu String konvertieren (fuer Vergleich) ---
(defun omni:sivasid-to-str (id)
  (cond
    ((= (type id) 'STR) id)
    ((= (type id) 'INT) (itoa id))
    ((= (type id) 'REAL) (itoa (fix id)))
    (T "")
  )
)


;; --- Eintrag anhand SivasId in einer Liste suchen ---
(defun omni:get-by-sivasid (lst sivasid / such-str eintrag sivasnr gefunden)
  (setq such-str (omni:sivasid-to-str sivasid))
  (setq gefunden nil)
  (foreach eintrag lst
    (if (null gefunden)
      (progn
        (setq sivasnr (cdr (assoc "Sivasnr" eintrag)))
        (if (= (omni:sivasid-to-str sivasnr) such-str)
          (setq gefunden eintrag)
        )
      )
    )
  )
  gefunden
)


;; --- Bogen anhand SivasId abfragen ---
;; Rueckgabe: Assoziationsliste mit allen Eigenschaften oder nil
;; Beispiel: (omni:get-bogen 821104025)
;;   -> (("Sivasnr" . 821104025) ("ProfilTyp" . "APB 110 R 550/22,5...") ...)
(defun omni:get-bogen (sivasid)
  (if (null *OMNI-BOEGEN*) (omni:load-data))
  (omni:get-by-sivasid *OMNI-BOEGEN* sivasid)
)


;; --- Weiche anhand SivasId abfragen ---
;; Rueckgabe: Assoziationsliste mit allen Eigenschaften oder nil
;; Beispiel: (omni:get-weiche 834372001)
;;   -> (("Sivasnr" . 834372001) ("ProfilTyp" . "WEICHE S 45...") ...)
(defun omni:get-weiche (sivasid)
  (if (null *OMNI-WEICHEN*) (omni:load-data))
  (omni:get-by-sivasid *OMNI-WEICHEN* sivasid)
)


;; --- Eintraege nach beliebigem Key/Wert filtern ---
;; lst  = *OMNI-BOEGEN* oder *OMNI-WEICHEN*
;; key  = Schluesselname z.B. "KurvenWinkel"
;; wert = Gesuchter Wert z.B. 45
;; Rueckgabe: Liste aller passenden Eintraege
;;
;; Beispiel: (omni:filter *OMNI-BOEGEN* "KurvenWinkel" 45)
;;   -> Liste aller 45-Grad-Boegen
;; Beispiel: (omni:filter *OMNI-WEICHEN* "WeichenTyp" "Doppelweiche")
;;   -> Liste aller Doppelweichen
(defun omni:filter (lst key wert / eintrag val ergebnis)
  (setq ergebnis nil)
  (foreach eintrag lst
    (setq val (cdr (assoc key eintrag)))
    (if (equal val wert)
      (setq ergebnis (cons eintrag ergebnis))
    )
  )
  (reverse ergebnis)
)


;; --- Einzelnen Wert aus einem Eintrag lesen ---
;; eintrag = Assoziationsliste (Rueckgabe von omni:get-bogen etc.)
;; key     = Schluesselname z.B. "Radius"
;; Beispiel: (omni:val (omni:get-bogen 821104025) "Radius") -> 550
(defun omni:val (eintrag key)
  (cdr (assoc key eintrag))
)


;; --- SivasNummern aller Boegen fuer einen bestimmten Winkel ---
;; winkel = KurvenWinkel z.B. 90, 45, 22.5
;; Rueckgabe: Liste von SivasIds (gemischt INT/STR)
;; Beispiel: (omni:boegen-ids 45) -> (821104021 821104026 "821104026+0_B10071" ...)
(defun omni:boegen-ids (winkel / lst eintrag ergebnis)
  (if (null *OMNI-BOEGEN*) (omni:load-data))
  (setq ergebnis nil)
  (foreach eintrag *OMNI-BOEGEN*
    (if (equal (cdr (assoc "KurvenWinkel" eintrag)) winkel)
      (setq ergebnis (cons (cdr (assoc "Sivasnr" eintrag)) ergebnis))
    )
  )
  (reverse ergebnis)
)


;; --- SivasNummern aller Boegen, gruppiert nach Winkel ---
;; Rueckgabe: Assoziationsliste ((180 . (id ...)) (90 . (id ...)) ...)
;; Beispiel: (omni:boegen-ids-alle)
;;   -> ((180 821104043) (90 821104022 821104030 ...) (67.5 ...) (45 ...) (22.5 ...))
(defun omni:boegen-ids-alle ()
  (list
    (cons 180  (omni:boegen-ids 180))
    (cons 90   (omni:boegen-ids 90))
    (cons 67.5 (omni:boegen-ids 67.5))
    (cons 45   (omni:boegen-ids 45))
    (cons 22.5 (omni:boegen-ids 22.5))
  )
)


;; --- SivasNummern von Weichen nach Winkel und WeichenTyp ---
;; winkel     = KurvenWinkel z.B. 90, 45
;; weichentyp = "Einzelweiche", "Doppelweiche", "Dreiwegeweiche"
;; Beispiel: (omni:weichen-ids 90 "Einzelweiche")
(defun omni:weichen-ids (winkel weichentyp / eintrag ergebnis)
  (if (null *OMNI-WEICHEN*) (omni:load-data))
  (setq ergebnis nil)
  (foreach eintrag *OMNI-WEICHEN*
    (if (and (equal (cdr (assoc "KurvenWinkel" eintrag)) winkel)
             (= (cdr (assoc "WeichenTyp" eintrag)) weichentyp)
        )
      (setq ergebnis (cons (cdr (assoc "Sivasnr" eintrag)) ergebnis))
    )
  )
  (reverse ergebnis)
)


;; --- SivasNummern von Weichenkombinationen (Delta/Star) ---
;; typ = "DELTA" oder "STAR"
;; Filtert anhand ProfilTyp-Inhalt
(defun omni:weichen-kombi-ids (typ / eintrag ergebnis profil)
  (if (null *OMNI-WEICHEN*) (omni:load-data))
  (setq ergebnis nil)
  (foreach eintrag *OMNI-WEICHEN*
    (setq profil (cdr (assoc "ProfilTyp" eintrag)))
    (if (and profil (vl-string-search typ profil))
      (setq ergebnis (cons (cdr (assoc "Sivasnr" eintrag)) ergebnis))
    )
  )
  (reverse ergebnis)
)


;; --- Alle Weichen-SivasNummern gruppiert ---
;; Rueckgabe: Assoziationsliste nach Kategorie
;; Beispiel: (omni:weichen-ids-alle)
;;   -> (("W90-Einfach" id1 id2 ...)
;;       ("W90-Doppel" ...)
;;       ...
;;       ("WKomb-Delta" ...)
;;       ("WKomb-Star" ...))
(defun omni:weichen-ids-alle ()
  (list
    ;; 90 Grad
    (cons "W90-Einfach"   (omni:weichen-ids 90 "Einzelweiche"))
    (cons "W90-Doppel"    (omni:weichen-ids 90 "Doppelweiche"))
    (cons "W90-Dreiwege"  (omni:weichen-ids 90 "Dreiwegeweiche"))
    ;; 45 Grad
    (cons "W45-Einfach"   (omni:weichen-ids 45 "Einzelweiche"))
    (cons "W45-Doppel"    (omni:weichen-ids 45 "Doppelweiche"))
    (cons "W45-Dreiwege"  (omni:weichen-ids 45 "Dreiwegeweiche"))
    ;; Parallel (KurvenWinkel = 0)
    (cons "WP-Einfach"    (omni:weichen-ids 0 "Einzelweiche"))
    (cons "WP-Doppel"     (omni:weichen-ids 0 "Doppelweiche"))
    (cons "WP-Dreiwege"   (omni:weichen-ids 0 "Dreiwegeweiche"))
    ;; Weichenkoerper (KurvenWinkel = 22.5)
    (cons "WK-Einfach"    (omni:weichen-ids 22.5 "Einzelweiche"))
    (cons "WK-Doppel"     (omni:weichen-ids 22.5 "Doppelweiche"))
    (cons "WK-Dreiwege"   (omni:weichen-ids 22.5 "Dreiwegeweiche"))
    ;; Weichenkombinationen
    (cons "WKomb-Delta"   (omni:weichen-kombi-ids "DELTA"))
    (cons "WKomb-Star"    (omni:weichen-kombi-ids "STAR"))
  )
)


;; --- BricsCAD-Befehl: Daten laden ---
(defun c:OMNI_LOAD ()
  (omni:load-data)
  (princ)
)


;; --- BricsCAD-Befehl: Bogen-Info anzeigen ---
(defun c:OMNI_INFO_BOGEN ( / id eintrag)
  (if (null *OMNI-BOEGEN*) (omni:load-data))
  (setq id (getstring T "\nSivasId des Bogens eingeben: "))
  (if (= id "") (princ "\nAbgebrochen.")
    (progn
      ;; Versuch als Zahl, dann als String
      (setq eintrag (omni:get-bogen (if (/= (atoi id) 0) (atoi id) id)))
      (if eintrag
        (progn
          (princ (strcat "\n  ProfilTyp:    " (omni:sivasid-to-str (omni:val eintrag "ProfilTyp"))))
          (princ (strcat "\n  Radius:       " (itoa (fix (omni:val eintrag "Radius")))))
          (princ (strcat "\n  KurvenWinkel: " (rtos (omni:val eintrag "KurvenWinkel") 2 1)))
          (princ (strcat "\n  Breite:       " (itoa (fix (omni:val eintrag "Breite")))))
          (princ (strcat "\n  Laenge:       " (itoa (fix (omni:val eintrag "Länge")))))
          (princ (strcat "\n  Antriebsart:  " (itoa (fix (omni:val eintrag "Antriebsart")))))
        )
        (princ (strcat "\nKein Bogen mit SivasId '" id "' gefunden."))
      )
    )
  )
  (princ)
)


;; --- BricsCAD-Befehl: Weichen-Info anzeigen ---
(defun c:OMNI_INFO_WEICHE ( / id eintrag wkl)
  (if (null *OMNI-WEICHEN*) (omni:load-data))
  (setq id (getstring T "\nSivasId der Weiche eingeben: "))
  (if (= id "") (princ "\nAbgebrochen.")
    (progn
      (setq eintrag (omni:get-weiche (if (/= (atoi id) 0) (atoi id) id)))
      (if eintrag
        (progn
          (princ (strcat "\n  ProfilTyp:      " (omni:sivasid-to-str (omni:val eintrag "ProfilTyp"))))
          (princ (strcat "\n  WeichenTyp:     " (omni:sivasid-to-str (omni:val eintrag "WeichenTyp"))))
          (setq wkl (omni:val eintrag "KurvenWinkel"))
          (princ (strcat "\n  KurvenWinkel:   " (if (= (type wkl) 'INT) (itoa wkl) (rtos wkl 2 1))))
          (princ (strcat "\n  Schaltungstyp:  " (omni:sivasid-to-str (omni:val eintrag "Schaltungstyp"))))
          (princ (strcat "\n  Breite:         " (itoa (fix (omni:val eintrag "Breite")))))
          (princ (strcat "\n  Laenge:         " (itoa (fix (omni:val eintrag "Länge")))))
          (princ (strcat "\n  KurvenRichtung: " (itoa (fix (omni:val eintrag "KurvenRichtung")))))
          (if (omni:val eintrag "WeichenkörperLänge")
            (princ (strcat "\n  WK-Laenge:      " (rtos (omni:val eintrag "WeichenkörperLänge") 2 1)))
          )
        )
        (princ (strcat "\nKeine Weiche mit SivasId '" id "' gefunden."))
      )
    )
  )
  (princ)
)


;; ============================================================
;; OMNIFLO BOGEN-DIALOG
;; Generischer Dialog fuer Bogen-Auswahl nach Winkel
;; ============================================================


;; --- Detail-Felder im Dialog aktualisieren ---
;; Wird bei Dropdown-Aenderung aufgerufen (action_tile callback)
(defun omni:bogen-dlg-update (idx-str / idx eintrag wkl)
  (setq idx (atoi idx-str))
  (setq eintrag (nth idx *OMNI-DLG-BOEGEN*))
  (if eintrag
    (progn
      (set_tile "val_sivasnr"
        (omni:sivasid-to-str (omni:val eintrag "Sivasnr")))
      (setq wkl (omni:val eintrag "KurvenWinkel"))
      (set_tile "val_winkel"
        (if (= (type wkl) 'INT) (strcat (itoa wkl) " Grad")
          (strcat (rtos wkl 2 1) " Grad")
        )
      )
      (set_tile "val_radius"
        (itoa (fix (omni:val eintrag "Radius"))))
      (set_tile "val_breite"
        (itoa (fix (omni:val eintrag "Breite"))))
      (set_tile "val_laenge"
        (itoa (fix (omni:val eintrag "Länge"))))
    )
  )
)


;; --- Bogen-Auswahl-Dialog oeffnen ---
;; winkel = KurvenWinkel (90, 67.5, 45, 22.5, 180)
;; Rueckgabe: gewaehlter Bogen-Eintrag (alist) oder nil bei Abbruch
(defun omni:bogen-dialog (winkel / dcl-pfad dat boegen-liste
                           profil-liste ergebnis)
  (if (null *OMNI-BOEGEN*) (omni:load-data))

  ;; Boegen nach Winkel filtern
  (setq boegen-liste (omni:filter *OMNI-BOEGEN* "KurvenWinkel" winkel))
  (if (null boegen-liste)
    (progn
      (alert (strcat "Keine Boegen fuer "
        (if (= (type winkel) 'INT) (itoa winkel) (rtos winkel 2 1))
        " Grad gefunden."))
      nil
    )
    (progn
      ;; In globaler Variable fuer Dialog-Callbacks speichern
      (setq *OMNI-DLG-BOEGEN* boegen-liste)

      ;; ProfilTyp-Liste fuer Dropdown aufbauen
      (setq profil-liste
        (mapcar '(lambda (e) (cdr (assoc "ProfilTyp" e))) boegen-liste))

      ;; DCL laden
      (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/omniflo_boegen.dcl"))
      (setq dat (load_dialog dcl-pfad))
      (if (not (new_dialog "omniflo_boegen" dat))
        (progn (alert "Bogen-Dialog konnte nicht geladen werden.") nil)
        (progn
          ;; Dropdown befuellen
          (start_list "bogenart")
          (mapcar 'add_list profil-liste)
          (end_list)
          (set_tile "bogenart" "0")

          ;; Startwerte anzeigen
          (omni:bogen-dlg-update "0")

          ;; Callback bei Dropdown-Aenderung
          (action_tile "bogenart" "(omni:bogen-dlg-update $value)")

          ;; OK/Abbrechen
          (action_tile "accept"
            "(setq ergebnis (atoi (get_tile \"bogenart\"))) (done_dialog 1)")
          (action_tile "cancel" "(done_dialog 0)")

          (start_dialog)
          (unload_dialog dat)

          ;; Gewaehlten Eintrag zurueckgeben
          (if ergebnis
            (nth ergebnis *OMNI-DLG-BOEGEN*)
            nil
          )
        )
      )
    )
  )
)


;; ============================================================
;; OMNIFLO MODUL-BEFEHLE
;; ============================================================

;; --- Omniflo / Boegen ---
(defun c:OMNI_APB_630_90 ( / eintrag)
  (setq eintrag (omni:bogen-dialog 90))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[BOGEN] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_APB_550_675 ( / eintrag)
  (setq eintrag (omni:bogen-dialog 67.5))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[BOGEN] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_APB_630_45 ( / eintrag)
  (setq eintrag (omni:bogen-dialog 45))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[BOGEN] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_APB_550_225 ( / eintrag)
  (setq eintrag (omni:bogen-dialog 22.5))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[BOGEN] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_APB_650_180 ( / eintrag)
  (setq eintrag (omni:bogen-dialog 180))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[BOGEN] Abgebrochen.")
  )
  (princ)
)

;; --- Omniflo / Aluprofil Gerade ---
(defun c:OMNI_AP110 ()
  (princ "\n[DUMMY] AP 110 Aluprofil Gerade")
  (princ)
)

;; ============================================================
;; OMNIFLO WEICHEN-DIALOG
;; Generischer Dialog fuer Weichen-Auswahl nach Winkel/Typ
;; mit Filter fuer Schaltungstyp und Richtung
;; ============================================================


;; --- Aktuelle Filterwerte aus Radio-Buttons lesen ---
(defun omni:weichen-get-filter ( / sch ri)
  (setq sch "alle")
  (if (= (get_tile "sch_m") "1") (setq sch "M"))
  (if (= (get_tile "sch_p") "1") (setq sch "P"))
  (setq ri "alle")
  (if (= (get_tile "ri_links") "1")  (setq ri "1"))
  (if (= (get_tile "ri_rechts") "1") (setq ri "2"))
  (list sch ri)
)


;; --- Gefilterte Weichen-Liste aufbauen ---
;; basis-liste = alle Weichen fuer den gewaehlten Winkel/Typ
;; sch-filter  = "M", "P" oder "alle"
;; ri-filter   = "1", "2" oder "alle"
(defun omni:weichen-filter-liste (basis-liste sch-filter ri-filter / eintrag sch kr ergebnis)
  (setq ergebnis nil)
  (foreach eintrag basis-liste
    (setq sch (cdr (assoc "Schaltungstyp" eintrag)))
    (setq kr  (cdr (assoc "KurvenRichtung" eintrag)))
    (if (and
          (or (= sch-filter "alle") (= sch sch-filter))
          (or (= ri-filter "alle")
              (= (omni:sivasid-to-str kr) ri-filter))
        )
      (setq ergebnis (cons eintrag ergebnis))
    )
  )
  (reverse ergebnis)
)


;; --- Dropdown mit gefilterter Liste neu befuellen ---
(defun omni:weichen-dlg-refresh ( / filter sch-f ri-f gefiltert profil-liste)
  (setq filter (omni:weichen-get-filter))
  (setq sch-f (car filter))
  (setq ri-f  (cadr filter))
  (setq gefiltert (omni:weichen-filter-liste *OMNI-DLG-WEICHEN-BASIS* sch-f ri-f))
  (setq *OMNI-DLG-WEICHEN* gefiltert)

  ;; Dropdown neu befuellen
  (setq profil-liste
    (mapcar '(lambda (e) (cdr (assoc "ProfilTyp" e))) gefiltert))
  (start_list "profiltyp")
  (mapcar 'add_list profil-liste)
  (end_list)

  ;; Ersten Eintrag anzeigen (falls vorhanden)
  (if gefiltert
    (progn
      (set_tile "profiltyp" "0")
      (omni:weichen-dlg-update "0")
    )
    (progn
      (set_tile "val_sivasnr" "---")
      (set_tile "val_winkel"  "---")
      (set_tile "val_breite"  "---")
      (set_tile "val_laenge"  "---")
    )
  )
)


;; --- Detail-Felder im Weichen-Dialog aktualisieren ---
(defun omni:weichen-dlg-update (idx-str / idx eintrag wkl)
  (setq idx (atoi idx-str))
  (setq eintrag (nth idx *OMNI-DLG-WEICHEN*))
  (if eintrag
    (progn
      (set_tile "val_sivasnr"
        (omni:sivasid-to-str (omni:val eintrag "Sivasnr")))
      (setq wkl (omni:val eintrag "KurvenWinkel"))
      (set_tile "val_winkel"
        (if (= (type wkl) 'INT) (strcat (itoa wkl) " Grad")
          (strcat (rtos wkl 2 1) " Grad")
        )
      )
      (set_tile "val_breite"
        (itoa (fix (omni:val eintrag "Breite"))))
      (set_tile "val_laenge"
        (itoa (fix (omni:val eintrag "Länge"))))
    )
  )
)


;; --- Weichen-Auswahl-Dialog oeffnen ---
;; winkel     = KurvenWinkel (90, 45, 0, 22.5)
;; weichentyp = "Einzelweiche", "Doppelweiche", "Dreiwegeweiche" oder nil fuer alle
;; Rueckgabe: gewaehlter Weichen-Eintrag (alist) oder nil bei Abbruch
(defun omni:weichen-dialog (winkel weichentyp / dcl-pfad dat basis-liste
                             profil-liste ergebnis)
  (if (null *OMNI-WEICHEN*) (omni:load-data))

  ;; Weichen nach Winkel filtern (nil = alle Winkel)
  (if winkel
    (setq basis-liste (omni:filter *OMNI-WEICHEN* "KurvenWinkel" winkel))
    (setq basis-liste *OMNI-WEICHEN*)
  )

  ;; Optional nach WeichenTyp filtern
  (if weichentyp
    (setq basis-liste
      (vl-remove-if-not
        '(lambda (e) (= (cdr (assoc "WeichenTyp" e)) weichentyp))
        basis-liste))
  )

  (if (null basis-liste)
    (progn
      (alert (strcat "Keine Weichen fuer "
        (cond
          ((null winkel) "alle Winkel")
          ((= (type winkel) 'INT) (strcat (itoa winkel) " Grad"))
          (T (strcat (rtos winkel 2 1) " Grad"))
        )
        (if weichentyp (strcat " / " weichentyp) "")
        " gefunden."))
      nil
    )
    (progn
      ;; Basis-Liste und gefilterte Liste in globalen Variablen speichern
      (setq *OMNI-DLG-WEICHEN-BASIS* basis-liste)
      (setq *OMNI-DLG-WEICHEN* basis-liste)

      ;; ProfilTyp-Liste fuer Dropdown aufbauen
      (setq profil-liste
        (mapcar '(lambda (e) (cdr (assoc "ProfilTyp" e))) basis-liste))

      ;; DCL laden
      (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/omniflo_weichen.dcl"))
      (setq dat (load_dialog dcl-pfad))
      (if (not (new_dialog "omniflo_weichen" dat))
        (progn (alert "Weichen-Dialog konnte nicht geladen werden.") nil)
        (progn
          ;; Dropdown befuellen
          (start_list "profiltyp")
          (mapcar 'add_list profil-liste)
          (end_list)
          (set_tile "profiltyp" "0")

          ;; Startwerte anzeigen
          (omni:weichen-dlg-update "0")

          ;; Callback bei Dropdown-Aenderung
          (action_tile "profiltyp" "(omni:weichen-dlg-update $value)")

          ;; Callbacks fuer Filter-Radio-Buttons (alle loesen Refresh aus)
          (action_tile "sch_alle" "(omni:weichen-dlg-refresh)")
          (action_tile "sch_m"   "(omni:weichen-dlg-refresh)")
          (action_tile "sch_p"   "(omni:weichen-dlg-refresh)")
          (action_tile "ri_alle"   "(omni:weichen-dlg-refresh)")
          (action_tile "ri_links"  "(omni:weichen-dlg-refresh)")
          (action_tile "ri_rechts" "(omni:weichen-dlg-refresh)")

          ;; OK/Abbrechen
          (action_tile "accept"
            "(setq ergebnis (atoi (get_tile \"profiltyp\"))) (done_dialog 1)")
          (action_tile "cancel" "(done_dialog 0)")

          (start_dialog)
          (unload_dialog dat)

          ;; Gewaehlten Eintrag zurueckgeben
          (if ergebnis
            (nth ergebnis *OMNI-DLG-WEICHEN*)
            nil
          )
        )
      )
    )
  )
)


;; ============================================================
;; OMNIFLO DXF-BLOCK EINFUEGEN
;; Fuegt eine DXF-Datei aus data/omniflo/ als Block ein.
;; Der Benutzer waehlt den Einfuegepunkt und Drehwinkel.
;; ============================================================

;; --- DXF-Datei als Block einfuegen ---
;; sivasnr-str = SivasNr als String (Dateiname ohne .dxf)
;; Rueckgabe: Einfuegepunkt oder nil bei Abbruch
(defun omni:insert-dxf (sivasnr-str / dxf-pfad data-pfad pt
                         oldOsnap oldCmdEcho oldLayer)
  (setq data-pfad (getenv "DXFM_DATA"))
  (if (null data-pfad)
    (progn
      (princ "\n[OMNI] FEHLER: DXFM_DATA nicht gesetzt!")
      nil
    )
    (progn
      (setq dxf-pfad (strcat data-pfad "/omniflo/" sivasnr-str ".dxf"))
      (if (not (findfile dxf-pfad))
        (progn
          (princ (strcat "\n[OMNI] FEHLER: DXF nicht gefunden: " dxf-pfad))
          nil
        )
        (progn
          (setq pt (getpoint "\nEinfuegepunkt waehlen: "))
          (if (null pt)
            (progn (princ "\n[OMNI] Abgebrochen.") nil)
            (progn
              ;; Einstellungen sichern
              (setq oldOsnap  (getvar "OSMODE"))
              (setq oldCmdEcho (getvar "CMDECHO"))
              (setq oldLayer  (getvar "CLAYER"))
              (setvar "CMDECHO" 0)

              ;; Block einfuegen mit Winkelabfrage (pause)
              (command "_.INSERT" dxf-pfad pt "" "" pause)

              ;; Einstellungen wiederherstellen
              (setvar "OSMODE" oldOsnap)
              (setvar "CMDECHO" oldCmdEcho)
              (setvar "CLAYER" oldLayer)

              (princ (strcat "\n[OMNI] " sivasnr-str " eingefuegt."))
              pt
            )
          )
        )
      )
    )
  )
)


;; --- Eintrag aus Dialog-Ergebnis einfuegen ---
;; Nimmt einen Eintrag (alist) und fuegt die zugehoerige DXF ein.
(defun omni:insert-from-entry (eintrag / sivasnr-str)
  (if eintrag
    (progn
      (setq sivasnr-str (omni:sivasid-to-str (omni:val eintrag "Sivasnr")))
      (princ (strcat "\n[OMNI] Einfuegen: "
        (omni:val eintrag "ProfilTyp") " (" sivasnr-str ")"))
      (omni:insert-dxf sivasnr-str)
    )
  )
)


;; ============================================================
;; OMNIFLO WEICHEN-BEFEHLE
;; ============================================================

;; --- Omniflo / Weiche 90 Grad ---
(defun c:OMNI_W90_Einfach ( / eintrag)
  (setq eintrag (omni:weichen-dialog 90 "Einzelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_W90_Doppel ( / eintrag)
  (setq eintrag (omni:weichen-dialog 90 "Doppelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_W90_Dreiwege ( / eintrag)
  (setq eintrag (omni:weichen-dialog 90 "Dreiwegeweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

;; --- Omniflo / Weiche 45 Grad ---
(defun c:OMNI_W45_Einfach ( / eintrag)
  (setq eintrag (omni:weichen-dialog 45 "Einzelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_W45_Doppel ( / eintrag)
  (setq eintrag (omni:weichen-dialog 45 "Doppelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_W45_Dreiwege ( / eintrag)
  (setq eintrag (omni:weichen-dialog 45 "Dreiwegeweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

;; --- Omniflo / Weichen Parallel ---
(defun c:OMNI_WP_Einfach ( / eintrag)
  (setq eintrag (omni:weichen-dialog 0 "Einzelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_WP_Doppel ( / eintrag)
  (setq eintrag (omni:weichen-dialog 0 "Doppelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_WP_Dreiwege ( / eintrag)
  (setq eintrag (omni:weichen-dialog 0 "Dreiwegeweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

;; --- Omniflo / Weichenkoerper ---
(defun c:OMNI_WK_Einfach ( / eintrag)
  (setq eintrag (omni:weichen-dialog 22.5 "Einzelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_WK_Doppel ( / eintrag)
  (setq eintrag (omni:weichen-dialog 22.5 "Doppelweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_WK_Dreiwege ( / eintrag)
  (setq eintrag (omni:weichen-dialog 22.5 "Dreiwegeweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

;; --- Omniflo / Weichenkombinationen ---
(defun c:OMNI_WKomb_Delta ( / eintrag)
  (setq eintrag (omni:weichen-dialog nil "Deltaweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

(defun c:OMNI_WKomb_Star ( / eintrag)
  (setq eintrag (omni:weichen-dialog nil "Sternweiche"))
  (if eintrag
    (omni:insert-from-entry eintrag)
    (princ "\n[WEICHE] Abgebrochen.")
  )
  (princ)
)

;; --- Omniflo / TEF Elemente ---
(defun c:OMNI_TEF_UmlenkR ()
  (princ "\n[DUMMY] Umlenkspannst. rechts fuer TEF links")
  (princ)
)

(defun c:OMNI_TEF_UmlenkL ()
  (princ "\n[DUMMY] Umlenkspannst. links fuer TEF rechts")
  (princ)
)

(defun c:OMNI_TEF_AntriebL ()
  (princ "\n[DUMMY] Antriebst. links fuer TEF links")
  (princ)
)

(defun c:OMNI_TEF_AntriebR ()
  (princ "\n[DUMMY] Antriebst. rechts fuer TEF rechts")
  (princ)
)

(defun c:OMNI_TEF_Gerade ()
  (princ "\n[DUMMY] TEF Gerade")
  (princ)
)

;; --- Omniflo / KettenFoerderer ---
(defun c:OMNI_KettenFoerderer ()
  (princ "\n[DUMMY] KettenFoerderer")
  (princ)
)
