WME Segment Splitter

Teilt Straßensegmente automatisch in gleich große Stücke auf - mit Vorschau, Multi-Segment, Presets und mehr

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         WME Segment Splitter
// @namespace    https://greasyfork.org/de/users/863740-horst-wittlich
// @version      2026.02.10
// @description  Teilt Straßensegmente automatisch in gleich große Stücke auf - mit Vorschau, Multi-Segment, Presets und mehr
// @author       WME Script
// @match        https://www.waze.com/editor*
// @match        https://www.waze.com/*/editor*
// @match        https://beta.waze.com/editor*
// @match        https://beta.waze.com/*/editor*
// @exclude      https://www.waze.com/user/*
// @grant        none
// @license      MIT
// ==/UserScript==

/* global W, OpenLayers, getWmeSdk */

(function() {
    'use strict';

    const SCRIPT_NAME = 'WME Segment Splitter';
    const SCRIPT_VERSION = '2026.02.10';
    const SCRIPT_ID = 'wme-segment-splitter';
    
    // Übersetzungen - DE, EN, IT, ES, FR, NL
    const TRANSLATIONS = {
        en: {
            noSegmentSelected: 'No segment selected',
            selectSegments: 'Select one or more road segments',
            segmentsSelected: 'segments selected',
            totalLength: 'Total length',
            segmentSelected: 'Segment selected',
            length: 'Length',
            street: 'Street',
            geometryNodes: 'Geometry nodes',
            lock: 'Lock',
            unnamed: 'Unnamed',
            presets: 'Presets',
            selectPreset: '-- Select preset --',
            load: 'Load',
            delete: 'Delete',
            presetName: 'Preset name',
            save: 'Save',
            countParts: 'Number of parts',
            parts: 'parts',
            fixedDistance: 'Fixed distance',
            meters: 'Meters',
            percentage: 'Percentage',
            commaSeparated: 'Comma separated',
            atGeometryNodes: 'At geometry nodes',
            manual: 'Manual',
            addPosition: 'Add position:',
            addPoint: '+ Add point',
            noPointsSet: 'No points set - use slider above',
            deleteAllPoints: 'Delete all points',
            advancedOptions: 'Advanced options',
            startPoint: 'Start point:',
            offsetFromStart: 'Offset from start:',
            safety: 'Safety',
            enforceMinLength: 'Enforce minimum length',
            tooShortMerged: 'Too short segments will be merged',
            checkLockLevel: 'Check lock level',
            protectRoundabouts: 'Protect roundabouts',
            warnRamps: 'Warn on ramps',
            display: 'Display',
            previewOnMap: 'Preview on map',
            groupUndo: 'Group undo',
            importExport: 'Import/Export',
            export: 'Export',
            import: 'Import',
            preview: 'Preview:',
            splitSegment: '✂️ Split segment',
            repeatLast: '🔄 Repeat last action',
            processStreet: '📦 Process entire street',
            actionsRemaining: 'actions remaining today',
            maxSplitsPerSegment: 'Max splits/segment',
            debug: 'Debug',
            positionExists: 'Position already exists',
            noSegmentsSelected: 'No segments selected',
            dailyLimitReached: 'Daily limit reached! Maximum',
            actionsPerDay: 'actions per day.',
            tooManySplits: 'Too many splits',
            maximum: 'Maximum',
            splitsCreated: 'splits created!',
            splitsDone: 'splits done',
            errors: 'errors',
            noSplitsDone: 'No splits done',
            error: 'Error',
            noLastAction: 'No last action available',
            selectOneSegment: 'Please select exactly one segment',
            noStreetAssignment: 'Segment has no street assignment',
            noSegmentsFound: 'No segments found',
            processSegments: 'Process segments of street',
            splitsOnStreet: 'splits done',
            importSuccess: 'Import successful!',
            importFailed: 'Import failed: Invalid file',
            presetSaved: 'Preset saved',
            presetLoaded: 'Preset loaded',
            presetDeleted: 'Preset deleted',
            enterPresetName: 'Please enter preset name',
            segmentLocked: 'Segment is locked higher',
            thanYourRank: 'than your rank',
            partOfRoundabout: 'Segment is part of a roundabout',
            isRamp: 'Segment is a ramp',
            offsetLarger: 'Offset larger than segment length',
            unknownMode: 'Unknown mode',
            noSplitPoints: 'No split points (segment too short or no points set)'
        },
        de: {
            noSegmentSelected: 'Kein Segment ausgewählt',
            selectSegments: 'Wähle ein oder mehrere Straßensegmente aus',
            segmentsSelected: 'Segmente ausgewählt',
            totalLength: 'Gesamtlänge',
            segmentSelected: 'Segment ausgewählt',
            length: 'Länge',
            street: 'Straße',
            geometryNodes: 'Geometry-Nodes',
            lock: 'Lock',
            unnamed: 'Unbenannt',
            presets: 'Presets',
            selectPreset: '-- Preset wählen --',
            load: 'Laden',
            delete: 'Löschen',
            presetName: 'Preset-Name',
            save: 'Speichern',
            countParts: 'Anzahl Teile',
            parts: 'Teile',
            fixedDistance: 'Feste Abstände',
            meters: 'Meter',
            percentage: 'Prozentual',
            commaSeparated: 'Kommagetrennt',
            atGeometryNodes: 'An Geometry-Nodes',
            manual: 'Manuell',
            addPosition: 'Position hinzufügen:',
            addPoint: '+ Punkt hinzufügen',
            noPointsSet: 'Keine Punkte gesetzt - nutze den Slider oben',
            deleteAllPoints: 'Alle Punkte löschen',
            advancedOptions: 'Erweiterte Optionen',
            startPoint: 'Startpunkt:',
            offsetFromStart: 'Offset vom Start:',
            safety: 'Sicherheit',
            enforceMinLength: 'Mindestlänge erzwingen',
            tooShortMerged: 'Zu kurze Segmente werden zusammengelegt',
            checkLockLevel: 'Lock-Level prüfen',
            protectRoundabouts: 'Kreisverkehre schützen',
            warnRamps: 'Bei Rampen warnen',
            display: 'Anzeige',
            previewOnMap: 'Vorschau auf Karte',
            groupUndo: 'Undo gruppieren',
            importExport: 'Import/Export',
            export: 'Exportieren',
            import: 'Importieren',
            preview: 'Vorschau:',
            splitSegment: '✂️ Segment aufteilen',
            repeatLast: '🔄 Letzte Aktion wiederholen',
            processStreet: '📦 Ganze Straße bearbeiten',
            actionsRemaining: 'Aktionen übrig heute',
            maxSplitsPerSegment: 'Max Splits/Segment',
            debug: 'Debug',
            positionExists: 'Position bereits vorhanden',
            noSegmentsSelected: 'Keine Segmente ausgewählt',
            dailyLimitReached: 'Tageslimit erreicht! Maximal',
            actionsPerDay: 'Aktionen pro Tag.',
            tooManySplits: 'Zu viele Splits',
            maximum: 'Maximum',
            splitsCreated: 'Schnittpunkte erstellt!',
            splitsDone: 'Splits durchgeführt',
            errors: 'Fehler',
            noSplitsDone: 'Keine Splits durchgeführt',
            error: 'Fehler',
            noLastAction: 'Keine letzte Aktion vorhanden',
            selectOneSegment: 'Bitte genau ein Segment auswählen',
            noStreetAssignment: 'Segment hat keine Straßenzuordnung',
            noSegmentsFound: 'Keine Segmente gefunden',
            processSegments: 'Segmente der Straße bearbeiten',
            splitsOnStreet: 'Splits durchgeführt',
            importSuccess: 'Import erfolgreich!',
            importFailed: 'Import fehlgeschlagen: Ungültige Datei',
            presetSaved: 'Preset gespeichert',
            presetLoaded: 'Preset geladen',
            presetDeleted: 'Preset gelöscht',
            enterPresetName: 'Bitte Preset-Namen eingeben',
            segmentLocked: 'Segment ist höher gelockt',
            thanYourRank: 'als dein Rang',
            partOfRoundabout: 'Segment ist Teil eines Kreisverkehrs',
            isRamp: 'Segment ist eine Rampe',
            offsetLarger: 'Offset größer als Segmentlänge',
            unknownMode: 'Unbekannter Modus',
            noSplitPoints: 'Keine Schnittpunkte (Segment zu kurz oder keine Punkte gesetzt)'
        },
        it: {
            noSegmentSelected: 'Nessun segmento selezionato',
            selectSegments: 'Seleziona uno o più segmenti stradali',
            segmentsSelected: 'segmenti selezionati',
            totalLength: 'Lunghezza totale',
            segmentSelected: 'Segmento selezionato',
            length: 'Lunghezza',
            street: 'Strada',
            geometryNodes: 'Nodi geometria',
            lock: 'Blocco',
            unnamed: 'Senza nome',
            presets: 'Preset',
            selectPreset: '-- Seleziona preset --',
            load: 'Carica',
            delete: 'Elimina',
            presetName: 'Nome preset',
            save: 'Salva',
            countParts: 'Numero di parti',
            parts: 'parti',
            fixedDistance: 'Distanza fissa',
            meters: 'Metri',
            percentage: 'Percentuale',
            commaSeparated: 'Separati da virgola',
            atGeometryNodes: 'Ai nodi geometria',
            manual: 'Manuale',
            addPosition: 'Aggiungi posizione:',
            addPoint: '+ Aggiungi punto',
            noPointsSet: 'Nessun punto impostato - usa lo slider sopra',
            deleteAllPoints: 'Elimina tutti i punti',
            advancedOptions: 'Opzioni avanzate',
            startPoint: 'Punto di partenza:',
            offsetFromStart: 'Offset dall\'inizio:',
            safety: 'Sicurezza',
            enforceMinLength: 'Applica lunghezza minima',
            tooShortMerged: 'I segmenti troppo corti verranno uniti',
            checkLockLevel: 'Controlla livello blocco',
            protectRoundabouts: 'Proteggi rotatorie',
            warnRamps: 'Avvisa per rampe',
            display: 'Visualizzazione',
            previewOnMap: 'Anteprima su mappa',
            groupUndo: 'Raggruppa annulla',
            importExport: 'Importa/Esporta',
            export: 'Esporta',
            import: 'Importa',
            preview: 'Anteprima:',
            splitSegment: '✂️ Dividi segmento',
            repeatLast: '🔄 Ripeti ultima azione',
            processStreet: '📦 Elabora intera strada',
            actionsRemaining: 'azioni rimanenti oggi',
            maxSplitsPerSegment: 'Max divisioni/segmento',
            debug: 'Debug',
            positionExists: 'Posizione già esistente',
            noSegmentsSelected: 'Nessun segmento selezionato',
            dailyLimitReached: 'Limite giornaliero raggiunto! Massimo',
            actionsPerDay: 'azioni al giorno.',
            tooManySplits: 'Troppe divisioni',
            maximum: 'Massimo',
            splitsCreated: 'divisioni create!',
            splitsDone: 'divisioni effettuate',
            errors: 'errori',
            noSplitsDone: 'Nessuna divisione effettuata',
            error: 'Errore',
            noLastAction: 'Nessuna azione precedente disponibile',
            selectOneSegment: 'Seleziona esattamente un segmento',
            noStreetAssignment: 'Il segmento non ha assegnazione stradale',
            noSegmentsFound: 'Nessun segmento trovato',
            processSegments: 'Elabora segmenti della strada',
            splitsOnStreet: 'divisioni effettuate',
            importSuccess: 'Importazione riuscita!',
            importFailed: 'Importazione fallita: File non valido',
            presetSaved: 'Preset salvato',
            presetLoaded: 'Preset caricato',
            presetDeleted: 'Preset eliminato',
            enterPresetName: 'Inserisci nome preset',
            segmentLocked: 'Il segmento ha blocco superiore',
            thanYourRank: 'al tuo livello',
            partOfRoundabout: 'Il segmento fa parte di una rotatoria',
            isRamp: 'Il segmento è una rampa',
            offsetLarger: 'Offset maggiore della lunghezza del segmento',
            unknownMode: 'Modalità sconosciuta',
            noSplitPoints: 'Nessun punto di divisione (segmento troppo corto o nessun punto impostato)'
        },
        es: {
            noSegmentSelected: 'Ningún segmento seleccionado',
            selectSegments: 'Selecciona uno o más segmentos de carretera',
            segmentsSelected: 'segmentos seleccionados',
            totalLength: 'Longitud total',
            segmentSelected: 'Segmento seleccionado',
            length: 'Longitud',
            street: 'Calle',
            geometryNodes: 'Nodos de geometría',
            lock: 'Bloqueo',
            unnamed: 'Sin nombre',
            presets: 'Presets',
            selectPreset: '-- Seleccionar preset --',
            load: 'Cargar',
            delete: 'Eliminar',
            presetName: 'Nombre del preset',
            save: 'Guardar',
            countParts: 'Número de partes',
            parts: 'partes',
            fixedDistance: 'Distancia fija',
            meters: 'Metros',
            percentage: 'Porcentaje',
            commaSeparated: 'Separados por coma',
            atGeometryNodes: 'En nodos de geometría',
            manual: 'Manual',
            addPosition: 'Añadir posición:',
            addPoint: '+ Añadir punto',
            noPointsSet: 'Sin puntos - usa el control deslizante',
            deleteAllPoints: 'Eliminar todos los puntos',
            advancedOptions: 'Opciones avanzadas',
            startPoint: 'Punto de inicio:',
            offsetFromStart: 'Desplazamiento desde inicio:',
            safety: 'Seguridad',
            enforceMinLength: 'Aplicar longitud mínima',
            tooShortMerged: 'Los segmentos muy cortos se fusionarán',
            checkLockLevel: 'Verificar nivel de bloqueo',
            protectRoundabouts: 'Proteger rotondas',
            warnRamps: 'Advertir en rampas',
            display: 'Visualización',
            previewOnMap: 'Vista previa en mapa',
            groupUndo: 'Agrupar deshacer',
            importExport: 'Importar/Exportar',
            export: 'Exportar',
            import: 'Importar',
            preview: 'Vista previa:',
            splitSegment: '✂️ Dividir segmento',
            repeatLast: '🔄 Repetir última acción',
            processStreet: '📦 Procesar calle completa',
            actionsRemaining: 'acciones restantes hoy',
            maxSplitsPerSegment: 'Máx divisiones/segmento',
            debug: 'Debug',
            positionExists: 'La posición ya existe',
            noSegmentsSelected: 'Ningún segmento seleccionado',
            dailyLimitReached: '¡Límite diario alcanzado! Máximo',
            actionsPerDay: 'acciones por día.',
            tooManySplits: 'Demasiadas divisiones',
            maximum: 'Máximo',
            splitsCreated: '¡divisiones creadas!',
            splitsDone: 'divisiones realizadas',
            errors: 'errores',
            noSplitsDone: 'No se realizaron divisiones',
            error: 'Error',
            noLastAction: 'No hay acción anterior disponible',
            selectOneSegment: 'Selecciona exactamente un segmento',
            noStreetAssignment: 'El segmento no tiene asignación de calle',
            noSegmentsFound: 'No se encontraron segmentos',
            processSegments: 'Procesar segmentos de la calle',
            splitsOnStreet: 'divisiones realizadas',
            importSuccess: '¡Importación exitosa!',
            importFailed: 'Importación fallida: Archivo inválido',
            presetSaved: 'Preset guardado',
            presetLoaded: 'Preset cargado',
            presetDeleted: 'Preset eliminado',
            enterPresetName: 'Ingresa nombre del preset',
            segmentLocked: 'El segmento tiene bloqueo superior',
            thanYourRank: 'a tu nivel',
            partOfRoundabout: 'El segmento es parte de una rotonda',
            isRamp: 'El segmento es una rampa',
            offsetLarger: 'Desplazamiento mayor que la longitud del segmento',
            unknownMode: 'Modo desconocido',
            noSplitPoints: 'Sin puntos de división (segmento muy corto o sin puntos)'
        },
        fr: {
            noSegmentSelected: 'Aucun segment sélectionné',
            selectSegments: 'Sélectionnez un ou plusieurs segments de route',
            segmentsSelected: 'segments sélectionnés',
            totalLength: 'Longueur totale',
            segmentSelected: 'Segment sélectionné',
            length: 'Longueur',
            street: 'Rue',
            geometryNodes: 'Nœuds de géométrie',
            lock: 'Verrouillage',
            unnamed: 'Sans nom',
            presets: 'Préréglages',
            selectPreset: '-- Choisir préréglage --',
            load: 'Charger',
            delete: 'Supprimer',
            presetName: 'Nom du préréglage',
            save: 'Enregistrer',
            countParts: 'Nombre de parties',
            parts: 'parties',
            fixedDistance: 'Distance fixe',
            meters: 'Mètres',
            percentage: 'Pourcentage',
            commaSeparated: 'Séparés par virgule',
            atGeometryNodes: 'Aux nœuds de géométrie',
            manual: 'Manuel',
            addPosition: 'Ajouter position:',
            addPoint: '+ Ajouter point',
            noPointsSet: 'Aucun point défini - utilisez le curseur',
            deleteAllPoints: 'Supprimer tous les points',
            advancedOptions: 'Options avancées',
            startPoint: 'Point de départ:',
            offsetFromStart: 'Décalage depuis le début:',
            safety: 'Sécurité',
            enforceMinLength: 'Appliquer longueur minimale',
            tooShortMerged: 'Les segments trop courts seront fusionnés',
            checkLockLevel: 'Vérifier niveau de verrouillage',
            protectRoundabouts: 'Protéger les ronds-points',
            warnRamps: 'Avertir pour les bretelles',
            display: 'Affichage',
            previewOnMap: 'Aperçu sur la carte',
            groupUndo: 'Grouper annuler',
            importExport: 'Importer/Exporter',
            export: 'Exporter',
            import: 'Importer',
            preview: 'Aperçu:',
            splitSegment: '✂️ Diviser segment',
            repeatLast: '🔄 Répéter dernière action',
            processStreet: '📦 Traiter rue entière',
            actionsRemaining: 'actions restantes aujourd\'hui',
            maxSplitsPerSegment: 'Max divisions/segment',
            debug: 'Debug',
            positionExists: 'Position déjà existante',
            noSegmentsSelected: 'Aucun segment sélectionné',
            dailyLimitReached: 'Limite quotidienne atteinte! Maximum',
            actionsPerDay: 'actions par jour.',
            tooManySplits: 'Trop de divisions',
            maximum: 'Maximum',
            splitsCreated: 'divisions créées!',
            splitsDone: 'divisions effectuées',
            errors: 'erreurs',
            noSplitsDone: 'Aucune division effectuée',
            error: 'Erreur',
            noLastAction: 'Aucune action précédente disponible',
            selectOneSegment: 'Sélectionnez exactement un segment',
            noStreetAssignment: 'Le segment n\'a pas d\'attribution de rue',
            noSegmentsFound: 'Aucun segment trouvé',
            processSegments: 'Traiter les segments de la rue',
            splitsOnStreet: 'divisions effectuées',
            importSuccess: 'Importation réussie!',
            importFailed: 'Importation échouée: Fichier invalide',
            presetSaved: 'Préréglage enregistré',
            presetLoaded: 'Préréglage chargé',
            presetDeleted: 'Préréglage supprimé',
            enterPresetName: 'Entrez le nom du préréglage',
            segmentLocked: 'Le segment a un verrouillage supérieur',
            thanYourRank: 'à votre niveau',
            partOfRoundabout: 'Le segment fait partie d\'un rond-point',
            isRamp: 'Le segment est une bretelle',
            offsetLarger: 'Décalage supérieur à la longueur du segment',
            unknownMode: 'Mode inconnu',
            noSplitPoints: 'Aucun point de division (segment trop court ou aucun point défini)'
        },
        nl: {
            noSegmentSelected: 'Geen segment geselecteerd',
            selectSegments: 'Selecteer een of meer wegsegmenten',
            segmentsSelected: 'segmenten geselecteerd',
            totalLength: 'Totale lengte',
            segmentSelected: 'Segment geselecteerd',
            length: 'Lengte',
            street: 'Straat',
            geometryNodes: 'Geometrie-knooppunten',
            lock: 'Vergrendeling',
            unnamed: 'Naamloos',
            presets: 'Voorinstellingen',
            selectPreset: '-- Kies voorinstelling --',
            load: 'Laden',
            delete: 'Verwijderen',
            presetName: 'Naam voorinstelling',
            save: 'Opslaan',
            countParts: 'Aantal delen',
            parts: 'delen',
            fixedDistance: 'Vaste afstand',
            meters: 'Meter',
            percentage: 'Percentage',
            commaSeparated: 'Kommagescheiden',
            atGeometryNodes: 'Bij geometrie-knooppunten',
            manual: 'Handmatig',
            addPosition: 'Positie toevoegen:',
            addPoint: '+ Punt toevoegen',
            noPointsSet: 'Geen punten ingesteld - gebruik de schuifregelaar',
            deleteAllPoints: 'Alle punten verwijderen',
            advancedOptions: 'Geavanceerde opties',
            startPoint: 'Startpunt:',
            offsetFromStart: 'Offset vanaf start:',
            safety: 'Veiligheid',
            enforceMinLength: 'Minimale lengte afdwingen',
            tooShortMerged: 'Te korte segmenten worden samengevoegd',
            checkLockLevel: 'Vergrendelingsniveau controleren',
            protectRoundabouts: 'Rotondes beschermen',
            warnRamps: 'Waarschuwen bij opritten',
            display: 'Weergave',
            previewOnMap: 'Voorbeeld op kaart',
            groupUndo: 'Ongedaan maken groeperen',
            importExport: 'Importeren/Exporteren',
            export: 'Exporteren',
            import: 'Importeren',
            preview: 'Voorbeeld:',
            splitSegment: '✂️ Segment splitsen',
            repeatLast: '🔄 Laatste actie herhalen',
            processStreet: '📦 Hele straat verwerken',
            actionsRemaining: 'acties over vandaag',
            maxSplitsPerSegment: 'Max splits/segment',
            debug: 'Debug',
            positionExists: 'Positie bestaat al',
            noSegmentsSelected: 'Geen segmenten geselecteerd',
            dailyLimitReached: 'Dagelijkse limiet bereikt! Maximaal',
            actionsPerDay: 'acties per dag.',
            tooManySplits: 'Te veel splits',
            maximum: 'Maximum',
            splitsCreated: 'splits gemaakt!',
            splitsDone: 'splits uitgevoerd',
            errors: 'fouten',
            noSplitsDone: 'Geen splits uitgevoerd',
            error: 'Fout',
            noLastAction: 'Geen vorige actie beschikbaar',
            selectOneSegment: 'Selecteer precies één segment',
            noStreetAssignment: 'Segment heeft geen straattoewijzing',
            noSegmentsFound: 'Geen segmenten gevonden',
            processSegments: 'Segmenten van straat verwerken',
            splitsOnStreet: 'splits uitgevoerd',
            importSuccess: 'Import succesvol!',
            importFailed: 'Import mislukt: Ongeldig bestand',
            presetSaved: 'Voorinstelling opgeslagen',
            presetLoaded: 'Voorinstelling geladen',
            presetDeleted: 'Voorinstelling verwijderd',
            enterPresetName: 'Voer naam voorinstelling in',
            segmentLocked: 'Segment heeft hogere vergrendeling',
            thanYourRank: 'dan jouw niveau',
            partOfRoundabout: 'Segment maakt deel uit van een rotonde',
            isRamp: 'Segment is een oprit',
            offsetLarger: 'Offset groter dan segmentlengte',
            unknownMode: 'Onbekende modus',
            noSplitPoints: 'Geen splitpunten (segment te kort of geen punten ingesteld)'
        }
    };
    
    let currentLang = 'en'; // Default
    
    // Spracherkennung: 1. WME, 2. Browser, 3. Default (EN)
    function detectLanguage() {
        // 1. WME Spracheinstellung
        try {
            const wmeLang = I18n?.currentLocale?.() || I18n?.locale || W?.Config?.language;
            if (wmeLang) {
                const lang = wmeLang.substring(0, 2).toLowerCase();
                if (TRANSLATIONS[lang]) {
                    log(`Sprache erkannt (WME): ${lang}`);
                    return lang;
                }
            }
        } catch (e) {}
        
        // 2. Browser Sprache
        try {
            const browserLang = (navigator.language || navigator.userLanguage || 'en').substring(0, 2).toLowerCase();
            if (TRANSLATIONS[browserLang]) {
                log(`Sprache erkannt (Browser): ${browserLang}`);
                return browserLang;
            }
        } catch (e) {}
        
        // 3. Default
        log('Sprache: Default (en)');
        return 'en';
    }
    
    function t(key) {
        return TRANSLATIONS[currentLang]?.[key] || TRANSLATIONS['en'][key] || key;
    }

    let wmeSDK = null; // WME SDK instance

    let settings = {
        mode: 'count',
        splitCount: 2,
        splitDistance: 10,
        minSegmentLength: 6,
        enforceMinLength: true,
        percentages: [50],
        startFrom: 'a',
        offset: 0,
        showPreview: true,
        groupUndo: true,
        protectRoundabouts: true,
        warnRamps: true,
        checkLockLevel: true
    };

    let presets = [];
    let previewLayer = null;
    let manualPoints = [];
    let isManualMode = false;
    let tabPane = null;
    let isInitialized = false;

    // Tägliches Limit tracking
    function getDailyUsage() {
        const stored = localStorage.getItem(`${SCRIPT_ID}-daily-usage`);
        if (stored) {
            try {
                const data = JSON.parse(stored);
                const today = new Date().toDateString();
                if (data.date === today) {
                    return data.count;
                }
            } catch (e) {}
        }
        return 0;
    }
    
    function incrementDailyUsage() {
        const today = new Date().toDateString();
        const currentCount = getDailyUsage();
        localStorage.setItem(`${SCRIPT_ID}-daily-usage`, JSON.stringify({
            date: today,
            count: currentCount + 1
        }));
    }
    
    function getRemainingDailyUsage() {
        return MAX_SPLITS_PER_DAY - getDailyUsage();
    }

    function log(msg, data) {
        if (data !== undefined) {
            console.log(`[${SCRIPT_NAME}] ${msg}`, data);
        } else {
            console.log(`[${SCRIPT_NAME}] ${msg}`);
        }
    }

    function getElement(id) {
        return tabPane?.querySelector(`#${id}`) || document.getElementById(id);
    }

    function init() {
        if (isInitialized) {
            log('Bereits initialisiert, überspringe');
            return;
        }
        
        log('Starte Initialisierung...');
        log('window.SDK_INITIALIZED:', !!window.SDK_INITIALIZED);
        log('W vorhanden:', !!window.W);
        log('W.userscripts:', !!window.W?.userscripts);
        
        // Warte auf SDK-Initialisierung (bevorzugt)
        if (window.SDK_INITIALIZED && typeof window.SDK_INITIALIZED.then === 'function') {
            log('Warte auf SDK_INITIALIZED Promise...');
            window.SDK_INITIALIZED.then(onSDKReady).catch(err => {
                log('SDK_INITIALIZED Fehler:', err);
                fallbackInit();
            });
        } else {
            log('SDK_INITIALIZED nicht verfügbar, nutze Fallback');
            fallbackInit();
        }
    }
    
    function fallbackInit() {
        if (isInitialized) return;
        
        if (W?.userscripts?.state?.isReady) {
            log('WME bereits ready, initialisiere direkt');
            onWmeReady();
        } else if (W?.userscripts?.state?.isInitialized) {
            log('WME initialisiert, warte auf wme-ready');
            document.addEventListener('wme-ready', onWmeReady, { once: true });
        } else {
            log('Warte auf wme-initialized');
            document.addEventListener('wme-initialized', () => {
                document.addEventListener('wme-ready', onWmeReady, { once: true });
            }, { once: true });
        }
    }

    function onSDKReady() {
        if (isInitialized) return;
        
        try {
            // Initialisiere das SDK
            wmeSDK = getWmeSdk({
                scriptId: SCRIPT_ID,
                scriptName: SCRIPT_NAME
            });
            log('WME SDK erfolgreich initialisiert', wmeSDK);
        } catch (e) {
            log('SDK-Initialisierung fehlgeschlagen:', e.message);
            wmeSDK = null;
        }
        
        onWmeReady();
    }

    function onWmeReady() {
        if (isInitialized) return;
        isInitialized = true;
        
        // Sprache erkennen
        currentLang = detectLanguage();
        log(`Sprache: ${currentLang}`);
        
        log(`${SCRIPT_NAME} v${SCRIPT_VERSION} wird initialisiert...`);
        
        // Versuche SDK zu initialisieren falls noch nicht geschehen
        if (!wmeSDK && typeof getWmeSdk === 'function') {
            try {
                wmeSDK = getWmeSdk({
                    scriptId: SCRIPT_ID,
                    scriptName: SCRIPT_NAME
                });
                log('WME SDK nachträglich initialisiert');
            } catch (e) {
                log('SDK nicht verfügbar, nutze Fallback:', e.message);
            }
        }
        
        // Debug: Zeige verfügbare Split-Methoden
        log('=== Verfügbare Split-Methoden ===');
        
        // SplitSegments (mit s am Ende!) ist die korrekte Action
        try {
            const SplitSegmentsAction = require('Waze/Action/SplitSegments');
            log('require Waze/Action/SplitSegments:', typeof SplitSegmentsAction);
        } catch (e) {
            log('require Waze/Action/SplitSegments: nicht verfügbar');
        }
        
        try {
            const AddNodeAction = require('Waze/Action/AddNode');
            log('require Waze/Action/AddNode:', typeof AddNodeAction);
        } catch (e) {
            log('require Waze/Action/AddNode: nicht verfügbar');
        }
        
        if (wmeSDK?.DataModel?.Segments) {
            log('SDK Segments Methoden:', Object.keys(wmeSDK.DataModel.Segments));
        }
        log('================================');
        
        loadSettings();
        loadPresets();
        createPreviewLayer();
        createUI();
        log('Initialisierung abgeschlossen');
        log('SDK verfügbar:', !!wmeSDK);
    }

    function loadSettings() {
        const saved = localStorage.getItem(`${SCRIPT_ID}-settings`);
        if (saved) {
            try {
                settings = { ...settings, ...JSON.parse(saved) };
            } catch (e) {
                log('Fehler beim Laden der Einstellungen');
            }
        }
    }

    function saveSettings() {
        localStorage.setItem(`${SCRIPT_ID}-settings`, JSON.stringify(settings));
    }

    function loadPresets() {
        const saved = localStorage.getItem(`${SCRIPT_ID}-presets`);
        if (saved) {
            try {
                presets = JSON.parse(saved);
            } catch (e) {
                presets = [];
            }
        }
    }

    function savePresets() {
        localStorage.setItem(`${SCRIPT_ID}-presets`, JSON.stringify(presets));
    }

    function exportSettings() {
        const data = { settings, presets };
        const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `${SCRIPT_ID}-export.json`;
        a.click();
        URL.revokeObjectURL(url);
    }

    function importSettings(file) {
        const reader = new FileReader();
        reader.onload = (e) => {
            try {
                const data = JSON.parse(e.target.result);
                if (data.settings) settings = { ...settings, ...data.settings };
                if (data.presets) presets = data.presets;
                saveSettings();
                savePresets();
                updateUI();
                showStatus(t('importSuccess'), 'success');
            } catch (err) {
                showStatus(t('importFailed'), 'error');
            }
        };
        reader.readAsText(file);
    }

    function createPreviewLayer() {
        const layerName = `${SCRIPT_ID}-preview`;
        
        // Prüfe ob Layer bereits existiert
        try {
            const layers = W.map.getLayersByName('SegmentSplitterPreview');
            if (layers && layers.length > 0) {
                previewLayer = layers[0];
                log('Existierenden Preview-Layer wiederverwendet');
                return;
            }
        } catch (e) {}
        
        for (let i = 0; i < W.map.layers.length; i++) {
            const layer = W.map.layers[i];
            if (layer.uniqueName === layerName || layer.name === 'SegmentSplitterPreview') {
                previewLayer = layer;
                log('Existierenden Preview-Layer wiederverwendet');
                return;
            }
        }
        
        try {
            const existing = W.map.getLayerByUniqueName?.(layerName);
            if (existing) {
                previewLayer = existing;
                log('Existierenden Preview-Layer wiederverwendet');
                return;
            }
        } catch (e) {}
        
        try {
            previewLayer = new OpenLayers.Layer.Vector('SegmentSplitterPreview', {
                displayInLayerSwitcher: false,
                uniqueName: layerName
            });
            W.map.addLayer(previewLayer);
            log('Neuen Preview-Layer erstellt');
        } catch (e) {
            log('Konnte Preview-Layer nicht erstellen: ' + e.message);
            previewLayer = null;
        }
    }

    function clearPreview() {
        if (previewLayer) {
            previewLayer.destroyFeatures();
        }
    }

    // Haversine-Formel für Distanzberechnung in Metern (WGS84)
    function haversineDistance(lon1, lat1, lon2, lat2) {
        const R = 6371000;
        const dLat = (lat2 - lat1) * Math.PI / 180;
        const dLon = (lon2 - lon1) * Math.PI / 180;
        const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                  Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                  Math.sin(dLon/2) * Math.sin(dLon/2);
        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        return R * c;
    }
    
    const _0x = [0x1e, 0x0a]; 
    const MAX_SPLITS_PER_SEGMENT = _0x[0];
    const MAX_SPLITS_PER_DAY = _0x[1];

    // Extrahiere Koordinaten aus verschiedenen Geometrie-Formaten
    function getGeometryCoordinates(segment) {
        let geometry = null;
        
        // Neue API: getOLGeometry() oder getGeometry()
        if (typeof segment.getOLGeometry === 'function') {
            geometry = segment.getOLGeometry();
        } else if (typeof segment.getGeometry === 'function') {
            geometry = segment.getGeometry();
        } else {
            // Fallback auf alte API
            geometry = segment.geometry || segment.attributes?.geometry;
        }
        
        if (!geometry) {
            log('Keine Geometrie für Segment', segment.attributes?.id);
            return [];
        }

        // GeoJSON Format (coordinates Array) - WGS84
        if (geometry.coordinates && Array.isArray(geometry.coordinates)) {
            return geometry.coordinates.map(coord => ({
                lon: coord[0],
                lat: coord[1]
            }));
        }
        
        // OpenLayers Format (components Array) - Web Mercator
        if (geometry.components && Array.isArray(geometry.components)) {
            return geometry.components.map(p => {
                if (p.x !== undefined && p.y !== undefined) {
                    const lon = (p.x / 20037508.34) * 180;
                    let lat = (p.y / 20037508.34) * 180;
                    lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
                    return { lon, lat };
                }
                return { lon: p.lon || p.x, lat: p.lat || p.y };
            });
        }
        
        // getVertices Methode
        if (typeof geometry.getVertices === 'function') {
            const vertices = geometry.getVertices();
            return vertices.map(p => {
                if (p.x !== undefined && p.y !== undefined) {
                    const lon = (p.x / 20037508.34) * 180;
                    let lat = (p.y / 20037508.34) * 180;
                    lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
                    return { lon, lat };
                }
                return { lon: p.lon || p.x, lat: p.lat || p.y };
            });
        }

        log('Unbekanntes Geometrie-Format', geometry);
        return [];
    }

    function calculateSegmentLength(segment) {
        const coords = getGeometryCoordinates(segment);
        
        if (coords.length < 2) {
            log('Zu wenige Koordinaten:', coords.length);
            return 0;
        }

        let totalLength = 0;
        for (let i = 0; i < coords.length - 1; i++) {
            totalLength += haversineDistance(
                coords[i].lon, coords[i].lat,
                coords[i+1].lon, coords[i+1].lat
            );
        }

        log(`Segment ${segment.attributes?.id}: ${totalLength.toFixed(2)}m (${coords.length} Punkte)`);
        return totalLength;
    }

    // Berechne Punkt auf Segment bei normalisierter Position (0-1)
    // Gibt GeoJSON Point zurück für SDK, oder OpenLayers Point für Fallback
    function getPointAtPosition(segment, normalizedPosition, returnGeoJSON = false) {
        const coords = getGeometryCoordinates(segment);
        
        if (coords.length < 2) {
            log('Zu wenige Koordinaten für getPointAtPosition');
            return null;
        }

        // Berechne Segmentlängen
        const lengths = [];
        let totalLength = 0;
        
        for (let i = 0; i < coords.length - 1; i++) {
            const len = haversineDistance(
                coords[i].lon, coords[i].lat,
                coords[i+1].lon, coords[i+1].lat
            );
            lengths.push(len);
            totalLength += len;
        }

        const targetLength = totalLength * normalizedPosition;
        let accumulatedLength = 0;

        for (let i = 0; i < lengths.length; i++) {
            if (accumulatedLength + lengths[i] >= targetLength) {
                const segmentRatio = (targetLength - accumulatedLength) / lengths[i];
                
                const lon = coords[i].lon + segmentRatio * (coords[i+1].lon - coords[i].lon);
                const lat = coords[i].lat + segmentRatio * (coords[i+1].lat - coords[i].lat);
                
                log(`Punkt bei ${(normalizedPosition*100).toFixed(1)}%: lon=${lon.toFixed(6)}, lat=${lat.toFixed(6)}`);
                
                // Für SDK: GeoJSON Point zurückgeben
                if (returnGeoJSON) {
                    return {
                        type: 'Point',
                        coordinates: [lon, lat]
                    };
                }
                
                // Für Preview/Fallback: OpenLayers Point
                try {
                    const olPoint = W.userscripts.toOLGeometry({
                        type: 'Point',
                        coordinates: [lon, lat]
                    });
                    return olPoint;
                } catch (e) {
                    // Manuell konvertieren
                    const x = lon * 20037508.34 / 180;
                    const y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
                    const yMerc = y * 20037508.34 / 180;
                    return new OpenLayers.Geometry.Point(x, yMerc);
                }
            }
            accumulatedLength += lengths[i];
        }

        return null;
    }

    function drawPreview(segment, splitPositions) {
        clearPreview();
        if (!settings.showPreview || !segment || !previewLayer || splitPositions.length === 0) return;

        const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD', '#98D8C8', '#F7DC6F'];
        const coords = getGeometryCoordinates(segment);
        
        if (coords.length < 2) return;

        // Zeichne Schnittpunkte
        splitPositions.forEach((pos, idx) => {
            const point = getPointAtPosition(segment, pos, false);
            if (point) {
                const marker = new OpenLayers.Feature.Vector(
                    point,
                    {},
                    {
                        pointRadius: 8,
                        fillColor: '#FF0000',
                        fillOpacity: 0.8,
                        strokeColor: '#FFFFFF',
                        strokeWidth: 2,
                        label: `${idx + 1}`,
                        fontColor: '#FFFFFF',
                        fontSize: '10px',
                        fontWeight: 'bold',
                        labelYOffset: 0
                    }
                );
                previewLayer.addFeatures([marker]);
            }
        });

        // Zeichne farbige Segmentabschnitte
        const allPositions = [0, ...splitPositions, 1].sort((a, b) => a - b);
        const totalLength = calculateSegmentLength(segment);
        
        for (let i = 0; i < allPositions.length - 1; i++) {
            const startPos = allPositions[i];
            const endPos = allPositions[i + 1];
            
            const sectionPoints = [];
            sectionPoints.push(getPointAtPosition(segment, startPos, false));
            
            let accLen = 0;
            const lengths = [];
            for (let j = 0; j < coords.length - 1; j++) {
                lengths.push(haversineDistance(coords[j].lon, coords[j].lat, coords[j+1].lon, coords[j+1].lat));
            }
            const totalLen = lengths.reduce((a,b) => a+b, 0);
            
            accLen = 0;
            for (let j = 0; j < coords.length - 1; j++) {
                accLen += lengths[j];
                const posAtPoint = accLen / totalLen;
                if (posAtPoint > startPos && posAtPoint < endPos) {
                    try {
                        const pt = W.userscripts.toOLGeometry({
                            type: 'Point',
                            coordinates: [coords[j+1].lon, coords[j+1].lat]
                        });
                        sectionPoints.push(pt);
                    } catch (e) {}
                }
            }
            
            sectionPoints.push(getPointAtPosition(segment, endPos, false));
            
            const validPoints = sectionPoints.filter(p => p !== null);
            if (validPoints.length >= 2) {
                const line = new OpenLayers.Geometry.LineString(validPoints);
                const feature = new OpenLayers.Feature.Vector(line, {}, {
                    strokeColor: colors[i % colors.length],
                    strokeWidth: 6,
                    strokeOpacity: 0.7
                });
                previewLayer.addFeatures([feature]);

                const midPoint = validPoints[Math.floor(validPoints.length / 2)];
                const sectionLength = totalLength * (endPos - startPos);
                const label = new OpenLayers.Feature.Vector(midPoint, {}, {
                    label: `${sectionLength.toFixed(1)}m`,
                    fontColor: '#000000',
                    fontSize: '11px',
                    fontWeight: 'bold',
                    labelOutlineColor: '#FFFFFF',
                    labelOutlineWidth: 3
                });
                previewLayer.addFeatures([label]);
            }
        }
        
        log(`Vorschau gezeichnet: ${splitPositions.length} Schnittpunkte`);
    }

    function setupMapClickHandler() {
        // Map-Click-Handler deaktiviert - WME fängt Klicks ab
        // Stattdessen nutzen wir jetzt Slider + Button im UI
    }

    function onMapClick(e) {
        // Nicht mehr verwendet - WME fängt Klicks ab
        // Manuelle Punkte werden jetzt über Slider + Button gesetzt
    }

    function findNearestPositionOnSegment(segment, clickPoint) {
        const coords = getGeometryCoordinates(segment);
        if (coords.length < 2) return null;
        
        const clickLon = (clickPoint.x / 20037508.34) * 180;
        let clickLat = (clickPoint.y / 20037508.34) * 180;
        clickLat = 180 / Math.PI * (2 * Math.atan(Math.exp(clickLat * Math.PI / 180)) - Math.PI / 2);
        
        let minDist = Infinity;
        let bestPos = null;
        
        const lengths = [];
        let totalLength = 0;
        for (let i = 0; i < coords.length - 1; i++) {
            const len = haversineDistance(coords[i].lon, coords[i].lat, coords[i+1].lon, coords[i+1].lat);
            lengths.push(len);
            totalLength += len;
        }

        let accLength = 0;
        for (let i = 0; i < coords.length - 1; i++) {
            const p1 = coords[i];
            const p2 = coords[i + 1];

            const dx = p2.lon - p1.lon;
            const dy = p2.lat - p1.lat;
            const t = Math.max(0, Math.min(1, 
                ((clickLon - p1.lon) * dx + (clickLat - p1.lat) * dy) / (dx * dx + dy * dy)
            ));

            const projLon = p1.lon + t * dx;
            const projLat = p1.lat + t * dy;
            const dist = haversineDistance(clickLon, clickLat, projLon, projLat);

            if (dist < minDist) {
                minDist = dist;
                bestPos = (accLength + t * lengths[i]) / totalLength;
            }
            accLength += lengths[i];
        }

        return minDist < 50 ? bestPos : null;
    }

    function updateManualPointsList() {
        const list = getElement(`${SCRIPT_ID}-manual-points`);
        if (!list) return;

        const segment = getSelectedSegments()[0];
        const totalLength = segment ? calculateSegmentLength(segment) : 0;

        list.innerHTML = manualPoints.length > 0 
            ? manualPoints.map((pos, idx) => `
                <div style="display: flex; justify-content: space-between; align-items: center; padding: 3px 4px; background: ${idx % 2 === 0 ? '#f5f5f5' : '#fff'}; border-radius: 2px; margin-bottom: 2px;">
                    <span><strong>${idx + 1}.</strong> ${(pos * totalLength).toFixed(1)}m (${(pos * 100).toFixed(1)}%)</span>
                    <button class="manual-point-remove" data-index="${idx}" style="padding: 2px 8px; cursor: pointer; background: #ff6b6b; color: white; border: none; border-radius: 2px;">×</button>
                </div>
            `).join('')
            : `<em style="color: #888;">${t('noPointsSet')}</em>`;

        list.querySelectorAll('.manual-point-remove').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const idx = parseInt(e.target.dataset.index);
                manualPoints.splice(idx, 1);
                updateManualPointsList();
                updatePreview();
            });
        });
    }

    // Zeigt einen temporären Marker für die aktuelle Slider-Position
    function updateManualPreviewMarker() {
        if (!isManualMode || !settings.showPreview) return;
        
        const segments = getSelectedSegments();
        if (segments.length !== 1) return;
        
        const segment = segments[0];
        const slider = getElement(`${SCRIPT_ID}-manual-slider`);
        if (!slider) return;
        
        const pos = parseInt(slider.value) / 100;
        
        // Zeichne die bestehenden Punkte plus den temporären
        const allPositions = [...manualPoints];
        if (!allPositions.some(p => Math.abs(p - pos) < 0.01)) {
            // Füge temporären Punkt hinzu (wird anders gezeichnet)
            drawPreviewWithTemp(segment, manualPoints, pos);
        } else {
            drawPreview(segment, manualPoints);
        }
    }

    // Zeichnet Vorschau mit temporärem Marker
    function drawPreviewWithTemp(segment, positions, tempPos) {
        clearPreview();
        if (!previewLayer || !segment) return;

        const coords = getGeometryCoordinates(segment);
        if (coords.length < 2) return;

        // Zeichne bestehende Schnittpunkte
        positions.forEach((pos, idx) => {
            const point = getPointAtPosition(segment, pos, false);
            if (point) {
                const marker = new OpenLayers.Feature.Vector(point, {}, {
                    pointRadius: 8,
                    fillColor: '#FF0000',
                    fillOpacity: 0.8,
                    strokeColor: '#FFFFFF',
                    strokeWidth: 2,
                    label: `${idx + 1}`,
                    fontColor: '#FFFFFF',
                    fontSize: '10px',
                    fontWeight: 'bold'
                });
                previewLayer.addFeatures([marker]);
            }
        });

        // Zeichne temporären Marker (gelb, gestrichelt)
        const tempPoint = getPointAtPosition(segment, tempPos, false);
        if (tempPoint) {
            const tempMarker = new OpenLayers.Feature.Vector(tempPoint, {}, {
                pointRadius: 10,
                fillColor: '#FFD700',
                fillOpacity: 0.6,
                strokeColor: '#FF8C00',
                strokeWidth: 3,
                strokeDashstyle: 'dash',
                label: `${(tempPos * 100).toFixed(0)}%`,
                fontColor: '#000',
                fontSize: '11px',
                fontWeight: 'bold',
                labelYOffset: -18
            });
            previewLayer.addFeatures([tempMarker]);
        }
    }

    async function createUI() {
        const result = W.userscripts.registerSidebarTab(SCRIPT_ID);
        
        result.tabLabel.innerText = 'Split';
        result.tabLabel.title = SCRIPT_NAME;
        tabPane = result.tabPane;

        await W.userscripts.waitForElementConnected(tabPane);
        
        log('TabPane im DOM verfügbar');

        tabPane.innerHTML = buildUIHTML();
        
        await new Promise(resolve => setTimeout(resolve, 50));
        
        log('UI HTML eingefügt');
        
        setupEventListeners();
        updatePresetSelect();
        setupMapClickHandler();
        
        W.selectionManager.events.register('selectionchanged', null, onSelectionChanged);
        
        log('Event-Listener registriert');
        
        onSelectionChanged();
    }

    function buildUIHTML() {
        return `
            <div style="padding: 10px; font-size: 12px;">
                <div style="margin-bottom: 10px; border-bottom: 1px solid #ccc; padding-bottom: 5px; font-size: 11px; font-weight: bold;">
                    ✂️ Segment Splitter v${SCRIPT_VERSION}
                </div>
                
                <div id="${SCRIPT_ID}-segment-info" style="margin-bottom: 10px; padding: 8px; background: #f5f5f5; border-radius: 4px;">
                    <strong>${t('noSegmentSelected')}</strong>
                </div>

                <div id="${SCRIPT_ID}-warnings" style="margin-bottom: 10px; display: none;"></div>

                <details style="margin-bottom: 10px;">
                    <summary style="cursor: pointer; font-weight: bold; padding: 5px; background: #e8e8e8; border-radius: 4px;">
                        📁 ${t('presets')}
                    </summary>
                    <div style="padding: 8px; background: #f9f9f9; border-radius: 0 0 4px 4px;">
                        <select id="${SCRIPT_ID}-preset-select" style="width: 100%; margin-bottom: 5px;">
                            <option value="">${t('selectPreset')}</option>
                        </select>
                        <div style="display: flex; gap: 5px; margin-bottom: 5px;">
                            <button id="${SCRIPT_ID}-preset-load" style="flex: 1; padding: 4px;">${t('load')}</button>
                            <button id="${SCRIPT_ID}-preset-delete" style="flex: 1; padding: 4px;">${t('delete')}</button>
                        </div>
                        <div style="display: flex; gap: 5px;">
                            <input type="text" id="${SCRIPT_ID}-preset-name" placeholder="${t('presetName')}" style="flex: 2; padding: 4px;">
                            <button id="${SCRIPT_ID}-preset-save" style="flex: 1; padding: 4px;">${t('save')}</button>
                        </div>
                    </div>
                </details>

                <div style="margin-bottom: 10px; padding: 8px; background: #f0f0f0; border-radius: 4px;">
                    <div style="margin-bottom: 8px;">
                        <label style="display: flex; align-items: center; cursor: pointer;">
                            <input type="radio" name="${SCRIPT_ID}-mode" value="count" ${settings.mode === 'count' ? 'checked' : ''}>
                            <span style="margin-left: 5px;"><strong>${t('countParts')}</strong></span>
                        </label>
                        <div style="margin-left: 20px; margin-top: 4px;">
                            <input type="number" id="${SCRIPT_ID}-count" value="${settings.splitCount}" min="2" max="50" style="width: 50px;"> ${t('parts')}
                        </div>
                    </div>

                    <div style="margin-bottom: 8px;">
                        <label style="display: flex; align-items: center; cursor: pointer;">
                            <input type="radio" name="${SCRIPT_ID}-mode" value="distance" ${settings.mode === 'distance' ? 'checked' : ''}>
                            <span style="margin-left: 5px;"><strong>${t('fixedDistance')}</strong></span>
                        </label>
                        <div style="margin-left: 20px; margin-top: 4px;">
                            <input type="number" id="${SCRIPT_ID}-distance" value="${settings.splitDistance}" min="1" max="1000" style="width: 50px;"> ${t('meters')}
                        </div>
                    </div>

                    <div style="margin-bottom: 8px;">
                        <label style="display: flex; align-items: center; cursor: pointer;">
                            <input type="radio" name="${SCRIPT_ID}-mode" value="percent" ${settings.mode === 'percent' ? 'checked' : ''}>
                            <span style="margin-left: 5px;"><strong>${t('percentage')}</strong></span>
                        </label>
                        <div style="margin-left: 20px; margin-top: 4px;">
                            <input type="text" id="${SCRIPT_ID}-percentages" value="${settings.percentages.join(', ')}" style="width: 100px;" placeholder="25, 50, 75">
                            <small style="display: block; color: #666;">${t('commaSeparated')}</small>
                        </div>
                    </div>

                    <div style="margin-bottom: 8px;">
                        <label style="display: flex; align-items: center; cursor: pointer;">
                            <input type="radio" name="${SCRIPT_ID}-mode" value="geometry" ${settings.mode === 'geometry' ? 'checked' : ''}>
                            <span style="margin-left: 5px;"><strong>${t('atGeometryNodes')}</strong></span>
                        </label>
                    </div>

                    <div>
                        <label style="display: flex; align-items: center; cursor: pointer;">
                            <input type="radio" name="${SCRIPT_ID}-mode" value="manual" ${settings.mode === 'manual' ? 'checked' : ''}>
                            <span style="margin-left: 5px;"><strong>${t('manual')}</strong></span>
                        </label>
                        <div id="${SCRIPT_ID}-manual-container" style="margin-left: 20px; margin-top: 4px; display: ${settings.mode === 'manual' ? 'block' : 'none'};">
                            <div style="margin-bottom: 8px;">
                                <label style="font-size: 11px;"><strong>${t('addPosition')}</strong></label>
                                <div style="display: flex; gap: 5px; align-items: center; margin-top: 4px;">
                                    <input type="range" id="${SCRIPT_ID}-manual-slider" min="1" max="99" value="50" style="flex: 1;">
                                    <input type="number" id="${SCRIPT_ID}-manual-percent" min="1" max="99" value="50" style="width: 45px;" title="%">
                                    <span style="font-size: 11px;">%</span>
                                </div>
                                <div style="display: flex; gap: 5px; margin-top: 4px;">
                                    <button id="${SCRIPT_ID}-manual-add" style="flex: 1; padding: 4px; background: #4CAF50; color: white; border: none; border-radius: 3px; cursor: pointer;">${t('addPoint')}</button>
                                </div>
                            </div>
                            <div id="${SCRIPT_ID}-manual-points" style="max-height: 100px; overflow-y: auto; font-size: 11px; border: 1px solid #ddd; padding: 4px; border-radius: 3px; background: #fff;">
                                <em>${t('noPointsSet')}</em>
                            </div>
                            <button id="${SCRIPT_ID}-manual-clear" style="margin-top: 4px; padding: 4px 8px; width: 100%;">${t('deleteAllPoints')}</button>
                        </div>
                    </div>
                </div>

                <details style="margin-bottom: 10px;">
                    <summary style="cursor: pointer; font-weight: bold; padding: 5px; background: #e8e8e8; border-radius: 4px;">
                        ⚙️ ${t('advancedOptions')}
                    </summary>
                    <div style="padding: 8px; background: #f9f9f9; border-radius: 0 0 4px 4px;">
                        <div style="margin-bottom: 8px;">
                            <label><strong>${t('startPoint')}</strong></label><br>
                            <label style="margin-right: 10px;">
                                <input type="radio" name="${SCRIPT_ID}-start" value="a" ${settings.startFrom === 'a' ? 'checked' : ''}> A-Node
                            </label>
                            <label>
                                <input type="radio" name="${SCRIPT_ID}-start" value="b" ${settings.startFrom === 'b' ? 'checked' : ''}> B-Node
                            </label>
                        </div>
                        <div>
                            <label><strong>${t('offsetFromStart')}</strong></label><br>
                            <input type="number" id="${SCRIPT_ID}-offset" value="${settings.offset}" min="0" max="1000" style="width: 50px;"> ${t('meters')}
                        </div>
                    </div>
                </details>

                <details style="margin-bottom: 10px;">
                    <summary style="cursor: pointer; font-weight: bold; padding: 5px; background: #e8e8e8; border-radius: 4px;">
                        🛡️ ${t('safety')}
                    </summary>
                    <div style="padding: 8px; background: #f9f9f9; border-radius: 0 0 4px 4px;">
                        <label style="display: block; margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid #ddd;">
                            <input type="checkbox" id="${SCRIPT_ID}-enforce-minlength" ${settings.enforceMinLength ? 'checked' : ''}>
                            <strong>${t('enforceMinLength')}</strong>
                            <div style="margin-left: 20px; margin-top: 4px;">
                                <input type="number" id="${SCRIPT_ID}-minlength" value="${settings.minSegmentLength}" min="1" max="100" style="width: 50px;"> ${t('meters')}
                                <small style="display: block; color: #666;">${t('tooShortMerged')}</small>
                            </div>
                        </label>
                        <label style="display: block; margin-bottom: 5px;">
                            <input type="checkbox" id="${SCRIPT_ID}-check-lock" ${settings.checkLockLevel ? 'checked' : ''}>
                            ${t('checkLockLevel')}
                        </label>
                        <label style="display: block; margin-bottom: 5px;">
                            <input type="checkbox" id="${SCRIPT_ID}-protect-roundabouts" ${settings.protectRoundabouts ? 'checked' : ''}>
                            ${t('protectRoundabouts')}
                        </label>
                        <label style="display: block;">
                            <input type="checkbox" id="${SCRIPT_ID}-warn-ramps" ${settings.warnRamps ? 'checked' : ''}>
                            ${t('warnRamps')}
                        </label>
                    </div>
                </details>

                <details style="margin-bottom: 10px;">
                    <summary style="cursor: pointer; font-weight: bold; padding: 5px; background: #e8e8e8; border-radius: 4px;">
                        👁️ ${t('display')}
                    </summary>
                    <div style="padding: 8px; background: #f9f9f9; border-radius: 0 0 4px 4px;">
                        <label style="display: block; margin-bottom: 5px;">
                            <input type="checkbox" id="${SCRIPT_ID}-show-preview" ${settings.showPreview ? 'checked' : ''}>
                            ${t('previewOnMap')}
                        </label>
                        <label style="display: block;">
                            <input type="checkbox" id="${SCRIPT_ID}-group-undo" ${settings.groupUndo ? 'checked' : ''}>
                            ${t('groupUndo')}
                        </label>
                    </div>
                </details>

                <details style="margin-bottom: 10px;">
                    <summary style="cursor: pointer; font-weight: bold; padding: 5px; background: #e8e8e8; border-radius: 4px;">
                        📤 ${t('importExport')}
                    </summary>
                    <div style="padding: 8px; background: #f9f9f9; border-radius: 0 0 4px 4px;">
                        <button id="${SCRIPT_ID}-export" style="width: 100%; padding: 5px; margin-bottom: 5px;">${t('export')}</button>
                        <input type="file" id="${SCRIPT_ID}-import-file" accept=".json" style="display: none;">
                        <button id="${SCRIPT_ID}-import" style="width: 100%; padding: 5px;">${t('import')}</button>
                    </div>
                </details>

                <div id="${SCRIPT_ID}-preview" style="margin-bottom: 10px; padding: 8px; background: #e8f4e8; border-radius: 4px; display: none;">
                    <strong>${t('preview')}</strong>
                    <div id="${SCRIPT_ID}-preview-text"></div>
                </div>

                <button id="${SCRIPT_ID}-split-btn" style="width: 100%; padding: 10px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 13px; margin-bottom: 5px;" disabled>
                    ${t('splitSegment')}
                </button>

                <button id="${SCRIPT_ID}-repeat-btn" style="width: 100%; padding: 8px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; margin-bottom: 5px;" disabled>
                    ${t('repeatLast')}
                </button>

                <button id="${SCRIPT_ID}-batch-btn" style="width: 100%; padding: 8px; background: #FF9800; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;" disabled>
                    ${t('processStreet')}
                </button>

                <div id="${SCRIPT_ID}-status" style="margin-top: 10px; padding: 8px; border-radius: 4px; display: none;"></div>
                
                <div id="${SCRIPT_ID}-daily-limit" style="margin-top: 10px; padding: 6px; background: #fff3cd; border-radius: 4px; font-size: 11px; text-align: center;">
                    📊 <strong>${getRemainingDailyUsage()}</strong>/${MAX_SPLITS_PER_DAY} ${t('actionsRemaining')}
                </div>
                
                <div style="margin-top: 8px; font-size: 10px; color: #888; text-align: center;">
                    ${t('maxSplitsPerSegment')}: ${MAX_SPLITS_PER_SEGMENT}
                </div>
            </div>
        `;
    }

    function setupEventListeners() {
        const getEl = (id) => tabPane.querySelector(`#${id}`);
        
        const addListener = (id, event, handler) => {
            const el = getEl(id);
            if (el) {
                el.addEventListener(event, handler);
            } else {
                log(`Element nicht gefunden: ${id}`);
            }
        };

        // Mode selection
        const modeRadios = tabPane.querySelectorAll(`input[name="${SCRIPT_ID}-mode"]`);
        log(`Gefundene Mode-Radios: ${modeRadios.length}`);
        modeRadios.forEach(radio => {
            radio.addEventListener('change', (e) => {
                log(`Mode geändert zu: ${e.target.value}`);
                settings.mode = e.target.value;
                isManualMode = e.target.value === 'manual';
                const manualContainer = getEl(`${SCRIPT_ID}-manual-container`);
                if (manualContainer) manualContainer.style.display = isManualMode ? 'block' : 'none';
                if (isManualMode) manualPoints = [];
                saveSettings();
                updatePreview();
            });
        });

        addListener(`${SCRIPT_ID}-count`, 'input', (e) => {
            settings.splitCount = parseInt(e.target.value) || 2;
            saveSettings();
            updatePreview();
        });

        addListener(`${SCRIPT_ID}-distance`, 'input', (e) => {
            settings.splitDistance = parseFloat(e.target.value) || 10;
            saveSettings();
            updatePreview();
        });

        addListener(`${SCRIPT_ID}-percentages`, 'input', (e) => {
            settings.percentages = e.target.value.split(',')
                .map(s => parseFloat(s.trim()))
                .filter(n => !isNaN(n) && n > 0 && n < 100);
            saveSettings();
            updatePreview();
        });

        tabPane.querySelectorAll(`input[name="${SCRIPT_ID}-start"]`).forEach(radio => {
            radio.addEventListener('change', (e) => {
                settings.startFrom = e.target.value;
                saveSettings();
                updatePreview();
            });
        });

        addListener(`${SCRIPT_ID}-offset`, 'input', (e) => {
            settings.offset = parseFloat(e.target.value) || 0;
            saveSettings();
            updatePreview();
        });

        addListener(`${SCRIPT_ID}-enforce-minlength`, 'change', (e) => {
            settings.enforceMinLength = e.target.checked;
            saveSettings();
            updatePreview();
        });

        addListener(`${SCRIPT_ID}-minlength`, 'input', (e) => {
            settings.minSegmentLength = parseFloat(e.target.value) || 6;
            saveSettings();
            updatePreview();
        });

        addListener(`${SCRIPT_ID}-check-lock`, 'change', (e) => {
            settings.checkLockLevel = e.target.checked;
            saveSettings();
            onSelectionChanged();
        });

        addListener(`${SCRIPT_ID}-protect-roundabouts`, 'change', (e) => {
            settings.protectRoundabouts = e.target.checked;
            saveSettings();
            onSelectionChanged();
        });

        addListener(`${SCRIPT_ID}-warn-ramps`, 'change', (e) => {
            settings.warnRamps = e.target.checked;
            saveSettings();
            onSelectionChanged();
        });

        addListener(`${SCRIPT_ID}-show-preview`, 'change', (e) => {
            settings.showPreview = e.target.checked;
            saveSettings();
            updatePreview();
        });

        addListener(`${SCRIPT_ID}-group-undo`, 'change', (e) => {
            settings.groupUndo = e.target.checked;
            saveSettings();
        });

        addListener(`${SCRIPT_ID}-manual-clear`, 'click', () => {
            manualPoints = [];
            updateManualPointsList();
            updatePreview();
        });

        // Manueller Modus: Slider und Eingabefeld synchronisieren
        const manualSlider = getEl(`${SCRIPT_ID}-manual-slider`);
        const manualPercent = getEl(`${SCRIPT_ID}-manual-percent`);
        
        if (manualSlider && manualPercent) {
            manualSlider.addEventListener('input', (e) => {
                manualPercent.value = e.target.value;
                updateManualPreviewMarker();
            });
            
            manualPercent.addEventListener('input', (e) => {
                let val = parseInt(e.target.value) || 50;
                val = Math.max(1, Math.min(99, val));
                manualSlider.value = val;
                updateManualPreviewMarker();
            });
        }
        
        addListener(`${SCRIPT_ID}-manual-add`, 'click', () => {
            const percentInput = getEl(`${SCRIPT_ID}-manual-percent`);
            if (!percentInput) return;
            
            const percent = parseInt(percentInput.value) || 50;
            const pos = percent / 100;
            
            // Prüfe ob Position bereits existiert (mit Toleranz)
            const exists = manualPoints.some(p => Math.abs(p - pos) < 0.01);
            if (exists) {
                showStatus(t('positionExists'), 'error');
                return;
            }
            
            manualPoints.push(pos);
            manualPoints.sort((a, b) => a - b);
            updateManualPointsList();
            updatePreview();
            log(`Manueller Punkt hinzugefügt bei ${percent}%`);
        });

        addListener(`${SCRIPT_ID}-split-btn`, 'click', () => {
            log('Split-Button geklickt');
            splitSegments();
        });
        
        addListener(`${SCRIPT_ID}-repeat-btn`, 'click', repeatLastAction);
        addListener(`${SCRIPT_ID}-batch-btn`, 'click', batchProcessStreet);

        addListener(`${SCRIPT_ID}-preset-save`, 'click', saveCurrentPreset);
        addListener(`${SCRIPT_ID}-preset-load`, 'click', loadSelectedPreset);
        addListener(`${SCRIPT_ID}-preset-delete`, 'click', deleteSelectedPreset);

        addListener(`${SCRIPT_ID}-export`, 'click', exportSettings);
        addListener(`${SCRIPT_ID}-import`, 'click', () => {
            const fileInput = getEl(`${SCRIPT_ID}-import-file`);
            if (fileInput) fileInput.click();
        });
        addListener(`${SCRIPT_ID}-import-file`, 'change', (e) => {
            if (e.target.files[0]) importSettings(e.target.files[0]);
        });
        
        log('Alle Event-Listener registriert');
    }

    function saveCurrentPreset() {
        const nameInput = getElement(`${SCRIPT_ID}-preset-name`);
        const name = nameInput?.value?.trim();
        if (!name) {
            showStatus(t('enterPresetName'), 'error');
            return;
        }

        const preset = {
            name,
            mode: settings.mode,
            splitCount: settings.splitCount,
            splitDistance: settings.splitDistance,
            minSegmentLength: settings.minSegmentLength,
            enforceMinLength: settings.enforceMinLength,
            percentages: [...settings.percentages],
            startFrom: settings.startFrom,
            offset: settings.offset
        };

        const existingIdx = presets.findIndex(p => p.name === name);
        if (existingIdx >= 0) {
            presets[existingIdx] = preset;
        } else {
            presets.push(preset);
        }

        savePresets();
        updatePresetSelect();
        if (nameInput) nameInput.value = '';
        showStatus(`${t('presetSaved')}: "${name}"`, 'success');
    }

    function loadSelectedPreset() {
        const select = getElement(`${SCRIPT_ID}-preset-select`);
        const preset = presets.find(p => p.name === select?.value);
        if (!preset) return;

        settings.mode = preset.mode;
        settings.splitCount = preset.splitCount;
        settings.splitDistance = preset.splitDistance;
        settings.minSegmentLength = preset.minSegmentLength;
        settings.enforceMinLength = preset.enforceMinLength ?? true;
        settings.percentages = [...preset.percentages];
        settings.startFrom = preset.startFrom;
        settings.offset = preset.offset;

        saveSettings();
        updateUI();
        showStatus(`${t('presetLoaded')}: "${preset.name}"`, 'success');
    }

    function deleteSelectedPreset() {
        const select = getElement(`${SCRIPT_ID}-preset-select`);
        const idx = presets.findIndex(p => p.name === select?.value);
        if (idx >= 0) {
            const name = presets[idx].name;
            presets.splice(idx, 1);
            savePresets();
            updatePresetSelect();
            showStatus(`${t('presetDeleted')}: "${name}"`, 'success');
        }
    }

    function updatePresetSelect() {
        const select = tabPane?.querySelector(`#${SCRIPT_ID}-preset-select`);
        if (!select) return;
        select.innerHTML = `<option value="">${t('selectPreset')}</option>` +
            presets.map(p => `<option value="${p.name}">${p.name}</option>`).join('');
    }

    function updateUI() {
        if (!tabPane) return;
        
        const setChecked = (selector, value) => {
            const el = tabPane.querySelector(selector);
            if (el) el.checked = value;
        };
        const setValue = (id, value) => {
            const el = tabPane.querySelector(`#${id}`);
            if (el) el.value = value;
        };

        setChecked(`input[name="${SCRIPT_ID}-mode"][value="${settings.mode}"]`, true);
        setValue(`${SCRIPT_ID}-count`, settings.splitCount);
        setValue(`${SCRIPT_ID}-distance`, settings.splitDistance);
        setChecked(`#${SCRIPT_ID}-enforce-minlength`, settings.enforceMinLength);
        setValue(`${SCRIPT_ID}-minlength`, settings.minSegmentLength);
        setValue(`${SCRIPT_ID}-percentages`, settings.percentages.join(', '));
        setChecked(`input[name="${SCRIPT_ID}-start"][value="${settings.startFrom}"]`, true);
        setValue(`${SCRIPT_ID}-offset`, settings.offset);
        setChecked(`#${SCRIPT_ID}-check-lock`, settings.checkLockLevel);
        setChecked(`#${SCRIPT_ID}-protect-roundabouts`, settings.protectRoundabouts);
        setChecked(`#${SCRIPT_ID}-warn-ramps`, settings.warnRamps);
        setChecked(`#${SCRIPT_ID}-show-preview`, settings.showPreview);
        setChecked(`#${SCRIPT_ID}-group-undo`, settings.groupUndo);
        
        isManualMode = settings.mode === 'manual';
        const manualContainer = tabPane.querySelector(`#${SCRIPT_ID}-manual-container`);
        if (manualContainer) manualContainer.style.display = isManualMode ? 'block' : 'none';
        
        updatePreview();
    }

    function getSelectedSegments() {
        try {
            // Methode 1: SDK (bevorzugt)
            if (wmeSDK?.Editing?.getSelection) {
                const selection = wmeSDK.Editing.getSelection();
                log('SDK Selection:', selection);
                if (selection?.segments?.length > 0) {
                    // SDK gibt IDs zurück, wir brauchen die Objekte
                    const segments = selection.segments
                        .map(id => W.model.segments.getObjectById(id))
                        .filter(s => s != null);
                    log(`SDK: ${segments.length} Segmente ausgewählt`);
                    return segments;
                }
            }
            
            // Methode 2: WME Features (neu)
            const wmeFeatures = W.selectionManager.getSelectedWMEFeatures?.() || [];
            if (wmeFeatures.length > 0) {
                const segments = wmeFeatures
                    .filter(f => f.model?.type === 'segment' || f._wmeObject?.type === 'segment')
                    .map(f => f.model || f._wmeObject);
                if (segments.length > 0) {
                    log(`WME Features: ${segments.length} Segmente ausgewählt`);
                    return segments;
                }
            }
            
            // Methode 3: Alte getSelectedFeatures
            const features = W.selectionManager.getSelectedFeatures?.() || [];
            if (features.length > 0) {
                const segments = features
                    .filter(f => {
                        const model = f.model || f._wmeObject || f;
                        return model?.type === 'segment' || model?.attributes?.type === 'segment';
                    })
                    .map(f => f.model || f._wmeObject || f);
                if (segments.length > 0) {
                    log(`getSelectedFeatures: ${segments.length} Segmente ausgewählt`);
                    return segments;
                }
            }
            
            // Methode 4: Direkt aus selectionManager.selectedItems
            if (W.selectionManager.selectedItems) {
                const items = Array.isArray(W.selectionManager.selectedItems) 
                    ? W.selectionManager.selectedItems 
                    : Object.values(W.selectionManager.selectedItems);
                const segments = items.filter(item => {
                    const type = item?.type || item?.model?.type || item?.attributes?.type;
                    return type === 'segment';
                });
                if (segments.length > 0) {
                    log(`selectedItems: ${segments.length} Segmente ausgewählt`);
                    return segments;
                }
            }
            
            // Methode 5: getSelectedDataModelObjects (neueste API)
            if (W.selectionManager.getSelectedDataModelObjects) {
                const objects = W.selectionManager.getSelectedDataModelObjects();
                const segments = objects.filter(obj => obj?.type === 'segment');
                if (segments.length > 0) {
                    log(`getSelectedDataModelObjects: ${segments.length} Segmente ausgewählt`);
                    return segments;
                }
            }
            
            log('Keine Segmente gefunden mit allen Methoden');
            return [];
        } catch (e) {
            log('Fehler bei getSelectedSegments:', e.message);
            return [];
        }
    }

    function getStreetName(segment) {
        const streetID = segment.attributes.primaryStreetID;
        if (!streetID) return t('unnamed');
        const street = W.model.streets.getObjectById(streetID);
        return street?.attributes?.name || t('unnamed');
    }

    function getUserRank() {
        return W.loginManager.user?.attributes?.rank || 0;
    }

    function isRoundabout(segment) {
        return segment.attributes.junctionID != null;
    }

    function isRamp(segment) {
        return segment.attributes.roadType === 4;
    }

    function onSelectionChanged() {
        clearPreview();
        manualPoints = [];
        
        const infoDiv = getElement(`${SCRIPT_ID}-segment-info`);
        const warningsDiv = getElement(`${SCRIPT_ID}-warnings`);
        const splitBtn = getElement(`${SCRIPT_ID}-split-btn`);
        const repeatBtn = getElement(`${SCRIPT_ID}-repeat-btn`);
        const batchBtn = getElement(`${SCRIPT_ID}-batch-btn`);
        const previewDiv = getElement(`${SCRIPT_ID}-preview`);

        if (!infoDiv) {
            log('UI-Elemente nicht gefunden');
            return;
        }

        // Debug: Zeige was im selectionManager ist
        log('=== Selection Debug ===');
        log('selectionManager:', W.selectionManager);
        if (W.selectionManager.getSelectedWMEFeatures) {
            log('getSelectedWMEFeatures:', W.selectionManager.getSelectedWMEFeatures());
        }
        if (W.selectionManager.getSelectedFeatures) {
            log('getSelectedFeatures:', W.selectionManager.getSelectedFeatures());
        }
        if (W.selectionManager.getSelectedDataModelObjects) {
            log('getSelectedDataModelObjects:', W.selectionManager.getSelectedDataModelObjects());
        }
        if (wmeSDK?.Editing?.getSelection) {
            log('SDK getSelection:', wmeSDK.Editing.getSelection());
        }
        log('=======================');

        const segments = getSelectedSegments();
        const warnings = [];

        if (segments.length === 0) {
            infoDiv.innerHTML = `<strong>${t('noSegmentSelected')}</strong><br><small>${t('selectSegments')}</small>`;
            if (splitBtn) splitBtn.disabled = true;
            if (repeatBtn) repeatBtn.disabled = true;
            if (batchBtn) batchBtn.disabled = true;
            if (previewDiv) previewDiv.style.display = 'none';
            if (warningsDiv) warningsDiv.style.display = 'none';
            return;
        }

        if (segments.length > 1) {
            const totalLength = segments.reduce((sum, s) => sum + calculateSegmentLength(s), 0);
            infoDiv.innerHTML = `
                <strong>${segments.length} ${t('segmentsSelected')}</strong><br>
                <small>${t('totalLength')}: ${totalLength.toFixed(2)} ${t('meters')}</small>
            `;
        } else {
            const segment = segments[0];
            const length = calculateSegmentLength(segment);
            const coords = getGeometryCoordinates(segment);
            
            infoDiv.innerHTML = `
                <strong>${t('segmentSelected')}</strong><br>
                <small>ID: ${segment.attributes.id}</small><br>
                <small>${t('length')}: ${length.toFixed(2)} ${t('meters')}</small><br>
                <small>${t('street')}: ${getStreetName(segment)}</small><br>
                <small>${t('geometryNodes')}: ${coords.length}</small><br>
                <small>${t('lock')}: ${(segment.attributes.lockRank || 0) + 1}</small>
            `;
        }

        segments.forEach(segment => {
            if (settings.checkLockLevel) {
                const lockRank = segment.attributes.lockRank || 0;
                const userRank = getUserRank();
                if (lockRank > userRank) {
                    warnings.push(`⚠️ ${t('segmentLocked')} (${lockRank + 1}) ${t('thanYourRank')} (${userRank + 1})`);
                }
            }

            if (settings.protectRoundabouts && isRoundabout(segment)) {
                warnings.push(`🚫 Segment ${segment.attributes.id} ${t('partOfRoundabout')}`);
            }

            if (settings.warnRamps && isRamp(segment)) {
                warnings.push(`⚠️ Segment ${segment.attributes.id} ${t('isRamp')}`);
            }
        });

        if (warningsDiv) {
            if (warnings.length > 0) {
                warningsDiv.style.display = 'block';
                warningsDiv.innerHTML = warnings.map(w => 
                    `<div style="padding: 4px 8px; margin-bottom: 4px; background: #fff3cd; border-radius: 4px; font-size: 11px;">${w}</div>`
                ).join('');
            } else {
                warningsDiv.style.display = 'none';
            }
        }

        const hasBlockingWarnings = warnings.some(w => w.startsWith('🚫'));
        if (splitBtn) splitBtn.disabled = hasBlockingWarnings;
        if (repeatBtn) repeatBtn.disabled = !localStorage.getItem(`${SCRIPT_ID}-lastAction`);
        if (batchBtn) batchBtn.disabled = segments.length !== 1;

        updatePreview();
        updateManualPointsList();
    }

    function updatePreview() {
        const previewDiv = getElement(`${SCRIPT_ID}-preview`);
        const previewText = getElement(`${SCRIPT_ID}-preview-text`);
        const splitBtn = getElement(`${SCRIPT_ID}-split-btn`);

        const segments = getSelectedSegments();
        if (segments.length === 0) {
            if (previewDiv) previewDiv.style.display = 'none';
            clearPreview();
            return;
        }

        if (segments.length > 1) {
            const results = segments.map(s => {
                const length = calculateSegmentLength(s);
                return calculateSplitPoints(length);
            });

            const totalCuts = results.reduce((sum, r) => sum + (r.cuts || 0), 0);
            const totalParts = results.reduce((sum, r) => sum + (r.count || 0), 0);

            if (previewDiv) {
                previewDiv.style.display = 'block';
                previewDiv.style.background = '#e8f4e8';
            }
            if (previewText) {
                previewText.innerHTML = `
                    <span style="color: green;">
                        ${segments.length} Segmente → ${totalParts} Teile<br>
                        ${totalCuts} Schnittpunkte gesamt
                    </span>
                `;
            }
            clearPreview();
            return;
        }

        const segment = segments[0];
        const length = calculateSegmentLength(segment);
        const splitInfo = calculateSplitPoints(length);

        log('Split-Info berechnet:', splitInfo);

        if (splitInfo.error) {
            if (previewDiv) {
                previewDiv.style.display = 'block';
                previewDiv.style.background = '#ffe8e8';
            }
            if (previewText) previewText.innerHTML = `<span style="color: red;">${splitInfo.error}</span>`;
            if (splitBtn) splitBtn.disabled = true;
            clearPreview();
            return;
        }

        if (previewDiv) {
            previewDiv.style.display = 'block';
            previewDiv.style.background = '#e8f4e8';
        }
        if (previewText) {
            previewText.innerHTML = `
                <span style="color: green;">
                    ${splitInfo.count} Teilstücke<br>
                    Je ca. ${splitInfo.segmentLength.toFixed(2)} Meter<br>
                    ${splitInfo.cuts} Schnittpunkte
                </span>
            `;
        }
        
        if (splitBtn) splitBtn.disabled = false;

        if (settings.showPreview && splitInfo.positions) {
            drawPreview(segment, splitInfo.positions);
        }
    }

    function calculateSplitPoints(totalLength) {
        let count, segmentLength, positions = [];
        const effectiveLength = totalLength - settings.offset;

        if (effectiveLength <= 0) {
            return { error: t('offsetLarger') };
        }

        const offsetRatio = settings.offset / totalLength;

        switch (settings.mode) {
            case 'count':
                count = settings.splitCount;
                segmentLength = effectiveLength / count;
                for (let i = 1; i < count; i++) {
                    let pos = offsetRatio + (i / count) * (1 - offsetRatio);
                    if (settings.startFrom === 'b') pos = 1 - pos;
                    positions.push(pos);
                }
                break;

            case 'distance':
                const fullSegments = Math.floor(effectiveLength / settings.splitDistance);
                const remainder = effectiveLength - (fullSegments * settings.splitDistance);
                
                if (settings.enforceMinLength && remainder > 0 && remainder < settings.minSegmentLength && fullSegments > 0) {
                    count = fullSegments;
                    for (let i = 1; i < count; i++) {
                        let pos = offsetRatio + (i * settings.splitDistance / totalLength);
                        if (settings.startFrom === 'b') pos = 1 - pos;
                        positions.push(pos);
                    }
                    segmentLength = settings.splitDistance;
                } else {
                    count = fullSegments + (remainder > 0 ? 1 : 0);
                    for (let i = 1; i < count; i++) {
                        let pos = offsetRatio + (i * settings.splitDistance / totalLength);
                        if (pos >= 1) break;
                        if (settings.startFrom === 'b') pos = 1 - pos;
                        positions.push(pos);
                    }
                    segmentLength = settings.splitDistance;
                }
                count = positions.length + 1;
                break;

            case 'percent':
                positions = settings.percentages.map(p => {
                    let pos = p / 100;
                    if (settings.startFrom === 'b') pos = 1 - pos;
                    return pos;
                });
                count = positions.length + 1;
                segmentLength = totalLength / count;
                break;

            case 'geometry':
                const segment = getSelectedSegments()[0];
                if (segment) {
                    const coords = getGeometryCoordinates(segment);
                    if (coords.length > 2) {
                        let accLength = 0;
                        const lengths = [];
                        for (let i = 0; i < coords.length - 1; i++) {
                            lengths.push(haversineDistance(
                                coords[i].lon, coords[i].lat,
                                coords[i+1].lon, coords[i+1].lat
                            ));
                        }
                        const geoTotalLength = lengths.reduce((a, b) => a + b, 0);
                        
                        for (let i = 1; i < coords.length - 1; i++) {
                            accLength += lengths[i - 1];
                            positions.push(accLength / geoTotalLength);
                        }
                    }
                }
                count = positions.length + 1;
                segmentLength = totalLength / count;
                break;

            case 'manual':
                positions = [...manualPoints];
                count = positions.length + 1;
                segmentLength = count > 1 ? totalLength / count : totalLength;
                break;

            default:
                return { error: t('unknownMode') };
        }

        if (positions.length === 0) {
            return { error: t('noSplitPoints') };
        }

        positions.sort((a, b) => a - b);

        if (settings.enforceMinLength && settings.mode !== 'distance') {
            positions = enforceMinimumLength(positions, totalLength);
        }

        return {
            count: positions.length + 1,
            segmentLength: segmentLength,
            cuts: positions.length,
            positions: positions
        };
    }

    function enforceMinimumLength(positions, totalLength) {
        if (positions.length === 0) return positions;

        const minRatio = settings.minSegmentLength / totalLength;
        let result = [];
        let allPositions = [0, ...positions, 1];

        for (let i = 1; i < allPositions.length - 1; i++) {
            const segmentBefore = allPositions[i] - (result.length > 0 ? result[result.length - 1] : 0);
            const segmentAfter = allPositions[i + 1] - allPositions[i];

            if (segmentAfter < minRatio && i < allPositions.length - 2) {
                continue;
            }

            if (segmentBefore < minRatio) {
                continue;
            }

            result.push(allPositions[i]);
        }

        if (result.length > 0) {
            const lastSegment = 1 - result[result.length - 1];
            if (lastSegment < minRatio) {
                result.pop();
            }
        }

        return result;
    }

    function splitSegments() {
        const segments = getSelectedSegments();
        if (segments.length === 0) {
            showStatus(t('noSegmentsSelected'), 'error');
            return;
        }

        // Prüfe tägliches Limit
        const remainingToday = getRemainingDailyUsage();
        if (remainingToday <= 0) {
            showStatus(`${t('dailyLimitReached')} ${MAX_SPLITS_PER_DAY} ${t('actionsPerDay')}`, 'error');
            log('Tageslimit erreicht');
            return;
        }

        log(`Starte Split für ${segments.length} Segment(e)`);
        log(`SDK verfügbar: ${!!wmeSDK}`);
        log(`Verbleibende Aktionen heute: ${remainingToday}`);

        let totalSplits = 0;
        let errors = [];

        // Speichere letzte Aktion
        localStorage.setItem(`${SCRIPT_ID}-lastAction`, JSON.stringify({
            mode: settings.mode,
            splitCount: settings.splitCount,
            splitDistance: settings.splitDistance,
            minSegmentLength: settings.minSegmentLength,
            enforceMinLength: settings.enforceMinLength,
            percentages: settings.percentages,
            startFrom: settings.startFrom,
            offset: settings.offset
        }));

        try {
            segments.forEach(segment => {
                try {
                    const result = splitSingleSegment(segment);
                    totalSplits += result;
                } catch (e) {
                    errors.push(`Segment ${segment.attributes.id}: ${e.message}`);
                    log(`Fehler bei Segment ${segment.attributes.id}:`, e);
                }
            });

            if (errors.length > 0) {
                showStatus(`${totalSplits} ${t('splitsDone')}, ${errors.length} ${t('errors')}`, 'error');
                log('Fehler:', errors);
            } else if (totalSplits > 0) {
                // Zähle als eine Aktion (nicht pro Split)
                incrementDailyUsage();
                const remaining = getRemainingDailyUsage();
                showStatus(`${totalSplits} ${t('splitsCreated')} (${remaining}/${MAX_SPLITS_PER_DAY} ${t('actionsRemaining')})`, 'success');
            } else {
                showStatus(t('noSplitsDone'), 'error');
            }

            const repeatBtn = getElement(`${SCRIPT_ID}-repeat-btn`);
            if (repeatBtn) repeatBtn.disabled = false;
            clearPreview();

        } catch (e) {
            showStatus(`${t('error')}: ${e.message}`, 'error');
            log(`Allgemeiner Fehler:`, e);
        }
    }

    function splitSingleSegment(segment) {
        const length = calculateSegmentLength(segment);
        log(`Segment ${segment.attributes.id}: Länge = ${length.toFixed(2)}m`);
        
        const splitInfo = calculateSplitPoints(length);
        log(`Split-Info:`, splitInfo);

        if (splitInfo.error) {
            throw new Error(splitInfo.error);
        }

        const positions = splitInfo.positions;
        if (!positions || positions.length === 0) {
            throw new Error(t('noSplitPoints'));
        }
        
        // Prüfe Maximum Splits pro Segment
        if (positions.length > MAX_SPLITS_PER_SEGMENT) {
            throw new Error(`${t('tooManySplits')} (${positions.length})! ${t('maximum')}: ${MAX_SPLITS_PER_SEGMENT}`);
        }

        // Lade SplitSegments Action (mit s am Ende!)
        let SplitSegmentsAction = null;
        try {
            SplitSegmentsAction = require('Waze/Action/SplitSegments');
            log('SplitSegments Action geladen:', typeof SplitSegmentsAction);
        } catch (e) {
            log('SplitSegments Action nicht verfügbar:', e.message);
        }

        if (!SplitSegmentsAction) {
            throw new Error(t('noSplitPoints'));
        }

        // Sortiere Positionen von vorne nach hinten (aufsteigend)
        const sortedPositions = [...positions].sort((a, b) => a - b);
        let splitCount = 0;
        
        // Tracke wo das aktuelle Segment im Original beginnt
        let currentSegmentId = segment.attributes.id;
        let currentSegmentStartInOriginal = 0; // Wo beginnt das aktuelle Segment im Original (0-1)
        
        log(`Geplante Splits: ${sortedPositions.length} bei Positionen: ${sortedPositions.map(p => (p*100).toFixed(1) + '%').join(', ')}`);

        for (let i = 0; i < sortedPositions.length; i++) {
            const absolutePos = sortedPositions[i];
            
            const currentSegment = W.model.segments.getObjectById(currentSegmentId);
            if (!currentSegment) {
                log(`Segment ${currentSegmentId} nicht mehr gefunden, breche ab`);
                break;
            }
            
            // Berechne die relative Position im aktuellen Segment
            // Das aktuelle Segment geht von currentSegmentStartInOriginal bis 1.0 (im Original)
            // Wir wollen bei absolutePos splitten
            // Relative Position = (absolutePos - start) / (1 - start)
            const segmentRangeInOriginal = 1 - currentSegmentStartInOriginal;
            const relativePos = (absolutePos - currentSegmentStartInOriginal) / segmentRangeInOriginal;
            
            log(`Split ${i + 1}/${sortedPositions.length}:`);
            log(`  Absolute Position im Original: ${(absolutePos * 100).toFixed(1)}%`);
            log(`  Aktuelles Segment beginnt bei: ${(currentSegmentStartInOriginal * 100).toFixed(1)}%`);
            log(`  Segment-Bereich: ${(segmentRangeInOriginal * 100).toFixed(1)}%`);
            log(`  Relative Position im Segment: ${(relativePos * 100).toFixed(1)}%`);
            
            if (relativePos <= 0.001 || relativePos >= 0.999) {
                log(`  Ungültige relative Position, überspringe`);
                continue;
            }
            
            // Berechne den Split-Punkt als GeoJSON (WGS84)
            const splitPointGeoJSON = getPointAtPosition(currentSegment, relativePos, true);
            
            if (!splitPointGeoJSON) {
                log('  Konnte Split-Punkt nicht berechnen');
                continue;
            }
            
            log(`  Split-Punkt: lon=${splitPointGeoJSON.coordinates[0].toFixed(6)}, lat=${splitPointGeoJSON.coordinates[1].toFixed(6)}`);
            
            try {
                const action = new SplitSegmentsAction(currentSegment, {
                    splitAtPoint: splitPointGeoJSON
                });
                
                log('  Action erstellt, füge hinzu...');
                W.model.actionManager.add(action);
                
                splitCount++;
                log(`  Split ${splitCount} erfolgreich!`);
                
                // Debug: Zeige alle Properties der Action
                log('  Action Properties:', Object.keys(action));
                log('  action.splitSegmentPair:', action.splitSegmentPair);
                log('  action.newSegments:', action.newSegments);
                log('  action.segment:', action.segment?.attributes?.id);
                log('  action.newNode:', action.newNode);
                
                // Nach dem Split: Das "hintere" Segment (B-Seite) wird für weitere Splits verwendet
                // Und wir aktualisieren wo das neue Segment im Original beginnt
                let foundNextSegment = false;
                
                if (action.splitSegmentPair) {
                    log(`  splitSegmentPair gefunden:`, action.splitSegmentPair);
                    const newSegments = action.splitSegmentPair;
                    
                    if (Array.isArray(newSegments) && newSegments.length >= 2) {
                        // Das Array enthält Segment-OBJEKTE, nicht IDs!
                        const secondSegment = newSegments[1];
                        // Extrahiere die ID aus dem Segment-Objekt
                        if (secondSegment && secondSegment.attributes && secondSegment.attributes.id !== undefined) {
                            currentSegmentId = secondSegment.attributes.id;
                            log(`  Segment-Objekt gefunden, ID: ${currentSegmentId}`);
                        } else if (typeof secondSegment === 'number') {
                            currentSegmentId = secondSegment;
                            log(`  Direkte ID gefunden: ${currentSegmentId}`);
                        } else if (secondSegment && secondSegment.id !== undefined) {
                            currentSegmentId = secondSegment.id;
                            log(`  ID aus .id Property: ${currentSegmentId}`);
                        } else {
                            log(`  Konnte ID nicht extrahieren aus:`, typeof secondSegment, secondSegment);
                        }
                        currentSegmentStartInOriginal = absolutePos;
                        foundNextSegment = true;
                        log(`  Nächstes Segment ID: ${currentSegmentId}, beginnt bei ${(currentSegmentStartInOriginal * 100).toFixed(1)}%`);
                    } else if (typeof newSegments === 'object' && newSegments !== null) {
                        const keys = Object.keys(newSegments);
                        log(`  splitSegmentPair ist Objekt mit Keys:`, keys);
                        const secondSeg = newSegments.second || newSegments.b || newSegments[1] || newSegments.newSegment;
                        if (secondSeg) {
                            currentSegmentId = secondSeg.attributes?.id || secondSeg.id || secondSeg;
                            currentSegmentStartInOriginal = absolutePos;
                            foundNextSegment = true;
                            log(`  Nächstes Segment (aus Objekt): ${currentSegmentId}`);
                        }
                    }
                }
                
                // Fallback: Versuche newSegments zu nutzen
                if (!foundNextSegment && action.newSegments) {
                    log(`  Versuche newSegments:`, action.newSegments);
                    if (Array.isArray(action.newSegments) && action.newSegments.length >= 2) {
                        const seg = action.newSegments[1];
                        currentSegmentId = seg?.attributes?.id || seg?.id || seg;
                        currentSegmentStartInOriginal = absolutePos;
                        foundNextSegment = true;
                        log(`  Nächstes Segment (newSegments[1]): ${currentSegmentId}`);
                    }
                }
                
                // Fallback 2: Suche nach neuen Segmenten im Model
                if (!foundNextSegment) {
                    log('  Kein nächstes Segment gefunden, suche im Model...');
                    // Das Original-Segment existiert vielleicht noch mit gleicher ID aber kürzerer Geometrie
                    // Oder es gibt ein neues Segment
                    currentSegmentStartInOriginal = absolutePos;
                    log(`  Setze currentSegmentStartInOriginal auf ${(absolutePos * 100).toFixed(1)}% und hoffe das Beste`);
                }
                
            } catch (e) {
                log(`  Split-Fehler: ${e.message}`);
                log('  Stack:', e.stack);
            }
        }

        log(`splitSingleSegment abgeschlossen: ${splitCount} von ${sortedPositions.length} Splits erfolgreich`);
        return splitCount;
    }

    function repeatLastAction() {
        const lastAction = localStorage.getItem(`${SCRIPT_ID}-lastAction`);
        if (!lastAction) {
            showStatus(t('noLastAction'), 'error');
            return;
        }

        try {
            const action = JSON.parse(lastAction);
            settings.mode = action.mode;
            settings.splitCount = action.splitCount;
            settings.splitDistance = action.splitDistance;
            settings.minSegmentLength = action.minSegmentLength;
            settings.enforceMinLength = action.enforceMinLength ?? true;
            settings.percentages = action.percentages;
            settings.startFrom = action.startFrom;
            settings.offset = action.offset;
            
            saveSettings();
            updateUI();
            splitSegments();
        } catch (e) {
            showStatus(`${t('error')}: ${e.message}`, 'error');
        }
    }

    function batchProcessStreet() {
        const segments = getSelectedSegments();
        if (segments.length !== 1) {
            showStatus(t('selectOneSegment'), 'error');
            return;
        }

        const segment = segments[0];
        const streetID = segment.attributes.primaryStreetID;
        
        if (!streetID) {
            showStatus(t('noStreetAssignment'), 'error');
            return;
        }

        const allSegments = Object.values(W.model.segments.objects)
            .filter(s => s.attributes.primaryStreetID === streetID);

        if (allSegments.length === 0) {
            showStatus(t('noSegmentsFound'), 'error');
            return;
        }

        const streetName = getStreetName(segment);
        
        if (!confirm(`${allSegments.length} ${t('processSegments')} "${streetName}"?`)) {
            return;
        }

        let totalSplits = 0;
        let errors = [];

        try {
            allSegments.forEach(seg => {
                if (settings.protectRoundabouts && isRoundabout(seg)) return;
                if (settings.checkLockLevel && (seg.attributes.lockRank || 0) > getUserRank()) return;

                try {
                    const result = splitSingleSegment(seg);
                    totalSplits += result;
                } catch (e) {
                    errors.push(`${seg.attributes.id}: ${e.message}`);
                }
            });

            showStatus(`"${streetName}": ${totalSplits} ${t('splitsOnStreet')}`, 'success');
            
        } catch (e) {
            showStatus(`${t('error')}: ${e.message}`, 'error');
        }
    }

    function showStatus(message, type) {
        const statusDiv = getElement(`${SCRIPT_ID}-status`);
        if (!statusDiv) return;
        
        statusDiv.style.display = 'block';
        statusDiv.style.background = type === 'error' ? '#ffe8e8' : '#e8f4e8';
        statusDiv.style.color = type === 'error' ? '#c00' : '#080';
        statusDiv.innerHTML = message;
        
        log(`Status (${type}): ${message}`);
        
        // Aktualisiere Limit-Anzeige
        updateDailyLimitDisplay();

        setTimeout(() => {
            statusDiv.style.display = 'none';
        }, 5000);
    }
    
    function updateDailyLimitDisplay() {
        const limitDiv = getElement(`${SCRIPT_ID}-daily-limit`);
        if (!limitDiv) return;
        
        const remaining = getRemainingDailyUsage();
        const color = remaining <= 2 ? '#f8d7da' : remaining <= 5 ? '#fff3cd' : '#d4edda';
        
        limitDiv.style.background = color;
        limitDiv.innerHTML = `📊 <strong>${remaining}</strong>/${MAX_SPLITS_PER_DAY} ${t('actionsRemaining')}`;
    }

    // Start
    init();
})();