#!/usr/bin/python3

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import subprocess
import os
import sys
import re
import getpass
import typing
import subprocess
import logging

# Set up logging
logger = logging.getLogger(__name__)
EMPTY_PASSWORD = 'EMPTY_PASSWORD'


def scrambleString(password: str, fallback_to_plain: bool = False) -> str:
    """
    Scramble a password using the nxscramble binary with enhanced error handling.
    """
    try:
        # Run nxscramble with the password as input
        result = subprocess.run(
            ['/usr/bin/nxscramble', password],
            capture_output=True,
            text=True,
            check=True,
            timeout=5  # 5 second timeout
        )

        scrambled_password = result.stdout.strip()

        if not scrambled_password:
            raise ValueError("nxscramble returned empty result")

        logger.debug(f"Successfully scrambled password (length: {len(scrambled_password)})")
        return scrambled_password

    except subprocess.CalledProcessError as e:
        error_msg = f"nxscramble failed with exit code {e.returncode}: {e.stderr}"
        logger.error(error_msg)
        if fallback_to_plain:
            logger.warning("Falling back to plain password due to scrambling failure")
            return password
        raise RuntimeError(error_msg) from e

    except FileNotFoundError:
        error_msg = "nxscramble binary not found at /usr/bin/nxscramble"
        logger.error(error_msg)
        if fallback_to_plain:
            logger.warning("Falling back to plain password - nxscramble not found")
            return password
        raise RuntimeError(error_msg) from None

    except subprocess.TimeoutExpired:
        error_msg = "nxscramble timed out after 5 seconds"
        logger.error(error_msg)
        if fallback_to_plain:
            logger.warning("Falling back to plain password - nxscramble timed out")
            return password
        raise RuntimeError(error_msg) from None

    except Exception as e:
        error_msg = f"Unexpected error while scrambling password: {e}"
        logger.error(error_msg)
        if fallback_to_plain:
            logger.warning("Falling back to plain password due to unexpected error")
            return password
        raise RuntimeError(error_msg) from e

def scrambleStringSafe(password: typing.Optional[str], fallback_to_plain: bool = True) -> str:
    """
    Safe version that handles None and empty strings.
    """
    if not password:
        return EMPTY_PASSWORD

    try:
        return scrambleString(password, fallback_to_plain=fallback_to_plain)
    except Exception as e:
        if fallback_to_plain:
            logger.error(f"Password scrambling failed, using plain text: {e}")
            return password
        else:
            raise


# Then continue with the rest of your existing code...
NXTEMPLATE = '''<!DOCTYPE NXClientSettings>
<NXClientSettings version="2.0" application="nxclient" >
 <group name="Advanced" >
  <option key="Grab keyboard input" value="" />
  <option key="Grab mouse input" value="" />
  <option key="Enable remote cursor tracking" value="" />
  <option key="Enable HTTP proxy" value="false" />
  <option key="HTTP proxy host" value="" />
  <option key="HTTP proxy port" value="8080" />
  <option key="HTTP proxy password" value="EMPTY_PASSWORD" />
  <option key="Remember HTTP proxy password" value="false" />
  <option key="HTTP proxy username" value="" />
  <option key="Emulate middle mouse button" value="" />
  <option key="Use TOR for SOCKS proxy connections" value="false" />
  <option key="Use URL for automatic proxy configuration" value="false" />
  <option key="Manual proxy configuration type" value="http" />
  <option key="Proxy configuration mode" value="manual" />
  <option key="Automatic proxy configuration URL" value="" />
 </group>
 <group name="Environment" >
  <option key="Use font server" value="false" />
  <option key="Font server host" value="" />
  <option key="Font server port" value="7100" />
 </group>
 <group name="General" >
  <option key="Automatically connect to session with specified ID" value="" />
  <option key="Enable session auto-resize" value="" />
  <option key="Physical desktop auto-resize" value="false" />
  <option key="Virtual desktop auto-resize" value="false" />
  <option key="Close the client application when a single session terminates" value="true" />
  <option key="Connection service" value="nx" />
  <option key="Always create a physical desktop on a headless Linux host" value="false" />
  <option key="View a specific monitor among available monitors" value="0" />
  <option key="Command line" value="" />
  <option key="Use custom server" value="false" />
  <option key="Custom server command" value="/etc/NX/nxserver" />
  <option key="Custom Unix Desktop" value="" />
  <option key="NoMachine daemon port" value="{PORT}" />
  <option key="Connect to this node when manual selection is enabled" value="" />
  <option key="Connect to this server when manual selection is enabled" value="" />
  <option key="Desktop" value="" />
  <option key="Disable SHM" value="false" />
  <option key="Disable emulate shared pixmaps" value="false" />
  <option key="Use render" value="true" />
  <option key="Try to wake up server when it is powered off" value="false" />
  <option key="Last connection time" value="78793200" />
  <option key="Link quality" value="5" />
  <option key="Platform of the last connection" value="UDS" />
  <option key="Node primary display resolution" value="" />
  <option key="Node UUID" value="" />
  <option key="Physical desktop resize mode" value="scaled" />
  <option key="Session resize mode" value="" />
  <option key="Virtual desktop resize mode" value="viewport" />
  <option key="Server MAC address" value="" />
  <option key="Resize the remote screen upon connecting" value="no" />
  <option key="Resolution" value="" />
  <option key="Use WebRTC for multimedia data" value="true" />
  <option key="Remember session window size and position" value="" />
  <option key="Remember password" value="false" />
  <option key="Remember username" value="false" />
  <option key="Session screenshot" value="" />
  <option key="Server hardware" value="" />
  <option key="Server host" value="{HOST}" />
  <option key="Server port" value="{PORT}" />
  <option key="Server product" value="" />
  <option key="Server product version" value="" />
  <option key="Server hardware specifications" value="" />
  <option key="Session" value="UDS" />
  <option key="Show expiring license warning message" value="false" />
  <option key="Show remote audio alert message" value="false" />
  <option key="Show remote display resize message" value="false" />
  <option key="Show remote desktop view mode message" value="false" />
  <option key="Use UDP communication for multimedia data" value="{UDP}" />
  <option key="Virtual desktop" value="true" />
  <option key="NoMachine web server port" value="4443" />
  <option key="Web session information token" value="" />
  <option key="Session window geometry" value="" />
  <option key="Session window state" value="{WINDOW_SIZE}" />
  <option key="xdm mode" value="" />
  <option key="xdm broadcast port" value="177" />
  <option key="xdm list host" value="localhost" />
  <option key="xdm list port" value="177" />
  <option key="xdm query host" value="localhost" />
  <option key="xdm query port" value="177" />
  <option key="Use custom resolution" value="false" />
  <option key="Resolution width" value="" />
  <option key="Resolution height" value="" />
 </group>
 <group name="Login" >
  <option key="Always use selected user login" value="true" />
  <option key="Alternate NX Key" value="" />
  <option key="Forward SSH authentication" value="false" />
  <option key="Guest Mode" value="false" />
  <option key="Guest password" value="" />
  <option key="Guest username" value="" />
  <option key="Guest server" value="" />
  <option key="Guest desktop sharing mode" value="false" />
  <option key="Last selected user login" value="system user" />
  <option key="Server authentication method" value="system" />
  <option key="Auth" value="{PASSWORD}" />
  <option key="User" value="{USERNAME}" />
  <option key="Wallix login" value="" />
  <option key="NX login method" value="password" />
  <option key="Private key for NX authentication" value="" />
  <option key="Use alternate smart card module" value="false" />
  <option key="Smart card authentication module" value="" />
  <option key="Private key" value="" />
  <option key="Public Key" value="" />
  <option key="System auth" value="{PASSWORD}" />
  <option key="Two-factor authentication password" value="EMPTY_PASSWORD" />
  <option key="Remember NoMachine password" value="false" />
  <option key="Remember two-factor authentication password" value="false" />
  <option key="Imported private key for NX authentication" value="" />
  <option key="Use imported private key for NX authentication" value="false" />
  <option key="Imported private key" value="" />
  <option key="Use imported private key" value="false" />
  <option key="NoMachine Network login code" value="EMPTY_PASSWORD" />
  <option key="Remember NoMachine Network access ID" value="false" />
  <option key="NoMachine Network access ID" value="EMPTY_PASSWORD" />
  <option key="System login method" value="password" />
  <option key="Use alternate NX Key" value="false" />
  <option key="GSSAPI subsystem for the kerberos authentication" value="kerberos" />
  <option key="Kerberos key exchange to identify server host" value="false" />
  <option key="DNS translation when passing server to Kerberos library" value="false" />
 </group>
 <group name="Images" >
  <option key="Disable network-adaptive quality" value="false" />
  <option key="Disable backingstore" value="false" />
  <option key="Disable composite" value="false" />
  <option key="Disable image post-processing" value="false" />
  <option key="Disable frame buffering on decoding" value="false" />
  <option key="Disable lossless display refinement" value="false" />
  <option key="Disable multi-pass display encoding" value="false" />
  <option key="E-reader display update policy" value="false" />
  <option key="Video frame rate for display server" value="30" />
  <option key="Stream downsampling factor" value="0" />
  <option key="Request a specific frame rate" value="false" />
  <option key="Video encoding quality" value="5" />
 </group>
 <group name="Services" >
  <option key="Output audio device" value="autodetect" />
  <option key="Output audio quality" value="5" />
  <option key="Audio" value="true" />
  <option key="IPPPrinting" value="true" />
  <option key="Enable devices sharing" value="true" />
  <option key="Shares" value="true" />
  <option key="Mute audio of the remote physical desktop" value="true" />
  <option key="Input voice device" value="autodetect" />
  <option key="Input voice quality" value="5" />
 </group>
 <group name="VNC Session" >
  <option key="Display" value=":0" />
  <option key="Password" value="EMPTY_PASSWORD" />
  <option key="Remember login credentials" value="false" />
  <option key="Remember" value="false" />
  <option key="Server" value="" />
 </group>
 <group name="Windows Session" >
  <option key="Application" value="" />
  <option key="Authentication" value="2" />
  <option key="Domain" value="" />
  <option key="Password" value="EMPTY_PASSWORD" />
  <option key="Remember login credentials" value="false" />
  <option key="Remember" value="false" />
  <option key="Run application" value="false" />
  <option key="Server" value="" />
  <option key="User" value="" />
 </group>
 <group name="Remote Session" >
  <option key="Host" value="" />
  <option key="Port" value="" />
  <option key="Username" value="" />
  <option key="Password" value="EMPTY_PASSWORD" />
  <option key="Remember login credentials" value="false" />
  <option key="Fingerprint" value="" />
 </group>
</NXClientSettings>
'''

class NoMachineFile:
    def __init__(
            self,
            username: str,
            password: typing.Optional[str] = None,
            host: typing.Optional[str] = None,
            port: typing.Optional[str] = None,
            window_size: str = "normal",
            useUDP: bool = False
    ):
        self.username = username or ""
        self.password = password or ""
        self.host = host or ""
        self.port = port or "4000"
        self.window_size = window_size
        self.useUDP = useUDP

    def get(self) -> str:
        # Scramble password if provided
        scrambled = scrambleStringSafe(self.password)

        # Additional XML escaping for safety
        scrambled = (
            scrambled.replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace('"', "&quot;")
            .replace("'", "&apos;")
        )

        udp_val = "true" if self.useUDP else "false"

        return NXTEMPLATE.format(
            HOST=self.host,
            PORT=self.port,
            USERNAME=self.username,
            PASSWORD=scrambled,
            WINDOW_SIZE=self.window_size,
            UDP=udp_val
        )

    @property
    def as_file(self) -> str:
        return self.get()

class FirstBootApp:
    def __init__(self, root):
        self.root = root
        self.root.title("RDP Configuration")
        self.root.geometry("800x750")
        self.password = None
        self.network_interfaces = []

        # Create notebook for tabs
        self.notebook = ttk.Notebook(root)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Create tabs
        self.auth_frame = ttk.Frame(self.notebook)
        self.network_frame = ttk.Frame(self.notebook)
        self.connections_frame = ttk.Frame(self.notebook)  # Replaced SSH with Connections
        self.scanners_frame = ttk.Frame(self.notebook)
        self.printers_frame = ttk.Frame(self.notebook)
        self.usbip_frame = ttk.Frame(self.notebook)  # NEW: USB over Network tab

        self.notebook.add(self.auth_frame, text="1. Authentication")
        self.notebook.add(self.network_frame, text="2. Network Config")
        self.notebook.add(self.connections_frame, text="3. Connections")  # Replaced SSH
        self.notebook.add(self.scanners_frame, text="4. Scanners")
        self.notebook.add(self.printers_frame, text="5. Printers")
        self.notebook.add(self.usbip_frame, text="6. USB over Network")  # NEW USB OVER NET


        self.setup_auth_tab()
        self.setup_network_tab()
        self.setup_connections_tab()  # New method for connections
        self.setup_scanners_tab()
        self.setup_printers_tab()
        self.setup_usbip_tab()  # NEW

        # Disable tabs until authenticated
        self.notebook.tab(1, state="disabled")
        self.notebook.tab(2, state="disabled")
        self.notebook.tab(3, state="disabled")
        self.notebook.tab(4, state="disabled")
        self.notebook.tab(5, state="disabled")  # NEW: Disable USB tab

        # Track changes for auto-generation
        self.setup_auto_generation()

        # Bind tab change event
        self.notebook.bind('<<NotebookTabChanged>>', self.on_tab_changed)

    def on_tab_changed(self, event):
        """Handle tab change events"""
        current_tab = self.notebook.index(self.notebook.select())

        # If Scanners or Printers tab is selected, auto-refresh status
        if current_tab == 3:  # Scanners tab
            self.refresh_scanner_services()
            self.refresh_scanner_devices()  # Refresh scanner devices when tab is selected
        elif current_tab == 4:  # Printers tab
            self.refresh_printer_services()
            # Only check CUPS status if authenticated
            if self.password is not None:
                self.check_cups_status()
            else:
                self.cups_status_label.config(text="Please authenticate to check CUPS status")
        elif current_tab == 2:  # Connections tab
            self.refresh_connections_list()
        elif current_tab == 5:  # USB over Network tab
            self.refresh_usbip_devices()
            self.refresh_usbip_service_status()

    def detect_network_interfaces(self):
        """Detect available network interfaces with detailed information"""
        interfaces = []

        try:
            # Method 1: Using ip command (most reliable)
            result = subprocess.run(['ip', 'addr', 'show'], capture_output=True, text=True, timeout=5)
            if result.returncode == 0:
                current_interface = None
                for line in result.stdout.split('\n'):
                    # Look for interface lines (e.g., "2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP>")
                    if re.match(r'^\d+:', line):
                        parts = line.split(':')
                        if len(parts) >= 2:
                            current_interface = parts[1].strip()
                            if current_interface and current_interface != 'lo':  # Skip loopback
                                interfaces.append(current_interface)

            # If ip command failed, try alternative methods
            if not interfaces:
                # Method 2: Using /sys/class/net
                if os.path.exists('/sys/class/net'):
                    for item in os.listdir('/sys/class/net'):
                        if item != 'lo':  # Skip loopback
                            interfaces.append(item)

                # Method 3: Using ifconfig
                if not interfaces:
                    result = subprocess.run(['ifconfig', '-a'], capture_output=True, text=True, timeout=5)
                    if result.returncode == 0:
                        for line in result.stdout.split('\n'):
                            if line and not line.startswith(' ') and ':' in line:
                                interface = line.split(':')[0]
                                if interface and interface != 'lo':
                                    interfaces.append(interface)

            # Remove duplicates and sort
            interfaces = sorted(list(set(interfaces)))

            # Get interface details for display
            detailed_interfaces = []
            for interface in interfaces:
                details = self.get_interface_details(interface)
                detailed_interfaces.append(details)

            return detailed_interfaces

        except Exception as e:
            print(f"Error detecting interfaces: {e}")
            # Fallback to common interface names
            return [
                {"name": "eth0", "status": "Unknown", "mac": "N/A", "ip": "N/A"},
                {"name": "wlan0", "status": "Unknown", "mac": "N/A", "ip": "N/A"},
                {"name": "enp0s3", "status": "Unknown", "mac": "N/A", "ip": "N/A"},
                {"name": "wlp2s0", "status": "Unknown", "mac": "N/A", "ip": "N/A"}
            ]

    def get_interface_details(self, interface):
        """Get detailed information about a network interface"""
        details = {
            "name": interface,
            "status": "Down",
            "mac": "N/A",
            "ip": "N/A",
            "subnet": "N/A",
            "gateway": "N/A",
            "dns": "N/A"
        }

        try:
            # Get interface status
            operstate_path = f"/sys/class/net/{interface}/operstate"
            if os.path.exists(operstate_path):
                with open(operstate_path, 'r') as f:
                    details["status"] = f.read().strip().capitalize()

            # Get MAC address
            address_path = f"/sys/class/net/{interface}/address"
            if os.path.exists(address_path):
                with open(address_path, 'r') as f:
                    details["mac"] = f.read().strip()

            # Get IP address and subnet using ip command
            result = subprocess.run(['ip', 'addr', 'show', interface], capture_output=True, text=True, timeout=5)
            if result.returncode == 0:
                for line in result.stdout.split('\n'):
                    if 'inet ' in line:
                        ip_match = re.search(r'inet (\d+\.\d+\.\d+\.\d+)/(\d+)', line)
                        if ip_match:
                            details["ip"] = ip_match.group(1)
                            # Convert CIDR to subnet mask
                            cidr = int(ip_match.group(2))
                            details["subnet"] = self.cidr_to_subnet(cidr)
                            break

            # Get gateway
            result = subprocess.run(['ip', 'route', 'show', 'default'], capture_output=True, text=True, timeout=5)
            if result.returncode == 0:
                for line in result.stdout.split('\n'):
                    if 'default via' in line and f'dev {interface}' in line:
                        gateway_match = re.search(r'default via (\d+\.\d+\.\d+\.\d+)', line)
                        if gateway_match:
                            details["gateway"] = gateway_match.group(1)
                            break

            # Get DNS servers from resolv.conf
            if os.path.exists('/etc/resolv.conf'):
                with open('/etc/resolv.conf', 'r') as f:
                    dns_servers = []
                    for line in f:
                        if line.startswith('nameserver'):
                            dns_match = re.search(r'nameserver\s+(\S+)', line)
                            if dns_match:
                                dns_servers.append(dns_match.group(1))
                    if dns_servers:
                        details["dns"] = ', '.join(dns_servers)

        except Exception as e:
            print(f"Error getting details for {interface}: {e}")

        return details

    def cidr_to_subnet(self, cidr):
        """Convert CIDR notation to subnet mask"""
        if 0 <= cidr <= 32:
            mask = (0xffffffff >> (32 - cidr)) << (32 - cidr)
            return '.'.join([str((mask >> 24) & 0xff), str((mask >> 16) & 0xff),
                             str((mask >> 8) & 0xff), str(mask & 0xff)])
        return "255.255.255.0"  # Default

    def get_current_scanner_subnets(self):
        """Read current scanner subnets from /etc/sane.d/saned.conf"""
        subnets = []
        try:
            if os.path.exists('/etc/sane.d/saned.conf'):
                with open('/etc/sane.d/saned.conf', 'r') as f:
                    for line in f:
                        line = line.strip()
                        # Skip empty lines and comments
                        if line and not line.startswith('#'):
                            # Check if it looks like an IP/subnet
                            if re.match(r'^\d+\.\d+\.\d+\.\d+(\/\d+)?$', line):
                                subnets.append(line)
        except Exception as e:
            print(f"Error reading scanner subnets: {e}")
        return subnets

    def refresh_scanner_aliases(self):
        """Refresh and display current scanner aliases in listbox"""
        aliases = self.get_current_scanner_aliases()

        # Clear listbox
        self.aliases_listbox.delete(0, tk.END)

        if aliases:
            for alias in aliases:
                self.aliases_listbox.insert(tk.END, alias)
        else:
            self.aliases_listbox.insert(tk.END, "No aliases configured")

    def get_current_scanner_aliases(self):
        """Read current scanner aliases from /etc/sane.d/dll.aliases"""
        aliases = []
        try:
            if os.path.exists('/etc/sane.d/dll.aliases'):
                with open('/etc/sane.d/dll.aliases', 'r') as f:
                    for line in f:
                        line = line.strip()
                        # Skip empty lines and comments
                        if line and not line.startswith('#'):
                            aliases.append(line)
        except Exception as e:
            print(f"Error reading scanner aliases: {e}")
        return aliases

    def refresh_interfaces(self):
        """Refresh the network interfaces list"""
        self.network_interfaces = self.detect_network_interfaces()

        # Update the combobox
        interface_names = [iface["name"] for iface in self.network_interfaces]
        self.interface_combo['values'] = interface_names

        # Update the details display
        self.update_interface_details()

        # Select the first interface by default if none selected
        if interface_names and not self.interface_var.get():
            self.interface_combo.set(interface_names[0])
            self.update_interface_details()

    def update_interface_details(self):
        """Update the interface details display"""
        selected_interface = self.interface_var.get()
        if selected_interface:
            for iface in self.network_interfaces:
                if iface["name"] == selected_interface:
                    # Update details label
                    details_text = f"Status: {iface['status']}"
                    self.interface_details_label.config(text=details_text)

                    # Update current configuration display
                    current_config_text = f"Current Configuration:\n"
                    current_config_text += f"IP: {iface['ip']}\n"
                    current_config_text += f"Subnet: {iface['subnet']}\n"
                    current_config_text += f"Gateway: {iface['gateway']}\n"
                    current_config_text += f"DNS: {iface['dns']}"
                    self.current_config_label.config(text=current_config_text)

                    # Auto-fill IP if available and not manually set
                    current_ip = self.ip_entry.get().strip()
                    if iface["ip"] != "N/A" and (not current_ip or current_ip == "192.168.1.100"):
                        self.ip_entry.delete(0, tk.END)
                        # Use the same network but different host part
                        ip_parts = iface["ip"].split('.')
                        if len(ip_parts) == 4:
                            new_ip = f"{ip_parts[0]}.{ip_parts[1]}.{ip_parts[2]}.100"
                            self.ip_entry.insert(0, new_ip)

                    # Auto-fill other fields if they are empty
                    if iface["subnet"] != "N/A" and not self.subnet_entry.get().strip():
                        self.subnet_entry.delete(0, tk.END)
                        self.subnet_entry.insert(0, iface["subnet"])

                    if iface["gateway"] != "N/A" and not self.gateway_entry.get().strip():
                        self.gateway_entry.delete(0, tk.END)
                        self.gateway_entry.insert(0, iface["gateway"])

                    if iface["dns"] != "N/A" and not self.dns_entry.get().strip():
                        self.dns_entry.delete(0, tk.END)
                        self.dns_entry.insert(0, iface["dns"])

                    break
        else:
            self.interface_details_label.config(text="Select an interface to view details")
            self.current_config_label.config(text="Select an interface to view current configuration")

    def setup_auto_generation(self):
        # Auto-generation setup for connections tab
        pass

    def setup_auth_tab(self):
        """Authentication tab"""
        frame = ttk.LabelFrame(self.auth_frame, text="Root Authentication", padding="15")
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        ttk.Label(frame, text="Enter root password to configure system:").pack(pady=10)

        ttk.Label(frame, text="Root Password:").pack(pady=5)
        self.password_entry = ttk.Entry(frame, show="•", width=30)
        self.password_entry.pack(pady=5)
        self.password_entry.bind('<Return>', self.authenticate)
        self.password_entry.focus_set()

        ttk.Button(frame, text="Authenticate", command=self.authenticate).pack(pady=10)

        self.auth_status = ttk.Label(frame, text="Not authenticated", foreground="red")
        self.auth_status.pack(pady=5)

        help_text = """Note: You need root privileges to configure system settings.
        Enter the root password to continue."""
        ttk.Label(frame, text=help_text, foreground="gray", font=('Arial', 9)).pack(pady=10)

    def toggle_static_fields(self):
        """Enable or disable static IP configuration fields based on configuration type"""
        if self.config_type.get() == "static":
            # Enable all static IP fields
            self.ip_entry.config(state="normal")
            self.subnet_entry.config(state="normal")
            self.gateway_entry.config(state="normal")
            self.dns_entry.config(state="normal")
        else:
            # Disable all static IP fields for DHCP
            self.ip_entry.config(state="disabled")
            self.subnet_entry.config(state="disabled")
            self.gateway_entry.config(state="disabled")
            self.dns_entry.config(state="disabled")

    def setup_network_tab(self):
        # Network configuration tab
        frame = ttk.LabelFrame(self.network_frame, text="Network Configuration", padding="15")
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Interface selection with refresh button
        interface_frame = ttk.Frame(frame)
        interface_frame.grid(row=0, column=0, columnspan=3, sticky=tk.W + tk.E, pady=10)

        ttk.Label(interface_frame, text="Network Interface:", font=('Arial', 9, 'bold')).pack(side=tk.LEFT,
                                                                                              padx=(0, 10))

        self.interface_var = tk.StringVar()
        self.interface_combo = ttk.Combobox(interface_frame, textvariable=self.interface_var, width=15,
                                            state="readonly")
        self.interface_combo.pack(side=tk.LEFT, padx=(0, 10))
        self.interface_combo.bind('<<ComboboxSelected>>', lambda e: self.update_interface_details())

        ttk.Button(interface_frame, text="Refresh", command=self.refresh_interfaces, width=8).pack(side=tk.LEFT,
                                                                                                   padx=(0, 10))

        # Interface details
        self.interface_details_label = ttk.Label(interface_frame, text="Click Refresh to detect interfaces",
                                                 foreground="green")
        self.interface_details_label.pack(side=tk.LEFT)

        # Current configuration display
        self.current_config_label = ttk.Label(frame, text="Select an interface to view current configuration",
                                              justify=tk.LEFT, background='#f5f5f5', relief=tk.SUNKEN, padding=5)
        self.current_config_label.grid(row=1, column=0, columnspan=3, sticky=tk.W + tk.E, pady=10, padx=5)

        # IP Address
        ttk.Label(frame, text="IP Address:").grid(row=2, column=0, sticky=tk.W, pady=5)
        self.ip_entry = ttk.Entry(frame, width=20)
        self.ip_entry.grid(row=2, column=1, sticky=tk.W, pady=5, padx=5)
        self.ip_entry.insert(0, "192.168.1.100")

        # Subnet Mask
        ttk.Label(frame, text="Subnet Mask:").grid(row=3, column=0, sticky=tk.W, pady=5)
        self.subnet_entry = ttk.Entry(frame, width=20)
        self.subnet_entry.grid(row=3, column=1, sticky=tk.W, pady=5, padx=5)
        self.subnet_entry.insert(0, "255.255.255.0")

        # Gateway
        ttk.Label(frame, text="Gateway:").grid(row=4, column=0, sticky=tk.W, pady=5)
        self.gateway_entry = ttk.Entry(frame, width=20)
        self.gateway_entry.grid(row=4, column=1, sticky=tk.W, pady=5, padx=5)
        self.gateway_entry.insert(0, "192.168.1.1")

        # DNS
        ttk.Label(frame, text="DNS Servers:").grid(row=5, column=0, sticky=tk.W, pady=5)
        self.dns_entry = ttk.Entry(frame, width=20)
        self.dns_entry.grid(row=5, column=1, sticky=tk.W, pady=5, padx=5)
        self.dns_entry.insert(0, "8.8.8.8,8.8.4.4")

        # Configuration type
        ttk.Label(frame, text="Configuration Type:").grid(row=6, column=0, sticky=tk.W, pady=5)
        self.config_type = tk.StringVar(value="static")

        # Create radio buttons and bind the toggle function
        static_rb = ttk.Radiobutton(frame, text="Static IP", variable=self.config_type, value="static",
                                    command=self.toggle_static_fields)
        static_rb.grid(row=6, column=1, sticky=tk.W, padx=5)

        dhcp_rb = ttk.Radiobutton(frame, text="DHCP", variable=self.config_type, value="dhcp",
                                  command=self.toggle_static_fields)
        dhcp_rb.grid(row=6, column=1, sticky=tk.W, padx=80)

        # Buttons
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=7, column=0, columnspan=3, pady=15)

        ttk.Button(button_frame, text="Apply Changes", command=self.configure_network).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Detect Interfaces", command=self.refresh_interfaces).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Test Connection", command=self.test_network).pack(side=tk.LEFT, padx=5)

        self.network_status = ttk.Label(frame, text="Click 'Detect Interfaces' to find available network interfaces")
        self.network_status.grid(row=8, column=0, columnspan=3)

        # Configure grid weights
        frame.columnconfigure(1, weight=1)

        # Initial interface detection
        self.refresh_interfaces()

    def test_network(self):
        """Test network connectivity"""
        try:
            # Test internet connectivity
            result = subprocess.run(['ping', '-c', '3', '8.8.8.8'], capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                messagebox.showinfo("Network Test", "Network connectivity test successful!")
            else:
                messagebox.showwarning("Network Test", "Network connectivity test failed. Check your configuration.")
        except Exception as e:
            messagebox.showerror("Network Test", f"Network test error: {str(e)}")

    def setup_connections_tab(self):
        """Connections tab for RDP, SPICE, and VNC connections"""
        frame = ttk.LabelFrame(self.connections_frame, text="Remote Connections", padding="15")
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Connections list
        list_frame = ttk.LabelFrame(frame, text="Available Connections", padding="10")
        list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # Create treeview for connections with adjusted column widths
        columns = ("Name", "Type", "Address", "Status")
        self.connections_tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=8)

        # Define headings
        self.connections_tree.heading("Name", text="Connection Name")
        self.connections_tree.heading("Type", text="Type")
        self.connections_tree.heading("Address", text="Server Address")
        self.connections_tree.heading("Status", text="Status")

        # Set column widths - adjusted for better spacing
        self.connections_tree.column("Name", width=180, minwidth=150)
        self.connections_tree.column("Type", width=80, minwidth=70)
        self.connections_tree.column("Address", width=150, minwidth=120)
        self.connections_tree.column("Status", width=120, minwidth=100)  # Increased width for status

        # Add scrollbar
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.connections_tree.yview)
        self.connections_tree.configure(yscrollcommand=scrollbar.set)

        # Pack treeview and scrollbar
        self.connections_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # Button frame
        button_frame = ttk.Frame(frame)
        button_frame.pack(fill=tk.X, padx=5, pady=10)

        ttk.Button(button_frame, text="Create New Connection",
                   command=self.create_connection_dialog).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Edit Selected",
                   command=self.edit_connection).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Delete Selected",
                   command=self.delete_connection).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Refresh List",
                   command=self.refresh_connections_list).pack(side=tk.LEFT, padx=5)

        # Status label
        self.connections_status = ttk.Label(frame, text="")
        self.connections_status.pack(pady=5)

        # Load initial connections
        self.refresh_connections_list()

    def refresh_connections_list(self):
        """Refresh the list of available connections with accurate information"""
        # Clear existing items
        for item in self.connections_tree.get_children():
            self.connections_tree.delete(item)

        # Check which connection has autostart enabled
        autostart_connection = self.get_autostart_connection()

        # Check for RDP connection and parse details
        if os.path.exists('/usr/local/bin/.rdpcon.desktop'):
            details = self.parse_existing_connection('RDP')
            if details:
                conn_name = details.get('display_name', 'RDP Remote Connection')
                address = details.get('address', 'Unknown')
                has_autostart = (autostart_connection == conn_name)
                status = "Configured" + (" + Autostart" if has_autostart else "")
                self.connections_tree.insert("", "end", values=(conn_name, "RDP", address, status))

        # Check for SPICE connection and parse details
        if os.path.exists('/usr/local/bin/.spicecon.desktop'):
            details = self.parse_existing_connection('SPICE')
            if details:
                conn_name = details.get('display_name', 'Spice Remote Viewer')
                address = details.get('address', 'Unknown')
                port = details.get('port', 'Unknown')
                server_display = f"{address}:{port}" if address != 'Unknown' and port != 'Unknown' else address
                has_autostart = (autostart_connection == conn_name)
                status = "Configured" + (" + Autostart" if has_autostart else "")
                self.connections_tree.insert("", "end", values=(conn_name, "SPICE", server_display, status))

        # Check for VNC connection and parse details
        if os.path.exists('/usr/local/bin/.vnccon.desktop'):
            details = self.parse_existing_connection('VNC')
            if details:
                conn_name = details.get('display_name', 'VNC Remote Viewer')
                address = details.get('address', 'Unknown')
                port = details.get('port', 'Unknown')
                server_display = f"{address}:{port}" if address != 'Unknown' and port != 'Unknown' else address
                has_autostart = (autostart_connection == conn_name)
                status = "Configured" + (" + Autostart" if has_autostart else "")
                self.connections_tree.insert("", "end", values=(conn_name, "VNC", server_display, status))

        # Check for NoMachine connection and parse details
        if os.path.exists('/usr/local/bin/.nomachinecon.desktop'):
            details = self.parse_existing_connection('NOMACHINE')  # Use internal type
            if details:
                conn_name = details.get('display_name', 'NoMachine Connection')
                address = details.get('address', 'Unknown')
                port = details.get('port', 'Unknown')
                server_display = f"{address}:{port}" if address != 'Unknown' and port != 'Unknown' else address
                has_autostart = (autostart_connection == conn_name)
                status = "Configured" + (" + Autostart" if has_autostart else "")
                self.connections_tree.insert("", "end", values=(conn_name, "NoMachine", server_display, status))

        if not self.connections_tree.get_children():
            self.connections_tree.insert("", "end", values=("No connections configured", "", "", ""))

    def create_connection_dialog(self, conn_type=None, existing_details=None, conn_name=None):
        """Dialog to create or edit a connection"""
        is_edit = existing_details is not None

        # Store existing details as instance variable for use in populate_existing_data
        self.existing_details = existing_details

        dialog = tk.Toplevel(self.root)
        dialog.title("Edit Connection" if is_edit else "Create New Connection")
        dialog.geometry("450x550")
        dialog.transient(self.root)
        dialog.grab_set()

        # Make dialog resizable
        dialog.minsize(450, 550)

        # Connection type - DROPDOWN
        ttk.Label(dialog, text="Connection Type:", font=('Arial', 10, 'bold')).pack(pady=10)

        type_frame = ttk.Frame(dialog)
        type_frame.pack(pady=5, fill=tk.X, padx=20)

        self.conn_type = tk.StringVar(value=conn_type if conn_type else "RDP")

        # Create dropdown - added NoMachine
        conn_types = ["RDP", "SPICE", "VNC", "NoMachine"]
        type_combo = ttk.Combobox(type_frame, textvariable=self.conn_type, values=conn_types, state="readonly",
                                  width=15)
        type_combo.pack(pady=5)

        # Disable type selection when editing
        if is_edit:
            type_combo.config(state="disabled")

        # Connection details frame
        details_frame = ttk.LabelFrame(dialog, text="Connection Details", padding="10")
        details_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        # Connection Name (always show for both new and edit)
        ttk.Label(details_frame, text="Connection Name:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.conn_name_var = tk.StringVar(value=conn_name if conn_name else "")
        conn_name_entry = ttk.Entry(details_frame, textvariable=self.conn_name_var, width=25)
        conn_name_entry.grid(row=0, column=1, sticky=tk.W + tk.E, pady=5, padx=5)

        start_row = 1

        # Desktop Icon checkbox
        self.create_desktop_icon = tk.BooleanVar(value=True)
        self.desktop_icon_check = ttk.Checkbutton(details_frame, text="Create Desktop Icon",
                                                  variable=self.create_desktop_icon)

        # Autostart checkbox
        self.autostart_var = tk.BooleanVar(value=False)
        self.autostart_check = ttk.Checkbutton(details_frame, text="Enable Autostart",
                                               variable=self.autostart_var)

        # Update fields based on connection type and edit mode
        def update_fields(*args):
            current_type = self.conn_type.get()
            is_spice_edit = is_edit and current_type == "SPICE"

            # Set default connection name based on protocol for new connections
            if not is_edit:
                if current_type == "RDP":
                    self.conn_name_var.set("RDP Connection")
                elif current_type == "SPICE":
                    self.conn_name_var.set("SPICE Connection")
                elif current_type == "VNC":
                    self.conn_name_var.set("VNC Connection")
                elif current_type == "NoMachine":
                    self.conn_name_var.set("NoMachine Connection")


            if current_type == "RDP":
                # Show all fields for RDP
                self.conn_user_label.grid(row=start_row, column=0, sticky=tk.W, pady=5)
                self.conn_user.grid(row=start_row, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_pass_label.grid(row=start_row + 1, column=0, sticky=tk.W, pady=5)
                self.conn_pass.grid(row=start_row + 1, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_addr_label.grid(row=start_row + 2, column=0, sticky=tk.W, pady=5)
                self.conn_addr.grid(row=start_row + 2, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_extra_label.config(text="Domain:")
                self.conn_extra_label.grid(row=start_row + 3, column=0, sticky=tk.W, pady=5)
                self.conn_extra.grid(row=start_row + 3, column=1, sticky=tk.W + tk.E, pady=5, padx=5)

                if not is_edit:  # Only set default if not editing
                    self.conn_extra.delete(0, tk.END)
                    self.conn_extra.insert(0, "WORKGROUP")

            elif current_type == "SPICE":
                # Hide username field for SPICE
                self.conn_user_label.grid_remove()
                self.conn_user.grid_remove()

                # For SPICE editing, hide password field; for new SPICE, show it
                if is_spice_edit:
                    # Editing existing SPICE - hide password field
                    self.conn_pass_label.grid_remove()
                    self.conn_pass.grid_remove()

                    # Show only address and port
                    self.conn_addr_label.grid(row=start_row, column=0, sticky=tk.W, pady=5)
                    self.conn_addr.grid(row=start_row, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                    self.conn_extra_label.config(text="Port:")
                    self.conn_extra_label.grid(row=start_row + 1, column=0, sticky=tk.W, pady=5)
                    self.conn_extra.grid(row=start_row + 1, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                else:
                    # New SPICE connection - show password field
                    self.conn_pass_label.grid(row=start_row, column=0, sticky=tk.W, pady=5)
                    self.conn_pass.grid(row=start_row, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                    self.conn_addr_label.grid(row=start_row + 1, column=0, sticky=tk.W, pady=5)
                    self.conn_addr.grid(row=start_row + 1, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                    self.conn_extra_label.config(text="Port:")
                    self.conn_extra_label.grid(row=start_row + 2, column=0, sticky=tk.W, pady=5)
                    self.conn_extra.grid(row=start_row + 2, column=1, sticky=tk.W + tk.E, pady=5, padx=5)

                if not is_edit:  # Only set default if not editing
                    self.conn_extra.delete(0, tk.END)
                    self.conn_extra.insert(0, "5901")

            elif current_type == "NoMachine":
                # Show all fields for NoMachine
                self.conn_user_label.grid(row=start_row, column=0, sticky=tk.W, pady=5)
                self.conn_user.grid(row=start_row, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_pass_label.grid(row=start_row + 1, column=0, sticky=tk.W, pady=5)
                self.conn_pass.grid(row=start_row + 1, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_addr_label.grid(row=start_row + 2, column=0, sticky=tk.W, pady=5)
                self.conn_addr.grid(row=start_row + 2, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_extra_label.config(text="Port:")
                self.conn_extra_label.grid(row=start_row + 3, column=0, sticky=tk.W, pady=5)
                self.conn_extra.grid(row=start_row + 3, column=1, sticky=tk.W + tk.E, pady=5, padx=5)

                # Add window size field for NoMachine
                self.conn_window_size_label = ttk.Label(details_frame, text="Window Size:")
                self.conn_window_size_label.grid(row=start_row + 4, column=0, sticky=tk.W, pady=5)
                self.conn_window_size = ttk.Combobox(details_frame,
                                                     values=["normal", "fullscreen", "1024x768", "1280x720",
                                                             "1920x1080"], width=23)
                self.conn_window_size.grid(row=start_row + 4, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_window_size.set("normal")

                if not is_edit:
                    self.conn_extra.delete(0, tk.END)
                    self.conn_extra.insert(0, "4000")

            elif current_type == "VNC":
                # Show all fields for VNC
                self.conn_user_label.grid(row=start_row, column=0, sticky=tk.W, pady=5)
                self.conn_user.grid(row=start_row, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_pass_label.grid(row=start_row + 1, column=0, sticky=tk.W, pady=5)
                self.conn_pass.grid(row=start_row + 1, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_addr_label.grid(row=start_row + 2, column=0, sticky=tk.W, pady=5)
                self.conn_addr.grid(row=start_row + 2, column=1, sticky=tk.W + tk.E, pady=5, padx=5)
                self.conn_extra_label.config(text="Port:")
                self.conn_extra_label.grid(row=start_row + 3, column=0, sticky=tk.W, pady=5)
                self.conn_extra.grid(row=start_row + 3, column=1, sticky=tk.W + tk.E, pady=5, padx=5)

                if not is_edit:  # Only set default if not editing
                    self.conn_extra.delete(0, tk.END)
                    self.conn_extra.insert(0, "5900")

            # Position the checkboxes at the bottom of the form
            if current_type == "RDP":
                desktop_icon_row = start_row + 4
            elif current_type == "SPICE":
                desktop_icon_row = start_row + 2 if is_spice_edit else start_row + 3
            elif current_type == "NoMachine":
                desktop_icon_row = start_row + 5
            else:  # VNC
                desktop_icon_row = start_row + 4

            self.desktop_icon_check.grid(row=desktop_icon_row, column=0, columnspan=2, sticky=tk.W, pady=5)
            self.autostart_check.grid(row=desktop_icon_row + 1, column=0, columnspan=2, sticky=tk.W, pady=5)

        # Create all fields but only show based on connection type
        self.conn_user_label = ttk.Label(details_frame, text="Username:")
        self.conn_user = ttk.Entry(details_frame, width=25)

        self.conn_pass_label = ttk.Label(details_frame, text="Password:")
        self.conn_pass = ttk.Entry(details_frame, show="•", width=25)

        self.conn_addr_label = ttk.Label(details_frame, text="Server Address:")
        self.conn_addr = ttk.Entry(details_frame, width=25)

        self.conn_extra_label = ttk.Label(details_frame, text="Domain:")
        self.conn_extra = ttk.Entry(details_frame, width=25)

        # Configure grid weights for details frame to make entries expand
        details_frame.columnconfigure(1, weight=1)

        # Populate fields with existing data if editing
        def populate_existing_data_wrapper():
            if existing_details:
                # Set connection name from existing details - this preserves the original name
                if 'display_name' in existing_details:
                    self.conn_name_var.set(existing_details['display_name'])
                elif conn_name:  # Fallback to the conn_name parameter
                    self.conn_name_var.set(conn_name)

                # Populate fields based on connection type
                current_type = self.conn_type.get()

                if current_type == "RDP":
                    if 'username' in existing_details:
                        self.conn_user.delete(0, tk.END)
                        self.conn_user.insert(0, existing_details['username'])
                    if 'password' in existing_details:
                        self.conn_pass.delete(0, tk.END)
                        self.conn_pass.insert(0, existing_details['password'])
                    if 'address' in existing_details:
                        self.conn_addr.delete(0, tk.END)
                        self.conn_addr.insert(0, existing_details['address'])
                    if 'domain' in existing_details:
                        self.conn_extra.delete(0, tk.END)
                        self.conn_extra.insert(0, existing_details['domain'])

                elif current_type == "SPICE":
                    if 'address' in existing_details:
                        self.conn_addr.delete(0, tk.END)
                        self.conn_addr.insert(0, existing_details['address'])
                    if 'port' in existing_details:
                        self.conn_extra.delete(0, tk.END)
                        self.conn_extra.insert(0, existing_details['port'])

                elif current_type == "VNC":
                    if 'username' in existing_details:
                        self.conn_user.delete(0, tk.END)
                        self.conn_user.insert(0, existing_details['username'])
                    if 'password' in existing_details:
                        self.conn_pass.delete(0, tk.END)
                        self.conn_pass.insert(0, existing_details['password'])
                    if 'address' in existing_details:
                        self.conn_addr.delete(0, tk.END)
                        self.conn_addr.insert(0, existing_details['address'])
                    if 'port' in existing_details:
                        self.conn_extra.delete(0, tk.END)
                        self.conn_extra.insert(0, existing_details['port'])

                elif current_type == "NoMachine":
                    print(f"Populating NoMachine fields with: {existing_details}")  # Debug
                    if 'username' in existing_details and existing_details['username'] != 'Unknown':
                        self.conn_user.delete(0, tk.END)
                        self.conn_user.insert(0, existing_details['username'])
                    if 'password' in existing_details:
                        self.conn_pass.delete(0, tk.END)
                        self.conn_pass.insert(0, existing_details['password'])
                    if 'address' in existing_details and existing_details['address'] != 'Unknown':
                        self.conn_addr.delete(0, tk.END)
                        self.conn_addr.insert(0, existing_details['address'])
                    if 'port' in existing_details:
                        self.conn_extra.delete(0, tk.END)
                        self.conn_extra.insert(0, existing_details['port'])
                    if 'window_size' in existing_details:
                        self.conn_window_size.set(existing_details['window_size'])
                    else:
                        self.conn_window_size.set("normal")

                # Set desktop icon checkbox based on stored preference
                if 'desktop_icon' in existing_details:
                    self.create_desktop_icon.set(existing_details['desktop_icon'])
                    print(f"Setting desktop icon checkbox to: {existing_details['desktop_icon']}")  # Debug
                else:
                    # Fallback: check if desktop icon actually exists
                    desktop_path = self.get_desktop_path_by_type(current_type)
                    if current_type == "NoMachine":
                        desktop_path = os.path.expanduser("~/Desktop/NoMachineconnection.desktop")
                    desktop_icon_exists = os.path.exists(desktop_path)
                    self.create_desktop_icon.set(desktop_icon_exists)
                    print(f"DEBUG: Fallback - desktop icon exists: {desktop_icon_exists} at {desktop_path}")

                # Set autostart checkbox - check if this connection has autostart enabled
                autostart_connection = self.get_autostart_connection()
                current_display_name = self.conn_name_var.get()
                if autostart_connection and autostart_connection == current_display_name:
                    self.autostart_var.set(True)
                else:
                    self.autostart_var.set(False)
            else:
                # For new connections, set default connection name based on initial type
                current_type = self.conn_type.get()
                if current_type == "RDP":
                    self.conn_name_var.set("RDP Connection")
                elif current_type == "SPICE":
                    self.conn_name_var.set("SPICE Connection")
                elif current_type == "VNC":
                    self.conn_name_var.set("VNC Connection")
                elif current_type == "NoMachine":
                    self.conn_name_var.set("NoMachine Connection")

        self.conn_type.trace('w', update_fields)
        update_fields()  # Initial call
        populate_existing_data_wrapper()  # Populate existing data if editing

        # BUTTONS FRAME
        button_frame = ttk.Frame(dialog)
        button_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=20, pady=15)

        button_subframe = ttk.Frame(button_frame)
        button_subframe.pack(expand=True)

        ttk.Button(button_subframe, text="Save" if is_edit else "Create",
                   command=lambda: self.save_connection(dialog, is_edit)).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_subframe, text="Cancel",
                   command=dialog.destroy).pack(side=tk.LEFT, padx=10)


    def save_connection(self, dialog, is_edit):
        """Save connection (both create and edit)"""
        conn_type = self.conn_type.get()
        conn_name = self.conn_name_var.get().strip()
        username = self.conn_user.get().strip()
        password = self.conn_pass.get().strip()
        address = self.conn_addr.get().strip()
        extra = self.conn_extra.get().strip()
        create_desktop_icon = self.create_desktop_icon.get()
        enable_autostart = self.autostart_var.get()
        # For NoMachine, get window_size
        window_size = "normal"
        if conn_type == "NoMachine":
            window_size = self.conn_window_size.get().strip()

        # Validate fields
        if not conn_name:
            messagebox.showerror("Error", "Please enter a connection name")
            return

        # Validate fields based on connection type and edit mode
        is_spice_edit = is_edit and conn_type == "SPICE"

        if conn_type == "RDP":
            if not all([username, password, address, extra]):
                messagebox.showerror("Error", "Please fill in all fields for RDP connection")
                return
        elif conn_type == "SPICE":
            # For SPICE editing, only validate address and port (password is hidden)
            if is_spice_edit:
                if not all([address, extra]):
                    messagebox.showerror("Error", "Please fill in server address and port for SPICE connection")
                    return
                # Keep existing password when editing SPICE
                password = ""  # Will be handled by the existing connection data
            else:
                # New SPICE connection - validate all fields
                if not all([password, address, extra]):
                    messagebox.showerror("Error",
                                         "Please fill in password, server address, and port for SPICE connection")
                    return
            username = ""  # SPICE doesn't use username

        elif conn_type == "NoMachine":
            if not all([username, password, address, extra]):
                messagebox.showerror("Error", "Please fill in all fields for NoMachine connection")
                return

        elif conn_type == "VNC":
            if not all([username, password, address, extra]):
                messagebox.showerror("Error", "Please fill in all fields for VNC connection")
                return

        # Check if autostart is already enabled for another connection (only if we're enabling it)
        if enable_autostart:
            autostart_connection = self.get_autostart_connection()
            # Only show error if autostart is enabled for a DIFFERENT connection
            if autostart_connection and autostart_connection != conn_name:
                messagebox.showerror("Autostart Error",
                                     f"Cannot enable autostart for '{conn_name}'.\n"
                                     f"Autostart is already enabled for '{autostart_connection}'.\n\n"
                                     "Please disable autostart for the existing connection first.")
                return

        try:
            # If enabling autostart, disable autostart for all other connections first
            if enable_autostart:
                self.disable_all_autostart()

            # For edit mode, delete the old connection first
            if is_edit:
                # Remove existing desktop icon if it exists and user doesn't want it
                desktop_path = self.get_desktop_path_by_type(conn_type)
                if os.path.exists(desktop_path) and not create_desktop_icon:
                    subprocess.run(['rm', '-f', desktop_path], timeout=10)

                # Remove existing autostart if it exists and user doesn't want it
                if not enable_autostart:
                    # Only disable autostart if this specific connection had it
                    current_autostart = self.get_autostart_connection()
                    if current_autostart == conn_name:
                        self.disable_all_autostart()

                if conn_type == "RDP":
                    self.delete_connection_files('/usr/local/bin/.rdpcon.desktop')
                elif conn_type == "SPICE":
                    self.delete_connection_files('/usr/local/bin/.spicecon.desktop')
                elif conn_type == "VNC":
                    self.delete_connection_files('/usr/local/bin/.vnccon.desktop')
                elif conn_type == "NoMachine":
                    self.delete_connection_files('/usr/local/bin/.nomachinecon.desktop')

            # Create the new connection
            if conn_type == "RDP":
                self.create_rdp_connection(username, password, address, extra, create_desktop_icon, conn_name,
                                           enable_autostart)
            elif conn_type == "SPICE":
                # For SPICE editing, we need to preserve the existing password
                if is_spice_edit and not password:
                    # Get the existing password from the original connection
                    existing_details = self.parse_existing_connection('SPICE')
                    if existing_details and 'password' in existing_details:
                        password = existing_details['password']
                self.create_spice_connection(password, address, extra, create_desktop_icon, conn_name, enable_autostart)
            elif conn_type == "NoMachine":
                self.create_nomachine_connection(username, password, address, extra, window_size, create_desktop_icon,
                                                 conn_name, enable_autostart)
            elif conn_type == "VNC":
                self.create_vnc_connection(username, password, address, extra, create_desktop_icon, conn_name,
                                           enable_autostart)

            messagebox.showinfo("Success", f"{conn_type} connection {'updated' if is_edit else 'created'} successfully")
            dialog.destroy()
            self.refresh_connections_list()

        except Exception as e:
            messagebox.showerror("Error", f"Failed to {'update' if is_edit else 'create'} connection: {str(e)}")

    def get_desktop_path_by_type(self, conn_type):
        """Get the correct desktop file path based on connection type"""
        if conn_type == "RDP":
            return os.path.expanduser("~/Desktop/RDPconnection.desktop")
        elif conn_type == "SPICE":
            return os.path.expanduser("~/Desktop/SPICEconnection.desktop")
        elif conn_type == "VNC":
            return os.path.expanduser("~/Desktop/VNCconnection.desktop")
        elif conn_type == "NoMachine":
            return os.path.expanduser("~/Desktop/NoMachineconnection.desktop")
        else:
            return os.path.expanduser("~/Desktop/RDPconnection.desktop")

    def get_autostart_connection(self):
        """Check if autostart is enabled and return the connection name"""
        try:
            autostart_path = self.get_autostart_path()
            if not os.path.exists(autostart_path):
                return None

            # Read the autostart file to get the connection name
            with open(autostart_path, 'r') as f:
                content = f.read()

            # Parse the connection name from the autostart file
            name_match = re.search(r'Name=(.+)', content)
            if name_match:
                return name_match.group(1).strip()

            return "Unknown Connection"
        except Exception as e:
            print(f"Error reading autostart file: {e}")
            return None

    def get_autostart_path(self):
        """Get the autostart directory path"""
        autostart_dir = os.path.expanduser("~/.config/autostart")
        # Create directory if it doesn't exist
        os.makedirs(autostart_dir, exist_ok=True)
        return os.path.join(autostart_dir, "remote-connection.desktop")

    def disable_all_autostart(self):
        """Disable autostart for all connections"""
        try:
            autostart_path = self.get_autostart_path()
            if os.path.exists(autostart_path):
                subprocess.run(['rm', '-f', autostart_path], timeout=10)
        except Exception as e:
            print(f"Warning: Could not disable autostart: {e}")

    def create_rdp_connection(self, username, password, address, domain, create_desktop_icon=True, conn_name=None,
                              enable_autostart=False):
        """Create RDP connection with optional desktop icon and autostart"""
        # Define paths with unique names for RDP
        rdplauncher = "/usr/local/bin/.rdpcon.desktop"
        desktop_launcher = os.path.expanduser("~/Desktop/RDPconnection.desktop")
        autostart_launcher = self.get_autostart_path()

        # Use provided connection name or default
        display_name = conn_name if conn_name else "RDP Connection"

        # DEFINE EXEC COMMAND FOR RDP
        exec_command = f"xfreerdp3 /d:{domain} /u:{username} /p:{password} /v:{address} /cert:ignore /bpp:32 /rfx /network:auto /compression /f"

        # Create launcher content
        launcher_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    """

        # Save files using sudo
        if self.password is None:
            raise PermissionError("Authentication required")

        # Save launcher to /usr/local/bin/
        import tempfile
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
            tmp.write(launcher_content)
            tmp_path = tmp.name

        cmd = ['sudo', '-S', 'mv', tmp_path, rdplauncher]
        result = subprocess.run(cmd, input=f"{self.password}\n",
                                capture_output=True, text=True, timeout=10)
        if result.returncode != 0:
            raise Exception(f"Failed to save RDP launcher: {result.stderr}")

        # Set permissions
        cmd = ['sudo', '-S', 'chmod', '755', rdplauncher]
        subprocess.run(cmd, input=f"{self.password}\n",
                       capture_output=True, text=True, timeout=10)

        # Create desktop icon if requested
        if create_desktop_icon:
            try:
                # Use the same display name for desktop icon
                desktop_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    """
                with open(desktop_launcher, 'w') as f:
                    f.write(desktop_content)
                subprocess.run(['chmod', '755', desktop_launcher], timeout=10)
            except Exception as e:
                print(f"Warning: Could not create desktop icon: {e}")

        # Create autostart if requested
        if enable_autostart:
            try:
                # Create autostart file with proper content
                autostart_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    X-GNOME-Autostart-enabled=true
    """
                with open(autostart_launcher, 'w') as f:
                    f.write(autostart_content)
                subprocess.run(['chmod', '755', autostart_launcher], timeout=10)
                print(f"Autostart enabled for: {display_name}")
            except Exception as e:
                print(f"Warning: Could not create autostart: {e}")
                raise Exception(f"Failed to enable autostart: {str(e)}")

    def create_spice_connection(self, password, address, port, create_desktop_icon=True, conn_name=None,
                                enable_autostart=False):
        """Create SPICE connection with optional desktop icon and autostart"""
        # Define paths with unique names for SPICE
        spicelauncher = "/usr/local/bin/.spicecon.desktop"
        desktop_launcher = os.path.expanduser("~/Desktop/SPICEconnection.desktop")  # Changed to SPICEconnection.desktop
        autostart_launcher = self.get_autostart_path()

        # Use provided connection name or default
        display_name = conn_name if conn_name else "SPICE Connection"

        # DEFINE EXEC COMMAND FOR SPICE
        exec_command = f"remote-viewer spice://{address}:{port} -f"

        # Create launcher content
        launcher_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    """

        # Save files using sudo
        if self.password is None:
            raise PermissionError("Authentication required")

        # Save launcher to /usr/local/bin/
        import tempfile
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
            tmp.write(launcher_content)
            tmp_path = tmp.name

        cmd = ['sudo', '-S', 'mv', tmp_path, spicelauncher]
        result = subprocess.run(cmd, input=f"{self.password}\n",
                                capture_output=True, text=True, timeout=10)
        if result.returncode != 0:
            raise Exception(f"Failed to save SPICE launcher: {result.stderr}")

        # Set permissions
        cmd = ['sudo', '-S', 'chmod', '755', spicelauncher]
        subprocess.run(cmd, input=f"{self.password}\n",
                       capture_output=True, text=True, timeout=10)

        # Create desktop icon if requested
        if create_desktop_icon:
            try:
                # Use the same display name for desktop icon
                desktop_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    """
                with open(desktop_launcher, 'w') as f:
                    f.write(desktop_content)
                subprocess.run(['chmod', '755', desktop_launcher], timeout=10)
            except Exception as e:
                print(f"Warning: Could not create desktop icon: {e}")

        # Create autostart if requested
        if enable_autostart:
            try:
                # Create autostart file with proper content
                autostart_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    X-GNOME-Autostart-enabled=true
    """
                with open(autostart_launcher, 'w') as f:
                    f.write(autostart_content)
                subprocess.run(['chmod', '755', autostart_launcher], timeout=10)
                print(f"Autostart enabled for: {display_name}")
            except Exception as e:
                print(f"Warning: Could not create autostart: {e}")
                raise Exception(f"Failed to enable autostart: {str(e)}")

    def create_vnc_connection(self, username, password, address, port, create_desktop_icon=True, conn_name=None,
                              enable_autostart=False):
        """Create VNC connection with optional desktop icon and autostart"""
        # Define paths with unique names for VNC
        vnclauncher = "/usr/local/bin/.vnccon.desktop"
        desktop_launcher = os.path.expanduser("~/Desktop/VNCconnection.desktop")
        autostart_launcher = self.get_autostart_path()

        # Use provided connection name or default
        display_name = conn_name if conn_name else "VNC Connection"

        # DEFINE EXEC COMMAND FOR VNC - include username and password in URL if provided
        if username and password:
            exec_command = f"remote-viewer vnc://{username}:{password}@{address}:{port} -f"
        else:
            exec_command = f"remote-viewer vnc://{address}:{port} -f"

        # Create launcher content
        launcher_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    """

        # Save files using sudo
        if self.password is None:
            raise PermissionError("Authentication required")

        # Save launcher to /usr/local/bin/
        import tempfile
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
            tmp.write(launcher_content)
            tmp_path = tmp.name

        cmd = ['sudo', '-S', 'mv', tmp_path, vnclauncher]
        result = subprocess.run(cmd, input=f"{self.password}\n",
                                capture_output=True, text=True, timeout=10)
        if result.returncode != 0:
            raise Exception(f"Failed to save VNC launcher: {result.stderr}")

        # Set permissions
        cmd = ['sudo', '-S', 'chmod', '755', vnclauncher]
        subprocess.run(cmd, input=f"{self.password}\n",
                       capture_output=True, text=True, timeout=10)

        # Create desktop icon if requested
        if create_desktop_icon:
            try:
                # Use the same display name for desktop icon
                desktop_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    """
                with open(desktop_launcher, 'w') as f:
                    f.write(desktop_content)
                subprocess.run(['chmod', '755', desktop_launcher], timeout=10)
            except Exception as e:
                print(f"Warning: Could not create desktop icon: {e}")

        # Create autostart if requested
        if enable_autostart:
            try:
                # Create autostart file with proper content
                autostart_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=virt-viewer
    Exec={exec_command}
    X-GNOME-Autostart-enabled=true
    """
                with open(autostart_launcher, 'w') as f:
                    f.write(autostart_content)
                subprocess.run(['chmod', '755', autostart_launcher], timeout=10)
                print(f"Autostart enabled for: {display_name}")
            except Exception as e:
                print(f"Warning: Could not create autostart: {e}")
                raise Exception(f"Failed to enable autostart: {str(e)}")

    def create_nomachine_connection(self, username, password, address, port, window_size="normal",
                                    create_desktop_icon=True, conn_name=None,
                                    enable_autostart=False):
        """Create NoMachine connection with optional desktop icon and autostart"""
        # Define paths with unique names for NoMachine
        nomachinelauncher = "/usr/local/bin/.nomachinecon.desktop"
        desktop_launcher = os.path.expanduser("~/Desktop/NoMachineconnection.desktop")
        autostart_launcher = self.get_autostart_path()

        # Use provided connection name or default
        display_name = conn_name if conn_name else "NoMachine Connection"

        # Create configuration directory
        config_dir = os.path.expanduser("~/.config/nomachine")
        os.makedirs(config_dir, exist_ok=True)

        # Create .nxs file in persistent location
        nxs_content = self.generate_nomachine_nxs(username, password, address, port, window_size)
        nxs_filename = os.path.join(config_dir, f"{display_name.replace(' ', '_')}.nxs")

        # Save .nxs file
        with open(nxs_filename, "w", encoding="utf-8", newline="\n") as f:
            f.write(nxs_content)

        # DEFINE EXEC COMMAND FOR NOMACHINE - use correct path
        exec_command = f"/usr/NX/bin/nxplayer --session {nxs_filename}"

        # Create launcher content
        launcher_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=/usr/NX/share/icons/48x48/NoMachine-icon.png
    Exec={exec_command}
    """

        # Save files using sudo
        if self.password is None:
            raise PermissionError("Authentication required")

        # Save launcher to /usr/local/bin/
        import tempfile
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
            tmp.write(launcher_content)
            tmp_path = tmp.name

        cmd = ['sudo', '-S', 'mv', tmp_path, nomachinelauncher]
        result = subprocess.run(cmd, input=f"{self.password}\n",
                                capture_output=True, text=True, timeout=10)
        if result.returncode != 0:
            raise Exception(f"Failed to save NoMachine launcher: {result.stderr}")

        # Set permissions
        cmd = ['sudo', '-S', 'chmod', '755', nomachinelauncher]
        subprocess.run(cmd, input=f"{self.password}\n",
                       capture_output=True, text=True, timeout=10)

        # Create desktop icon if requested
        if create_desktop_icon:
            try:
                # Use the same display name for desktop icon
                desktop_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=/usr/NX/share/icons/48x48/NoMachine-icon.png
    Exec={exec_command}
    """
                with open(desktop_launcher, 'w') as f:
                    f.write(desktop_content)
                subprocess.run(['chmod', '755', desktop_launcher], timeout=10)
            except Exception as e:
                print(f"Warning: Could not create desktop icon: {e}")

        # Create autostart if requested
        if enable_autostart:
            try:
                # Create autostart file with proper content
                autostart_content = f"""[Desktop Entry]
    Name={display_name}
    Type=Application
    Icon=nomachine
    Exec={exec_command}
    X-GNOME-Autostart-enabled=true
    """
                with open(autostart_launcher, 'w') as f:
                    f.write(autostart_content)
                subprocess.run(['chmod', '755', autostart_launcher], timeout=10)
                print(f"Autostart enabled for: {display_name}")
            except Exception as e:
                print(f"Warning: Could not create autostart: {e}")
                raise Exception(f"Failed to enable autostart: {str(e)}")

    def generate_nomachine_nxs(self, username, password, host, port, window_size="normal"):
        """Generate NoMachine .nxs configuration file content using the provided NoMachine code"""
        nx = NoMachineFile(
            username=username,
            password=password,
            host=host,
            port=port,
            window_size=window_size,
            useUDP=False
        )
        return nx.as_file

    def parse_existing_connection(self, conn_type):
        """Parse existing connection details from desktop files including display name and autostart"""
        try:
            if conn_type == "RDP":
                launcher_path = '/usr/local/bin/.rdpcon.desktop'
            elif conn_type == "SPICE":
                launcher_path = '/usr/local/bin/.spicecon.desktop'
            elif conn_type == "VNC":
                launcher_path = '/usr/local/bin/.vnccon.desktop'
            elif conn_type == "NOMACHINE":
                launcher_path = '/usr/local/bin/.nomachinecon.desktop'
            else:
                return None

            if not os.path.exists(launcher_path):
                return None

            # Read the desktop file
            details = {'type': conn_type}

            with open(launcher_path, 'r') as f:
                content = f.read()

            # Parse display name from desktop file - this is the original name set by user
            name_match = re.search(r'Name=(.+)', content)
            if name_match:
                details['display_name'] = name_match.group(1).strip()

            if conn_type == "RDP":
                domain_match = re.search(r'/d:(\S+)', content)
                user_match = re.search(r'/u:(\S+)', content)
                pass_match = re.search(r'/p:(\S+)', content)
                address_match = re.search(r'/v:(\S+)', content)

                if domain_match:
                    details['domain'] = domain_match.group(1)
                if user_match:
                    details['username'] = user_match.group(1)
                if pass_match:
                    details['password'] = pass_match.group(1)
                if address_match:
                    details['address'] = address_match.group(1)

            elif conn_type == "SPICE":
                spice_match = re.search(r'spice://(\S+):(\d+)', content)
                if spice_match:
                    details['address'] = spice_match.group(1)
                    details['port'] = spice_match.group(2)

            elif conn_type == "VNC":
                # Parse VNC connection details - remote-viewer vnc://address:port -f
                vnc_match = re.search(r'vnc://(\S+):(\d+)', content)
                if vnc_match:
                    details['address'] = vnc_match.group(1)
                    details['port'] = vnc_match.group(2)

                # For VNC, we need to extract username and password if they exist in the connection string
                # Some VNC connections might have authentication in the URL like: vnc://username:password@address:port
                vnc_auth_match = re.search(r'vnc://([^:]+):([^@]+)@(\S+):(\d+)', content)
                if vnc_auth_match:
                    details['username'] = vnc_auth_match.group(1)
                    details['password'] = vnc_auth_match.group(2)
                    details['address'] = vnc_auth_match.group(3)
                    details['port'] = vnc_auth_match.group(4)

            elif conn_type == "NOMACHINE":
                # Parse NoMachine connection details - look for the .nxs file path in Exec command
                nxs_match = re.search(r'Exec=/usr/NX/bin/nxplayer --session\s+([^\s]+)', content)
                if nxs_match:
                    nxs_path = nxs_match.group(1).strip()
                    print(f"Found NoMachine .nxs file: {nxs_path}")

                    if os.path.exists(nxs_path):
                        try:
                            # Parse the .nxs file for connection details
                            with open(nxs_path, 'r') as nxs_file:
                                nxs_content = nxs_file.read()

                            print(f"Successfully read .nxs file: {len(nxs_content)} bytes")

                            # Extract details from .nxs content - use more robust parsing
                            # Look for the actual values in the XML
                            host_match = re.search(r'<option key="Server host" value="([^"]*)"', nxs_content)
                            port_match = re.search(r'<option key="Server port" value="([^"]*)"', nxs_content)
                            user_match = re.search(r'<option key="User" value="([^"]*)"', nxs_content)
                            window_match = re.search(r'<option key="Session window state" value="([^"]*)"', nxs_content)
                            password_match = re.search(r'<option key="Auth" value="([^"]*)"', nxs_content)

                            print(f"Parsing results - Host: {host_match.group(1) if host_match else 'None'}")
                            print(f"Parsing results - Port: {port_match.group(1) if port_match else 'None'}")
                            print(f"Parsing results - User: {user_match.group(1) if user_match else 'None'}")
                            print(f"Parsing results - Window: {window_match.group(1) if window_match else 'None'}")

                            # Store the actual values
                            details['address'] = host_match.group(1) if host_match and host_match.group(
                                1) != EMPTY_PASSWORD else 'Unknown'
                            details['port'] = port_match.group(1) if port_match and port_match.group(1) else '4000'
                            details['username'] = user_match.group(1) if user_match and user_match.group(
                                1) else 'Unknown'
                            details['window_size'] = window_match.group(1) if window_match and window_match.group(
                                1) else 'normal'
                            details['password'] = password_match.group(1) if password_match and password_match.group(
                                1) != EMPTY_PASSWORD else ''

                        except Exception as e:
                            print(f"Error parsing .nxs file {nxs_path}: {e}")
                            import traceback
                            traceback.print_exc()
                            # Set default values if parsing fails
                            details['address'] = 'Unknown'
                            details['port'] = '4000'
                            details['username'] = 'Unknown'
                            details['window_size'] = 'normal'
                            details['password'] = ''
                    else:
                        print(f".nxs file not found: {nxs_path}")
                        # Set default values if file doesn't exist
                        details['address'] = 'Unknown'
                        details['port'] = '4000'
                        details['username'] = 'Unknown'
                        details['window_size'] = 'normal'
                        details['password'] = ''
                else:
                    print("No .nxs file path found in Exec command")
                    # Try alternative pattern
                    nxs_match_alt = re.search(r'Exec=/usr/NX/bin/nxplayer --session\s+"([^"]+)"', content)
                    if nxs_match_alt:
                        nxs_path = nxs_match_alt.group(1).strip()
                        print(f"Found NoMachine .nxs file (alt pattern): {nxs_path}")
                    else:
                        print("No .nxs file found with any pattern")
                        # Set default values if no match
                        details['address'] = 'Unknown'
                        details['port'] = '4000'
                        details['username'] = 'Unknown'
                        details['window_size'] = 'normal'
                        details['password'] = ''

            # Check if desktop icon exists and store this preference
            desktop_path = self.get_desktop_path_by_type(conn_type)
            # Double-check for NoMachine specifically
            if conn_type == "NOMACHINE":
                nomachine_desktop_path = os.path.expanduser("~/Desktop/NoMachineconnection.desktop")
                desktop_icon_exists = os.path.exists(nomachine_desktop_path)
                print(f"NoMachine desktop icon check: {desktop_icon_exists} at {nomachine_desktop_path}")  # Debug
            else:
                desktop_icon_exists = os.path.exists(desktop_path)

            details['desktop_icon'] = desktop_icon_exists
            print(f"Desktop icon detection for {conn_type}: {desktop_icon_exists}")  # Debug

            # Check if autostart is enabled
            autostart_path = self.get_autostart_path()
            if os.path.exists(autostart_path):
                # Read autostart file to check if it's for this specific connection
                with open(autostart_path, 'r') as f:
                    autostart_content = f.read()
                autostart_name_match = re.search(r'Name=(.+)', autostart_content)
                if autostart_name_match and autostart_name_match.group(1).strip() == details.get('display_name', ''):
                    details['autostart'] = True
                else:
                    details['autostart'] = False
            else:
                details['autostart'] = False

            print(
                f"Parsed {conn_type} details: { {k: v for k, v in details.items() if k != 'password'} }")  # Don't log password
            return details

        except Exception as e:
            print(f"Error parsing existing connection {conn_type}: {e}")
            import traceback
            traceback.print_exc()
            return None

    def edit_connection(self):
        """Edit selected connection"""
        selection = self.connections_tree.selection()
        if not selection:
            messagebox.showwarning("Warning", "Please select a connection to edit")
            return

        item = self.connections_tree.item(selection[0])
        values = item['values']

        if values[0] == "No connections configured":
            messagebox.showwarning("Warning", "No connection selected")
            return

        # Get connection details from the treeview
        conn_name = values[0]
        conn_type = values[1]
        conn_address = values[2]

        # Map the display type to internal type
        type_mapping = {
            "RDP": "RDP",
            "SPICE": "SPICE",
            "VNC": "VNC",
            "NoMachine": "NOMACHINE"  # Map display name to internal type
        }

        internal_type = type_mapping.get(conn_type, conn_type)

        # Parse existing connection details from the desktop files
        existing_details = self.parse_existing_connection(internal_type)

        if existing_details:
            # Ensure the display_name is set from the treeview (which shows the actual name)
            existing_details['display_name'] = conn_name
            self.create_connection_dialog(conn_type, existing_details, conn_name)
        else:
            messagebox.showwarning("Warning", f"Could not parse existing {conn_type} connection details")
            print(f"Debug: conn_type={conn_type}, internal_type={internal_type}")  # Debug

    def delete_connection(self):
        """Delete selected connection"""
        selection = self.connections_tree.selection()
        if not selection:
            messagebox.showwarning("Warning", "Please select a connection to delete")
            return

        item = self.connections_tree.item(selection[0])
        values = item['values']

        if values[0] == "No connections configured":
            messagebox.showwarning("Warning", "No connection to delete")
            return

        conn_name = values[0]
        conn_type = values[1]

        if not messagebox.askyesno("Confirm Delete",
                                   f"Are you sure you want to delete the {conn_type} connection '{conn_name}'?"):
            return

        try:
            # Remove desktop icon with correct filename based on connection type
            if conn_type == "RDP":
                desktop_path = os.path.expanduser("~/Desktop/RDPconnection.desktop")
            elif conn_type == "SPICE":
                desktop_path = os.path.expanduser("~/Desktop/SPICEconnection.desktop")
            elif conn_type == "VNC":
                desktop_path = os.path.expanduser("~/Desktop/VNCconnection.desktop")
            elif conn_type == "NoMachine":
                desktop_path = os.path.expanduser("~/Desktop/NoMachineconnection.desktop")
                # Also remove the .nxs file for NoMachine
                config_dir = os.path.expanduser("~/.config/nomachine")
                nxs_file = os.path.join(config_dir, f"{conn_name.replace(' ', '_')}.nxs")
                if os.path.exists(nxs_file):
                    os.remove(nxs_file)
                    print(f"Removed .nxs file: {nxs_file}")

            if os.path.exists(desktop_path):
                subprocess.run(['rm', '-f', desktop_path], timeout=10)

            # Remove autostart if this connection has it enabled
            autostart_path = self.get_autostart_path()
            if os.path.exists(autostart_path):
                # Check if this is the autostart connection
                current_autostart = self.get_autostart_connection()
                if current_autostart == conn_name:
                    subprocess.run(['rm', '-f', autostart_path], timeout=10)

            # Remove the connection files
            if conn_type == "RDP":
                self.delete_connection_files('/usr/local/bin/.rdpcon.desktop')
            elif conn_type == "SPICE":
                self.delete_connection_files('/usr/local/bin/.spicecon.desktop')
            elif conn_type == "VNC":
                self.delete_connection_files('/usr/local/bin/.vnccon.desktop')
            elif conn_type == "NoMachine":
                self.delete_connection_files('/usr/local/bin/.nomachinecon.desktop')

            messagebox.showinfo("Success", f"{conn_type} connection deleted successfully")
            self.refresh_connections_list()

        except Exception as e:
            messagebox.showerror("Error", f"Failed to delete connection: {str(e)}")


    def delete_connection_files(self, launcher_path):
        """Delete connection files"""
        if self.password is None:
            raise PermissionError("Authentication required")

        # Delete launcher
        if os.path.exists(launcher_path):
            cmd = ['sudo', '-S', 'rm', '-f', launcher_path]
            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=10)
            if result.returncode != 0:
                raise Exception(f"Failed to delete launcher: {result.stderr}")

    def setup_scanners_tab(self):
        """Scanners tab for scanner subnet configuration"""
        frame = ttk.LabelFrame(self.scanners_frame, text="Scanner Network Configuration", padding="10")
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Use a grid layout for better control
        row = 0

        # Current scanner subnets display - COMPACT
        current_subnets_frame = ttk.LabelFrame(frame, text="Current Scanner Subnets", padding="5")
        current_subnets_frame.grid(row=row, column=0, columnspan=2, sticky=tk.W + tk.E, pady=5)
        row += 1

        self.current_subnets_label = ttk.Label(current_subnets_frame, text="Loading current subnets...",
                                               justify=tk.LEFT, background='#f5f5f5', relief=tk.SUNKEN, padding=3,
                                               wraplength=650)
        self.current_subnets_label.pack(fill=tk.X, padx=5, pady=2)

        ttk.Button(current_subnets_frame, text="Refresh Current Subnets",
                   command=self.refresh_scanner_subnets).pack(pady=2)

        # Scanner Subnets - COMPACT
        subnets_frame = ttk.LabelFrame(frame, text="Scanner Subnets/IPs", padding="5")
        subnets_frame.grid(row=row, column=0, columnspan=2, sticky=tk.W + tk.E, pady=5)
        row += 1

        ttk.Label(subnets_frame, text="Enter one subnet or IP per line:",
                  font=('Arial', 8), foreground='gray').pack(anchor=tk.W)

        text_frame = ttk.Frame(subnets_frame)
        text_frame.pack(fill=tk.X, pady=2)

        self.scanner_subnets_text = tk.Text(text_frame, height=2, width=30)
        self.scanner_subnets_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        scrollbar_subnets = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=self.scanner_subnets_text.yview)
        scrollbar_subnets.pack(side=tk.RIGHT, fill=tk.Y)
        self.scanner_subnets_text.config(yscrollcommand=scrollbar_subnets.set)

        # Scanner Device Detection - COMPACT
        scanner_alias_frame = ttk.LabelFrame(frame, text="Scanner Device Alias", padding="5")
        scanner_alias_frame.grid(row=row, column=0, columnspan=2, sticky=tk.W + tk.E, pady=5)
        row += 1

        # Device detection in one row
        detect_frame = ttk.Frame(scanner_alias_frame)
        detect_frame.pack(fill=tk.X, pady=2)

        ttk.Button(detect_frame, text="Detect Scanners",
                   command=self.detect_scanner_devices).pack(side=tk.LEFT, padx=(0, 10))

        self.scanner_devices_label = ttk.Label(detect_frame, text="Click 'Detect Scanners' to find devices",
                                               justify=tk.LEFT, background='#f5f5f5', relief=tk.SUNKEN, padding=3,
                                               wraplength=500)
        self.scanner_devices_label.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))

        # Alias creation in one row
        alias_frame = ttk.Frame(scanner_alias_frame)
        alias_frame.pack(fill=tk.X, pady=2)

        ttk.Label(alias_frame, text="Alias Name:").pack(side=tk.LEFT, padx=(0, 5))
        self.scanner_alias_entry = ttk.Entry(alias_frame, width=15)
        self.scanner_alias_entry.pack(side=tk.LEFT, padx=(0, 10))

        ttk.Button(alias_frame, text="Create Alias",
                   command=self.create_scanner_alias).pack(side=tk.LEFT, padx=(0, 10))

        ttk.Button(alias_frame, text="Remove Selected",
                   command=self.remove_selected_alias).pack(side=tk.LEFT)

        # Aliases listbox - COMPACT
        ttk.Label(scanner_alias_frame, text="Current Aliases:",
                  font=('Arial', 9, 'bold')).pack(anchor=tk.W, pady=(5, 2))

        aliases_frame = ttk.Frame(scanner_alias_frame)
        aliases_frame.pack(fill=tk.X, pady=2)

        self.aliases_listbox = tk.Listbox(aliases_frame, height=2, background='#f5f5f5', relief=tk.SUNKEN)
        self.aliases_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        listbox_scrollbar = ttk.Scrollbar(aliases_frame, orient=tk.VERTICAL, command=self.aliases_listbox.yview)
        listbox_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.aliases_listbox.config(yscrollcommand=listbox_scrollbar.set)

        # SANED Service Management - COMPACT
        saned_frame = ttk.LabelFrame(frame, text="SANED Service Management", padding="5")
        saned_frame.grid(row=row, column=0, columnspan=2, sticky=tk.W + tk.E, pady=5)
        row += 1

        saned_service_frame = ttk.Frame(saned_frame)
        saned_service_frame.pack(fill=tk.X, pady=2)

        ttk.Label(saned_service_frame, text="SANED Service:").pack(side=tk.LEFT, padx=(0, 10))

        ttk.Button(saned_service_frame, text="Start",
                   command=lambda: self.manage_service('xinetd', 'start')).pack(side=tk.LEFT, padx=2)
        ttk.Button(saned_service_frame, text="Restart",
                   command=lambda: self.manage_service('xinetd', 'restart')).pack(side=tk.LEFT, padx=2)
        ttk.Button(saned_service_frame, text="Enable",
                   command=lambda: self.manage_service('xinetd', 'enable')).pack(side=tk.LEFT, padx=2)

        self.saned_service_status = ttk.Label(saned_service_frame, text="Checking...")
        self.saned_service_status.pack(side=tk.LEFT, padx=(10, 0))

        # Bottom buttons - COMPACT
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=row, column=0, columnspan=2, sticky=tk.W + tk.E, pady=10)
        row += 1

        ttk.Button(button_frame, text="Apply Scanner Settings",
                   command=self.apply_scanner_settings).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Refresh Services",
                   command=self.refresh_scanner_services).pack(side=tk.LEFT, padx=5)

        self.scanner_status = ttk.Label(frame, text="", wraplength=650)
        self.scanner_status.grid(row=row, column=0, columnspan=2, sticky=tk.W + tk.E, pady=5)

        # Configure grid weights
        frame.columnconfigure(0, weight=1)
        frame.columnconfigure(1, weight=1)

        # Load current scanner subnets and auto-check status
        self.refresh_scanner_subnets()
        self.refresh_scanner_services()
        self.refresh_scanner_aliases()

    def setup_printers_tab(self):
        """Printers tab for CUPS configuration and printer management"""
        frame = ttk.LabelFrame(self.printers_frame, text="Printer Configuration", padding="15")
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # CUPS Remote Administration
        cups_frame = ttk.LabelFrame(frame, text="CUPS Remote Administration", padding="10")
        cups_frame.grid(row=0, column=0, columnspan=2, sticky=tk.W + tk.E, pady=10)

        self.cups_remote_var = tk.BooleanVar()
        self.cups_checkbutton = ttk.Checkbutton(cups_frame, text="Enable CUPS Remote Administration",
                                                variable=self.cups_remote_var)
        self.cups_checkbutton.pack(anchor=tk.W, pady=5)

        # CUPS status display
        self.cups_status_label = ttk.Label(cups_frame, text="Checking CUPS status...")
        self.cups_status_label.pack(anchor=tk.W, pady=5)

        # CUPS Printer Configuration Frame
        cups_config_frame = ttk.LabelFrame(frame, text="CUPS Printer Configuration", padding="10")
        cups_config_frame.grid(row=1, column=0, columnspan=2, sticky=tk.W + tk.E, pady=10)

        # Configure Printers Button
        ttk.Button(cups_config_frame, text="Configure Printers (Web Interface)",
                   command=self.open_cups_web_interface).pack(anchor=tk.W, pady=5)

        ttk.Label(cups_config_frame, text="Open CUPS web interface to add, remove, and manage printers",
                  font=('Arial', 8), foreground='gray').pack(anchor=tk.W, pady=(0, 5))

        # OpenRC Services Management
        services_frame = ttk.LabelFrame(frame, text="CUPS Services Management", padding="10")
        services_frame.grid(row=2, column=0, columnspan=2, sticky=tk.W + tk.E, pady=10)

        # CUPS Service controls
        cups_service_frame = ttk.Frame(services_frame)
        cups_service_frame.pack(fill=tk.X, pady=5)

        ttk.Label(cups_service_frame, text="CUPS Service:", font=('Arial', 9, 'bold')).pack(side=tk.LEFT, padx=(0, 10))

        ttk.Button(cups_service_frame, text="Start", command=lambda: self.manage_service('cupsd', 'start')).pack(
            side=tk.LEFT, padx=2)
        ttk.Button(cups_service_frame, text="Restart", command=lambda: self.manage_service('cupsd', 'restart')).pack(
            side=tk.LEFT, padx=2)
        ttk.Button(cups_service_frame, text="Enable", command=lambda: self.manage_service('cupsd', 'enable')).pack(
            side=tk.LEFT, padx=2)

        self.cups_service_status_label = ttk.Label(cups_service_frame, text="Checking...")
        self.cups_service_status_label.pack(side=tk.LEFT, padx=(10, 0))

        # Buttons
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=3, column=0, columnspan=2, pady=15)

        ttk.Button(button_frame, text="Apply Printer Settings", command=self.apply_printer_settings).pack(side=tk.LEFT,
                                                                                                          padx=5)
        ttk.Button(button_frame, text="Refresh Services", command=self.refresh_printer_services).pack(side=tk.LEFT,
                                                                                                      padx=5)

        self.printer_status = ttk.Label(frame, text="")
        self.printer_status.grid(row=4, column=0, columnspan=2)

        # Load current status
        self.refresh_printer_services()
        # Only check CUPS status if authenticated
        if self.password is not None:
            self.check_cups_status()
        else:
            self.cups_status_label.config(text="Please authenticate to check CUPS status")

    def open_cups_web_interface(self):
        """Open CUPS web interface in the default browser"""
        try:
            url = "http://127.0.0.1:631/admin"

            # Try different methods to open the browser
            methods = [
                ['xdg-open', url],  # Linux
                ['firefox', url],  # Firefox specifically
                ['chromium-browser', url],  # Chromium
                ['google-chrome', url],  # Google Chrome
                ['sensible-browser', url],  # Fallback on Linux
            ]

            success = False
            for method in methods:
                try:
                    result = subprocess.run(method, capture_output=True, timeout=10)
                    if result.returncode == 0:
                        success = True
                        self.printer_status.config(text="CUPS web interface opened successfully", foreground="green")
                        break
                except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
                    continue

            if not success:
                # Last resort: use webbrowser module
                import webbrowser
                webbrowser.open(url)
                self.printer_status.config(text="Opening CUPS web interface...", foreground="green")

        except Exception as e:
            self.printer_status.config(text=f"Error opening browser: {str(e)}", foreground="red")
            messagebox.showerror("Error", f"Could not open CUPS web interface:\n{str(e)}")

    def detect_scanner_devices(self):
        """Detect available scanner devices using scanimage -L and extract device paths"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            # Run scanimage -L and process output to extract only device paths
            cmd = ['bash', '-c', r"""
                scanimage -L | grep -q "device" && \
                scanimage -L | awk '{print $2}' | sed -e 's/^`//g' -e "s/'$//g" || \
                echo "No scanners detected"
                """.strip()]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)

            if result.returncode == 0:
                devices = []
                for line in result.stdout.split('\n'):
                    line = line.strip()
                    if line and not line.startswith('device'):
                        devices.append(line)

                if devices:
                    devices_text = "Detected scanner devices:\n" + "\n".join([f"• {device}" for device in devices])
                    self.scanner_devices_label.config(text=devices_text)

                    # Auto-fill the first device path in the alias entry if empty
                    if devices and not self.scanner_alias_entry.get().strip():
                        first_device = devices[0]
                        # Extract just the first part of device path for suggestion
                        if ':' in first_device:
                            suggested_alias = first_device.split(':')[0]
                            self.scanner_alias_entry.insert(0, suggested_alias)
                else:
                    self.scanner_devices_label.config(text="No scanners detected")
            else:
                self.scanner_devices_label.config(text=f"Error detecting scanners: {result.stderr}")

        except Exception as e:
            self.scanner_devices_label.config(text=f"Error detecting scanners: {str(e)}")

    def create_scanner_alias(self):
        """Create scanner alias in /etc/sane.d/dll.aliases"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            alias_name = self.scanner_alias_entry.get().strip()
            if not alias_name:
                messagebox.showerror("Error", "Please enter a scanner alias name")
                return

            # Get the detected scanner devices from the label text
            current_text = self.scanner_devices_label.cget("text")
            if not current_text.startswith("Detected scanner devices:"):
                messagebox.showerror("Error", "Please detect scanners first")
                return

            # Extract the first device path from the displayed text
            lines = current_text.split('\n')
            if len(lines) < 2:
                messagebox.showerror("Error", "No scanners detected")
                return

            # Find the first device line (starts with •)
            device_path = None
            for line in lines[1:]:  # Skip the first line (header)
                if line.strip().startswith('•'):
                    device_path = line.strip()[2:].strip()  # Remove the "• " prefix
                    break

            if device_path == "No scanners detected":
                messagebox.showerror("Error", "No scanner devices found")
                return

            if not device_path:
                messagebox.showerror("Error", "No scanner devices found")
                return

            # Create the alias entry
            alias_entry = f"alias {alias_name} {device_path}"

            # Read current aliases
            aliases = self.get_current_scanner_aliases()

            # Check if alias already exists
            for existing_alias in aliases:
                if existing_alias.startswith(f"alias {alias_name} "):
                    messagebox.showerror("Error", f"Alias '{alias_name}' already exists")
                    return

            # Add new alias
            aliases.append(alias_entry)

            # Save aliases back to file
            if self.save_scanner_aliases(aliases):
                messagebox.showinfo("Success", f"Scanner alias '{alias_name}' created successfully")
                self.refresh_scanner_aliases()
                self.scanner_alias_entry.delete(0, tk.END)
            else:
                messagebox.showerror("Error", "Failed to create scanner alias")

        except Exception as e:
            messagebox.showerror("Error", f"Error creating scanner alias: {str(e)}")

    def save_scanner_aliases(self, aliases):
        """Save scanner aliases to /etc/sane.d/dll.aliases using sudo"""
        try:
            aliases_path = '/etc/sane.d/dll.aliases'

            # Write the aliases using sudo
            import tempfile
            with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
                for alias in aliases:
                    tmp.write(f"{alias}\n")
                tmp_path = tmp.name

            # Move with sudo - use the stored password
            if self.password is None:
                raise PermissionError("Need root access to save scanner aliases")

            # Use the stored password for sudo
            cmd = ['sudo', '-S', 'mv', tmp_path, aliases_path]
            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=10)

            if result.returncode != 0:
                # Check if it's a password error
                if "sorry, try again" in result.stderr or "incorrect password" in result.stderr:
                    raise PermissionError("Authentication failed - wrong password")
                else:
                    raise PermissionError(f"Failed to save aliases: {result.stderr}")

            # Set proper permissions
            cmd = ['sudo', '-S', 'chmod', '644', aliases_path]
            subprocess.run(cmd, input=f"{self.password}\n",
                           capture_output=True, text=True, timeout=10)

            return True

        except Exception as e:
            messagebox.showerror("Error", f"Error saving scanner aliases: {str(e)}")
            return False

    def remove_selected_alias(self):
        """Remove the selected alias from listbox"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            # Get selected alias from LISTBOX, not entry field
            selection = self.aliases_listbox.curselection()
            if not selection:
                messagebox.showwarning("Warning", "Please select an alias from the list to remove")
                return

            selected_alias = self.aliases_listbox.get(selection[0])

            # Don't remove the "No aliases configured" message
            if selected_alias == "No aliases configured":
                messagebox.showwarning("Warning", "No aliases to remove")
                return

            # Confirm removal
            if not messagebox.askyesno("Confirm Removal", f"Are you sure you want to remove alias:\n{selected_alias}?"):
                return

            # Get current aliases
            aliases = self.get_current_scanner_aliases()

            # Remove the selected alias
            new_aliases = [a for a in aliases if a != selected_alias]

            # Save updated aliases
            if self.save_scanner_aliases(new_aliases):
                messagebox.showinfo("Success", "Scanner alias removed successfully")
                self.refresh_scanner_aliases()
                # AUTO-DETECT: Refresh scanner devices after removing alias
                self.detect_scanner_devices()
            else:
                # If save failed due to authentication, offer to re-authenticate
                if self.password is None:
                    messagebox.showerror("Authentication Failed",
                                         "Authentication failed. Please re-authenticate in the Authentication tab.")
                else:
                    messagebox.showerror("Error", "Failed to remove scanner alias")

        except Exception as e:
            messagebox.showerror("Error", f"Error removing scanner alias: {str(e)}")

    def refresh_scanner_subnets(self):
        """Refresh and display current scanner subnets"""
        subnets = self.get_current_scanner_subnets()

        # Update display
        if subnets:
            display_text = "Current subnets/IPs:\n" + "\n".join([f"• {subnet}" for subnet in subnets])
        else:
            display_text = "No subnets or IPs configured"

        self.current_subnets_label.config(text=display_text)

        # Update text area
        self.scanner_subnets_text.delete(1.0, tk.END)
        self.scanner_subnets_text.insert(1.0, "\n".join(subnets))

    def refresh_scanner_devices(self):
        """Refresh scanner devices display"""
        # This will be called when the scanners tab is selected
        current_text = self.scanner_devices_label.cget("text")
        if current_text == "Click 'Detect Scanners' to find devices":
            # Auto-detect scanners when tab is first opened
            self.detect_scanner_devices()

    def check_service_status(self, service_name):
        """Check if an OpenRC service is running"""
        try:
            result = subprocess.run(['rc-service', service_name, 'status'],
                                    capture_output=True, text=True, timeout=10)
            return result.returncode == 0
        except Exception as e:
            print(f"Error checking service {service_name}: {e}")
            return False

    def check_service_enabled(self, service_name):
        """Check if an OpenRC service is enabled"""
        try:
            result = subprocess.run(['rc-status'],
                                    capture_output=True, text=True, timeout=10)
            # Check if service is in the default runlevel
            if result.returncode == 0:
                lines = result.stdout.split('\n')
                in_default_section = False
                for line in lines:
                    if 'default' in line:
                        in_default_section = True
                        continue
                    if in_default_section and line.strip().startswith('['):
                        break  # Moved to next section
                    if in_default_section and service_name in line:
                        return True
            return False
        except Exception as e:
            print(f"Error checking service enabled {service_name}: {e}")
            return False

    def check_cups_service(self):
        """Check and display CUPS service status"""
        is_active = self.check_service_status('cupsd')
        is_enabled = self.check_service_enabled('cupsd')

        status_text = f"Status: {'Active' if is_active else 'Inactive'} | "
        status_text += f"Enabled: {'Yes' if is_enabled else 'No'}"

        self.cups_service_status_label.config(
            text=status_text,
            foreground="green" if is_active else "red"
        )

    def check_saned_service(self):
        """Check and display SANED service status"""
        is_active = self.check_service_status('xinetd')
        is_enabled = self.check_service_enabled('xinetd')

        status_text = f"Status: {'Active' if is_active else 'Inactive'} | "
        status_text += f"Enabled: {'Yes' if is_enabled else 'No'}"

        self.saned_service_status.config(
            text=status_text,
            foreground="green" if is_active else "red"
        )

    def refresh_scanner_services(self):
        """Refresh only scanner-related services"""
        self.check_saned_service()

    def refresh_printer_services(self):
        """Refresh only printer-related services"""
        self.check_cups_service()

    def refresh_services(self):
        """Refresh all services (for backward compatibility)"""
        self.refresh_scanner_services()
        self.refresh_printer_services()

    def manage_service(self, service_name, action):
        """Manage OpenRC service (start, stop, restart, add, delete)"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            # Map actions to OpenRC commands
            if action == 'enable':
                # In OpenRC, 'add' adds service to default runlevel
                cmd = ['sudo', '-S', 'rc-update', 'add', service_name]
            elif action == 'disable':
                cmd = ['sudo', '-S', 'rc-update', 'del', service_name]
            else:
                # start, stop, restart
                cmd = ['sudo', '-S', 'rc-service', service_name, action]

            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=30)

            if result.returncode == 0:
                messagebox.showinfo("Success", f"Service {service_name} {action}ed successfully")
                # Refresh appropriate services based on which service was managed
                if service_name == 'xinetd':
                    self.refresh_scanner_services()
                elif service_name == 'cupsd':
                    self.refresh_printer_services()
            else:
                messagebox.showerror("Error", f"Failed to {action} {service_name}: {result.stderr}")

        except Exception as e:
            messagebox.showerror("Error", f"Error managing service: {str(e)}")

    def check_cups_status(self):
        """Check CUPS daemon status and configuration"""
        try:
            # Check if CUPS is running
            result = subprocess.run(['rc-service', 'cupsd', 'status'],
                                    capture_output=True, text=True, timeout=10)
            cups_active = result.returncode == 0

            # Check CUPS configuration for remote admin
            cups_conf_path = '/etc/cups/cupsd.conf'
            remote_admin_enabled = False

            if os.path.exists(cups_conf_path):
                try:
                    # Try to read directly first
                    with open(cups_conf_path, 'r') as f:
                        content = f.read()
                except PermissionError:
                    # If permission denied, use sudo to read
                    if self.password is None:
                        self.cups_status_label.config(text="Authentication needed to check CUPS config")
                        self.cups_remote_var.set(False)
                        return

                    # Read with sudo
                    cmd = ['sudo', '-S', 'cat', cups_conf_path]
                    result = subprocess.run(cmd, input=f"{self.password}\n",
                                            capture_output=True, text=True, timeout=10)
                    if result.returncode == 0:
                        content = result.stdout
                    else:
                        # If we still can't read, show limited status
                        status_text = f"CUPS Service: {'Running' if cups_active else 'Stopped'} | "
                        status_text += "Remote Admin: Unknown (Permission denied)"
                        self.cups_status_label.config(text=status_text)
                        self.cups_remote_var.set(False)
                        return

                # Look for Listen directives that allow remote access
                # Check for Port 631 (enables remote access) vs Listen localhost:631 (local only)
                if 'Port 631' in content or 'Listen *:631' in content or re.search(r'Listen\s+\d+\.\d+\.\d+\.\d+:\d+',
                                                                                   content):
                    remote_admin_enabled = True
                elif 'Listen localhost:631' in content:
                    remote_admin_enabled = False
            else:
                # CUPS config file doesn't exist
                status_text = f"CUPS Service: {'Running' if cups_active else 'Stopped'} | "
                status_text += "Config file not found"
                self.cups_status_label.config(text=status_text)
                self.cups_remote_var.set(False)
                return

            status_text = f"CUPS Service: {'Running' if cups_active else 'Stopped'} | "
            status_text += f"Remote Admin: {'Enabled' if remote_admin_enabled else 'Disabled'}"

            self.cups_status_label.config(text=status_text)

            # Update checkbox state
            self.cups_remote_var.set(remote_admin_enabled)

        except Exception as e:
            # Show a more user-friendly error message
            error_msg = f"Error checking CUPS status: {str(e)}"
            if "Permission denied" in str(e):
                error_msg = "Permission denied to read CUPS config. Please authenticate first."
            self.cups_status_label.config(text=error_msg)
            self.cups_remote_var.set(False)

    def modify_cups_config(self, enable_remote):
        """Modify CUPS configuration to enable/disable remote administration"""
        try:
            cups_conf_path = '/etc/cups/cupsd.conf'

            # Check if file exists and we can read it
            if not os.path.exists(cups_conf_path):
                messagebox.showerror("Error", "CUPS configuration file not found")
                return False

            # Read the current configuration
            try:
                with open(cups_conf_path, 'r') as f:
                    content = f.read()
            except PermissionError:
                # Read with sudo if permission denied
                if self.password is None:
                    messagebox.showerror("Permission Denied",
                                         "Need root access to read CUPS configuration")
                    return False

                cmd = ['sudo', '-S', 'cat', cups_conf_path]
                result = subprocess.run(cmd, input=f"{self.password}\n",
                                        capture_output=True, text=True, timeout=10)
                if result.returncode != 0:
                    messagebox.showerror("Error", f"Failed to read CUPS config: {result.stderr}")
                    return False
                content = result.stdout

            if enable_remote:
                # Enable remote administration - use the provided configuration
                new_content = """LogLevel warn
MaxLogSize 0
ErrorPolicy stop-printer
# Allow remote access
Port 631
Listen /run/cups/cups.sock
Browsing Yes
BrowseLocalProtocols dnssd
DefaultAuthType Basic
WebInterface Yes
IdleExitTimeout 60
<Location />
  # Allow remote administration...
  Order allow,deny
  Allow all
</Location>
<Location /admin>
  AuthType Default
  Require user @SYSTEM
  # Allow remote administration...
  Order allow,deny
  Allow all
</Location>
<Location /admin/conf>
  AuthType Default
  Require user @SYSTEM
  # Allow remote access to the configuration files...
  Order allow,deny
  Allow all
</Location>
<Location /admin/log>
  AuthType Default
  Require user @SYSTEM
  # Allow remote access to the log files...
  Order allow,deny
  Allow all
</Location>
<Policy default>
  JobPrivateAccess default
  JobPrivateValues default
  SubscriptionPrivateAccess default
  SubscriptionPrivateValues default
  <Limit Create-Job Print-Job Print-URI Validate-Job>
    Order deny,allow
  </Limit>
  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job>
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Get-Document>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Cancel-Job>
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Authenticate-Job>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit All>
    Order deny,allow
  </Limit>
</Policy>
<Policy authenticated>
  JobPrivateAccess default
  JobPrivateValues default
  SubscriptionPrivateAccess default
  SubscriptionPrivateValues default
  <Limit Create-Job Print-Job Print-URI Validate-Job>
    AuthType Default
    Order deny,allow
  </Limit>
  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Cancel-Job CUPS-Authenticate-Job>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit All>
    Order deny,allow
  </Limit>
</Policy>
<Policy kerberos>
  JobPrivateAccess default
  JobPrivateValues default
  SubscriptionPrivateAccess default
  SubscriptionPrivateValues default
  <Limit Create-Job Print-Job Print-URI Validate-Job>
    AuthType Negotiate
    Order deny,allow
  </Limit>
  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
    AuthType Negotiate
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Cancel-Job CUPS-Authenticate-Job>
    AuthType Negotiate
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit All>
    Order deny,allow
  </Limit>
</Policy>"""
            else:
                # Disable remote administration - use the provided configuration
                new_content = """LogLevel warn
MaxLogSize 0
ErrorPolicy stop-printer
# Only listen for connections from the local machine.
Listen localhost:631
Listen /run/cups/cups.sock
# Disable printer sharing.
Browsing Off
DefaultAuthType Basic
WebInterface Yes
IdleExitTimeout 60
<Location />
  # Restrict access to the server...
  Order allow,deny
</Location>
<Location /admin>
  AuthType Default
  Require user @SYSTEM
  # Restrict access to the admin pages...
  Order allow,deny
</Location>
<Location /admin/conf>
  AuthType Default
  Require user @SYSTEM
  # Restrict access to the configuration files...
  Order allow,deny
</Location>
<Location /admin/log>
  AuthType Default
  Require user @SYSTEM
  # Restrict access to the log files...
  Order allow,deny
</Location>
<Policy default>
  JobPrivateAccess default
  JobPrivateValues default
  SubscriptionPrivateAccess default
  SubscriptionPrivateValues default
  <Limit Create-Job Print-Job Print-URI Validate-Job>
    Order deny,allow
  </Limit>
  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job>
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Get-Document>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Cancel-Job>
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Authenticate-Job>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit All>
    Order deny,allow
  </Limit>
</Policy>
<Policy authenticated>
  JobPrivateAccess default
  JobPrivateValues default
  SubscriptionPrivateAccess default
  SubscriptionPrivateValues default
  <Limit Create-Job Print-Job Print-URI Validate-Job>
    AuthType Default
    Order deny,allow
  </Limit>
  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Cancel-Job CUPS-Authenticate-Job>
    AuthType Default
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit All>
    Order deny,allow
  </Limit>
</Policy>
<Policy kerberos>
  JobPrivateAccess default
  JobPrivateValues default
  SubscriptionPrivateAccess default
  SubscriptionPrivateValues default
  <Limit Create-Job Print-Job Print-URI Validate-Job>
    AuthType Negotiate
    Order deny,allow
  </Limit>
  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
    AuthType Negotiate
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
    AuthType Default
    Require user @SYSTEM
    Order deny,allow
  </Limit>
  <Limit Cancel-Job CUPS-Authenticate-Job>
    AuthType Negotiate
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>
  <Limit All>
    Order deny,allow
  </Limit>
</Policy>"""

            # Write back the configuration using sudo
            import tempfile
            with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
                tmp.write(new_content)
                tmp_path = tmp.name

            # Move with sudo
            if self.password is None:
                messagebox.showerror("Permission Denied",
                                     "Need root access to modify CUPS configuration")
                return False

            cmd = ['sudo', '-S', 'mv', tmp_path, cups_conf_path]
            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=10)

            if result.returncode != 0:
                messagebox.showerror("Error", f"Failed to save CUPS config: {result.stderr}")
                return False

            # Set proper permissions
            cmd = ['sudo', '-S', 'chmod', '644', cups_conf_path]
            subprocess.run(cmd, input=f"{self.password}\n",
                           capture_output=True, text=True, timeout=10)

            return True

        except Exception as e:
            messagebox.showerror("Error", f"Error modifying CUPS configuration: {str(e)}")
            return False

    def save_scanner_subnet(self, subnets):
        """Save scanner subnets to saned.conf using sudo"""
        try:
            saned_conf_path = '/etc/sane.d/saned.conf'

            # Read existing content using sudo if needed
            existing_content = []
            if os.path.exists(saned_conf_path):
                try:
                    with open(saned_conf_path, 'r') as f:
                        existing_content = f.readlines()
                except PermissionError:
                    # Read with sudo
                    if self.password is None:
                        raise PermissionError("Need root access to read saned.conf")

                    cmd = ['sudo', '-S', 'cat', saned_conf_path]
                    result = subprocess.run(cmd, input=f"{self.password}\n",
                                            capture_output=True, text=True, timeout=10)
                    if result.returncode == 0:
                        existing_content = result.stdout.splitlines(True)
                    else:
                        raise PermissionError(f"Failed to read saned.conf: {result.stderr}")

            # Filter out existing subnet lines and comments we'll replace
            new_content = []
            for line in existing_content:
                line_stripped = line.strip()
                # Keep lines that don't look like subnets and aren't empty
                if (not line_stripped or
                        line_stripped.startswith('#') or
                        not re.match(r'^\d+\.\d+\.\d+\.\d+(\/\d+)?$', line_stripped)):
                    new_content.append(line)

            # Add the new subnets
            for subnet in subnets:
                if subnet.strip():  # Only add non-empty subnets
                    new_content.append(f"{subnet.strip()}\n")

            # Write the new configuration using sudo
            import tempfile
            with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
                tmp.writelines(new_content)
                tmp_path = tmp.name

            # Move with sudo
            if self.password is None:
                raise PermissionError("Need root access to save saned.conf")

            cmd = ['sudo', '-S', 'mv', tmp_path, saned_conf_path]
            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=10)

            if result.returncode != 0:
                raise PermissionError(f"Failed to save saned.conf: {result.stderr}")

            # Set proper permissions
            cmd = ['sudo', '-S', 'chmod', '644', saned_conf_path]
            subprocess.run(cmd, input=f"{self.password}\n",
                           capture_output=True, text=True, timeout=10)

            return True

        except Exception as e:
            messagebox.showerror("Error", f"Error saving scanner subnets: {str(e)}")
            return False

    def apply_scanner_settings(self):
        """Apply scanner subnet settings"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            # Get subnets from text area
            subnets_text = self.scanner_subnets_text.get(1.0, tk.END).strip()
            subnets = [s.strip() for s in subnets_text.split('\n') if s.strip()]

            # Validate subnets
            for subnet in subnets:
                if not re.match(r'^\d+\.\d+\.\d+\.\d+(\/\d+)?$', subnet):
                    messagebox.showerror("Error", f"Invalid subnet format: {subnet}")
                    return

            # Save subnets
            if self.save_scanner_subnet(subnets):
                # Restart saned service if we have subnets
                if subnets:
                    self.manage_service('xinetd', 'restart')

                messagebox.showinfo("Success", "Scanner settings applied successfully")
                self.refresh_scanner_subnets()
            else:
                messagebox.showerror("Error", "Failed to save scanner subnets")

        except Exception as e:
            messagebox.showerror("Error", f"Error applying scanner settings: {str(e)}")

    def apply_printer_settings(self):
        """Apply printer settings (CUPS configuration)"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            # Modify CUPS configuration
            if self.modify_cups_config(self.cups_remote_var.get()):
                # Restart CUPS service
                self.manage_service('cupsd', 'restart')

                messagebox.showinfo("Success", "Printer settings applied successfully")
                self.check_cups_status()
            else:
                messagebox.showerror("Error", "Failed to apply CUPS configuration")

        except Exception as e:
            messagebox.showerror("Error", f"Error applying printer settings: {str(e)}")

    def authenticate(self, event=None):
        """Authenticate with root password"""
        password = self.password_entry.get().strip()

        if not password:
            messagebox.showerror("Error", "Please enter the root password")
            return

        # Test the password by trying to run a command with sudo
        try:
            result = subprocess.run(['sudo', '-S', 'echo', 'test'],
                                    input=f"{password}\n", capture_output=True, text=True, timeout=5)

            if result.returncode == 0:
                self.password = password
                self.auth_status.config(text="Authenticated", foreground="green")
                self.password_entry.config(state="disabled")

                # Enable all tabs
                for i in range(1, 6):  # Tabs 1, 2, 3, 4, 5
                    self.notebook.tab(i, state="normal")

                messagebox.showinfo("Success", "Authentication successful! All tabs are now enabled.")

                # Refresh services and status after authentication
                self.refresh_scanner_services()
                self.refresh_printer_services()
                self.check_cups_status()
                self.refresh_connections_list()
                self.refresh_usbip_service_status()  # NEW: Refresh USB/IP status
                self.refresh_usbip_devices()  # NEW: Refresh USB devices list

            else:
                self.auth_status.config(text="Authentication failed", foreground="red")
                messagebox.showerror("Error", "Authentication failed. Please check the root password.")

        except Exception as e:
            self.auth_status.config(text="Authentication error", foreground="red")
            messagebox.showerror("Error", f"Authentication error: {str(e)}")

    def configure_network(self):
        """Configure network interface using nmcli commands"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            interface = self.interface_var.get()
            if not interface:
                messagebox.showerror("Error", "Please select a network interface")
                return

            config_type = self.config_type.get()

            if config_type == "static":
                ip = self.ip_entry.get().strip()
                subnet = self.subnet_entry.get().strip()
                gateway = self.gateway_entry.get().strip()
                dns = self.dns_entry.get().strip()

                if not all([ip, subnet, gateway]):
                    messagebox.showerror("Error", "Please fill in all required network fields for static configuration")
                    return

                # Convert subnet mask to CIDR
                cidr = self.subnet_to_cidr(subnet)

                # Use nmcli to configure static IP
                commands = [
                    f"sudo nmcli connection delete '{interface}' 2>/dev/null || true",  # Remove existing connection
                    f"sudo nmcli connection add type ethernet con-name '{interface}' ifname '{interface}'",
                    f"sudo nmcli connection modify '{interface}' ipv4.addresses {ip}/{cidr}",
                    f"sudo nmcli connection modify '{interface}' ipv4.gateway {gateway}",
                    f"sudo nmcli connection modify '{interface}' ipv4.method manual",
                    f"sudo nmcli connection up '{interface}'"
                ]

                # Add DNS if provided
                if dns:
                    dns_servers = dns.replace(',', ' ')
                    commands.insert(-1, f"sudo nmcli connection modify '{interface}' ipv4.dns '{dns_servers}'")

                # Execute commands
                for cmd in commands:
                    result = subprocess.run(cmd, shell=True, input=f"{self.password}\n",
                                            capture_output=True, text=True, timeout=30)
                    if result.returncode != 0 and "connection with uuid" not in result.stderr:
                        # Ignore errors about connection not existing for delete command
                        if "delete" not in cmd or "2>/dev/null" not in cmd:
                            messagebox.showerror("Error", f"Failed to configure network: {result.stderr}")
                            return

                messagebox.showinfo("Success", f"Network interface {interface} configured successfully with static IP")

            else:  # DHCP
                # Use nmcli to configure DHCP
                commands = [
                    f"sudo nmcli connection delete '{interface}' 2>/dev/null || true",  # Remove existing connection
                    f"sudo nmcli connection add type ethernet con-name '{interface}' ifname '{interface}'",
                    f"sudo nmcli connection modify '{interface}' ipv4.method auto",
                    f"sudo nmcli connection up '{interface}'"
                ]

                for cmd in commands:
                    result = subprocess.run(cmd, shell=True, input=f"{self.password}\n",
                                            capture_output=True, text=True, timeout=30)
                    if result.returncode != 0 and "connection with uuid" not in result.stderr:
                        # Ignore errors about connection not existing for delete command
                        if "delete" not in cmd or "2>/dev/null" not in cmd:
                            messagebox.showerror("Error", f"Failed to configure network: {result.stderr}")
                            return

                messagebox.showinfo("Success", f"Network interface {interface} configured successfully with DHCP")

            # Refresh interface details to show new configuration
            self.root.after(2000, self.refresh_interfaces)  # Wait a bit for changes to take effect

        except Exception as e:
            messagebox.showerror("Error", f"Error configuring network: {str(e)}")

    def subnet_to_cidr(self, subnet):
        """Convert subnet mask to CIDR notation"""
        try:
            # Count the number of 1 bits in the subnet mask
            return sum(bin(int(x)).count('1') for x in subnet.split('.'))
        except:
            return 24  # Default to /24 if conversion fails
## USB OVER NET
    def setup_usbip_tab(self):
        """USB over Network tab for USB/IP device sharing"""
        frame = ttk.LabelFrame(self.usbip_frame, text="USB over Network (USB/IP) Configuration", padding="15")
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # USB/IP Service Management
        service_frame = ttk.LabelFrame(frame, text="USB/IP Service Management", padding="10")
        service_frame.pack(fill=tk.X, padx=5, pady=5)

        service_controls_frame = ttk.Frame(service_frame)
        service_controls_frame.pack(fill=tk.X, pady=5)

        ttk.Label(service_controls_frame, text="USB/IP Daemon:", font=('Arial', 9, 'bold')).pack(side=tk.LEFT,
                                                                                                 padx=(0, 10))

        ttk.Button(service_controls_frame, text="Start",
                   command=lambda: self.manage_usbip_service('start')).pack(side=tk.LEFT, padx=2)
        ttk.Button(service_controls_frame, text="Restart",
                   command=lambda: self.manage_usbip_service('restart')).pack(side=tk.LEFT, padx=2)
        ttk.Button(service_controls_frame, text="Enable",
                   command=lambda: self.manage_usbip_service('enable')).pack(side=tk.LEFT, padx=2)

        self.usbip_service_status = ttk.Label(service_controls_frame, text="Checking service status...")
        self.usbip_service_status.pack(side=tk.LEFT, padx=(10, 0))

        # USB Devices List
        devices_frame = ttk.LabelFrame(frame, text="Available USB Devices", padding="10")
        devices_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # Create treeview for USB devices
        columns = ("Bus ID", "Description", "Status")
        self.usb_tree = ttk.Treeview(devices_frame, columns=columns, show="headings", height=8)

        # Define headings
        self.usb_tree.heading("Bus ID", text="Bus ID")
        self.usb_tree.heading("Description", text="Description")
        self.usb_tree.heading("Status", text="Status")

        # Set column widths
        self.usb_tree.column("Bus ID", width=80, minwidth=70)
        self.usb_tree.column("Description", width=350, minwidth=300)
        self.usb_tree.column("Status", width=100, minwidth=80)

        # Add scrollbar
        scrollbar = ttk.Scrollbar(devices_frame, orient=tk.VERTICAL, command=self.usb_tree.yview)
        self.usb_tree.configure(yscrollcommand=scrollbar.set)

        # Pack treeview and scrollbar
        self.usb_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # Device controls frame
        controls_frame = ttk.Frame(devices_frame)
        controls_frame.pack(fill=tk.X, pady=10)

        # Initialize the action button FIRST
        self.usb_action_button = ttk.Button(controls_frame, text="Select a device",
                                            command=self.toggle_usb_device_binding,
                                            state="disabled")
        self.usb_action_button.pack(side=tk.LEFT, padx=5)

        ttk.Button(controls_frame, text="Refresh Devices List",
                   command=self.refresh_usbip_devices).pack(side=tk.LEFT, padx=5)

        # Bind selection event AFTER creating the button
        self.usb_tree.bind('<<TreeviewSelect>>', self.on_usb_device_select)

        # Status and information
        info_frame = ttk.LabelFrame(frame, text="Information", padding="10")
        info_frame.pack(fill=tk.X, padx=5, pady=5)

        info_text = """USB/IP allows sharing USB devices over the network.
    • Select a device to see available actions
    • Bind a device to make it available over the network
    • Unbind a device to stop sharing it
    • The USB/IP daemon must be running for devices to be accessible
    • Use 'usbip list -r <server_ip>' on client machines to see shared devices"""

        self.info_label = ttk.Label(info_frame, text=info_text, justify=tk.LEFT,
                                    background='#f5f5f5', relief=tk.SUNKEN, padding=5)
        self.info_label.pack(fill=tk.X)

        self.usbip_status = ttk.Label(frame, text="")
        self.usbip_status.pack(pady=5)

    def setup_usbip_tab(self):
        """USB over Network tab for USB/IP device sharing"""
        frame = ttk.LabelFrame(self.usbip_frame, text="USB over Network (USB/IP) Configuration", padding="15")
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # USB/IP Service Management
        service_frame = ttk.LabelFrame(frame, text="USB/IP Service Management", padding="10")
        service_frame.pack(fill=tk.X, padx=5, pady=5)

        service_controls_frame = ttk.Frame(service_frame)
        service_controls_frame.pack(fill=tk.X, pady=5)

        ttk.Label(service_controls_frame, text="USB/IP Daemon:", font=('Arial', 9, 'bold')).pack(side=tk.LEFT,
                                                                                                 padx=(0, 10))

        ttk.Button(service_controls_frame, text="Start",
                   command=lambda: self.manage_usbip_service('start')).pack(side=tk.LEFT, padx=2)
        ttk.Button(service_controls_frame, text="Restart",
                   command=lambda: self.manage_usbip_service('restart')).pack(side=tk.LEFT, padx=2)
        ttk.Button(service_controls_frame, text="Enable",
                   command=lambda: self.manage_usbip_service('enable')).pack(side=tk.LEFT, padx=2)

        self.usbip_service_status = ttk.Label(service_controls_frame, text="Checking service status...")
        self.usbip_service_status.pack(side=tk.LEFT, padx=(10, 0))

        # USB Devices List - MAIN FRAME
        devices_main_frame = ttk.LabelFrame(frame, text="Available USB Devices", padding="10")
        devices_main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # Treeview frame (takes most space)
        tree_frame = ttk.Frame(devices_main_frame)
        tree_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))

        # Create treeview for USB devices
        columns = ("Bus ID", "Description", "Status")
        self.usb_tree = ttk.Treeview(tree_frame, columns=columns, show="headings", height=8)

        # Define headings
        self.usb_tree.heading("Bus ID", text="Bus ID")
        self.usb_tree.heading("Description", text="Description")
        self.usb_tree.heading("Status", text="Status")

        # Set column widths
        self.usb_tree.column("Bus ID", width=80, minwidth=70)
        self.usb_tree.column("Description", width=350, minwidth=300)
        self.usb_tree.column("Status", width=100, minwidth=80)

        # Add scrollbar
        scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=self.usb_tree.yview)
        self.usb_tree.configure(yscrollcommand=scrollbar.set)

        # Pack treeview and scrollbar
        self.usb_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # Device controls frame - NOW AT BOTTOM
        controls_frame = ttk.Frame(devices_main_frame)
        controls_frame.pack(fill=tk.X, pady=5)

        # Initialize the action button
        self.usb_action_button = ttk.Button(controls_frame, text="Select a device",
                                            command=self.toggle_usb_device_binding,
                                            state="disabled")
        self.usb_action_button.pack(side=tk.LEFT, padx=5)

        ttk.Button(controls_frame, text="Refresh Devices List",
                   command=self.refresh_usbip_devices).pack(side=tk.LEFT, padx=5)

        # Add debug button (optional, can remove later)
        ttk.Button(controls_frame, text="Debug Info",
                   command=self.debug_usbip_status).pack(side=tk.LEFT, padx=5)

        # Bind selection event
        self.usb_tree.bind('<<TreeviewSelect>>', self.on_usb_device_select)

        # Status and information
        info_frame = ttk.LabelFrame(frame, text="Information", padding="10")
        info_frame.pack(fill=tk.X, padx=5, pady=5)

        info_text = """USB/IP allows sharing USB devices over the network.
    • Select a device to see available actions
    • Bind a device to make it available over the network
    • Unbind a device to stop sharing it
    • The USB/IP daemon must be running for devices to be accessible
    • Use 'usbip list -r <server_ip>' on client machines to see shared devices"""

        self.info_label = ttk.Label(info_frame, text=info_text, justify=tk.LEFT,
                                    background='#f5f5f5', relief=tk.SUNKEN, padding=5)
        self.info_label.pack(fill=tk.X)

        self.usbip_status = ttk.Label(frame, text="")
        self.usbip_status.pack(pady=5)

    def on_usb_device_select(self, event):
        """Update the action button based on selected device status"""
        # Safety check - ensure button exists
        if not hasattr(self, 'usb_action_button'):
            return

        selection = self.usb_tree.selection()
        if not selection:
            self.usb_action_button.config(text="Select a device", state="disabled")
            return

        item = self.usb_tree.item(selection[0])
        values = item['values']

        if not values or len(values) < 3 or values[0] in ["Error", "No devices"]:
            self.usb_action_button.config(text="Select a device", state="disabled")
            return

        # Update button based on device status
        status = values[2]  # Status is now in the 3rd column (index 2)
        # CHANGE: Button shows "Unbind Device" when status is "Bind", and "Bind Device" when status is "Not Bind"
        if status == "Bind":
            self.usb_action_button.config(text="Unbind Device", state="normal")
        elif status == "Not Bind":
            self.usb_action_button.config(text="Bind Device", state="normal")
        else:
            self.usb_action_button.config(text="Select a device", state="disabled")

    def toggle_usb_device_binding(self):
        """Toggle binding/unbinding based on current device status"""
        # Safety check - ensure button exists
        if not hasattr(self, 'usb_action_button'):
            return

        selection = self.usb_tree.selection()
        if not selection:
            return

        item = self.usb_tree.item(selection[0])
        values = item['values']

        if not values or len(values) < 3 or values[0] in ["Error", "No devices"]:
            return

        busid = values[0]
        current_status = values[2]

        # CHANGE: Check for "Bind" and "Not Bind" instead of "Bound" and "Available"
        if current_status == "Bind":
            self.unbind_usb_device()
        elif current_status == "Not Bind":
            self.bind_usb_device()

    def refresh_usbip_service_status(self):
        """Check and display USB/IP service status"""
        try:
            # Check if service is running
            running = self.check_service_status('usbipd')

            # Check if service is enabled
            enabled = self.check_service_enabled('usbipd')

            status_text = f"Status: {'Running' if running else 'Stopped'} | "
            status_text += f"Enabled: {'Yes' if enabled else 'No'}"

            self.usbip_service_status.config(
                text=status_text,
                foreground="green" if running else "red"
            )

        except Exception as e:
            self.usbip_service_status.config(
                text=f"Error checking status: {str(e)}",
                foreground="red"
            )

    def manage_usbip_service(self, action):
        """Manage USB/IP service"""
        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            if action == 'enable':
                cmd = ['sudo', '-S', 'rc-update', 'add', 'usbipd']
            elif action == 'disable':
                cmd = ['sudo', '-S', 'rc-update', 'del', 'usbipd']
            else:
                cmd = ['sudo', '-S', 'rc-service', 'usbipd', action]

            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=30)

            if result.returncode == 0:
                messagebox.showinfo("Success", f"USB/IP service {action}ed successfully")
                self.refresh_usbip_service_status()

                # If starting/restarting, refresh devices list
                if action in ['start', 'restart']:
                    self.root.after(1000, self.refresh_usbip_devices)
            else:
                error_msg = result.stderr
                if "not found" in error_msg:
                    error_msg = "USB/IP service not installed. Please install usbip package."
                messagebox.showerror("Error", f"Failed to {action} USB/IP service: {error_msg}")

        except Exception as e:
            messagebox.showerror("Error", f"Error managing USB/IP service: {str(e)}")

    def debug_usbip_status(self):
        """Debug method to check USB/IP status"""
        try:
            print("=== USB/IP DEBUG INFO ===")

            # Check usbip list -l
            result = subprocess.run(['usbip', 'list', '-l'], capture_output=True, text=True)
            print("usbip list -l output:")
            print(result.stdout)

            # Check usbip list -p
            result = subprocess.run(['usbip', 'list', '-p'], capture_output=True, text=True)
            print("usbip list -p output:")
            print(result.stdout)

            # Check bound devices in sysfs
            usbip_driver_path = '/sys/bus/usb/drivers/usbip/'
            if os.path.exists(usbip_driver_path):
                print(f"USB/IP driver path exists. Contents: {os.listdir(usbip_driver_path)}")
            else:
                print("USB/IP driver path not found")

            print("=== END DEBUG ===")

        except Exception as e:
            print(f"Debug error: {e}")

    def refresh_usbip_devices(self):
        """Refresh the list of USB devices"""
        try:
            # Clear existing items
            for item in self.usb_tree.get_children():
                self.usb_tree.delete(item)

            # Reset action button with safety check
            if hasattr(self, 'usb_action_button'):
                self.usb_action_button.config(text="Select a device", state="disabled")

            # Get list of USB devices
            result = subprocess.run(['usbip', 'list', '-l'],
                                    capture_output=True, text=True, timeout=10)

            if result.returncode != 0:
                self.usb_tree.insert("", "end", values=("Error", "Failed to list USB devices", ""))
                self.usbip_status.config(text="Failed to list USB devices", foreground="red")
                return

            devices = self.parse_usbip_list(result.stdout)

            if not devices:
                self.usb_tree.insert("", "end", values=("No devices", "No USB devices found", ""))
                self.usbip_status.config(text="No USB devices found", foreground="orange")
                return

            # Get list of bound devices to show status
            bound_devices = self.get_bound_usb_devices()
            print(f"DEBUG: Refresh - Bound devices: {bound_devices}")

            for device in devices:
                busid = device.get('busid', 'Unknown')
                description = device.get('description', 'No description')

                # Double-check each device's binding status
                is_bound = busid in bound_devices
                if is_bound:
                    # Verify it's actually bound
                    is_bound = self.verify_device_binding(busid)

                status = "Bind" if is_bound else "Not Bind"

                print(f"DEBUG: Device {busid} -> {status}")

                # Insert with only 3 columns: Bus ID, Description, Status
                self.usb_tree.insert("", "end", values=(busid, description, status))

            self.usbip_status.config(text=f"Found {len(devices)} USB device(s)", foreground="green")

        except FileNotFoundError:
            self.usb_tree.insert("", "end", values=("Error", "usbip command not found", ""))
            self.usbip_status.config(text="USB/IP tools not installed", foreground="red")
        except Exception as e:
            self.usb_tree.insert("", "end", values=("Error", f"Failed to list devices: {str(e)}", ""))
            self.usbip_status.config(text=f"Error: {str(e)}", foreground="red")

    def parse_usbip_list(self, output):
        """Parse the output of 'usbip list -l' command"""
        devices = []
        current_device = {}

        for line in output.split('\n'):
            line = line.strip()

            # Look for busid lines with format: " - busid 1-1 (1b1c:2b08)"
            if line.startswith('- busid'):
                if current_device:
                    devices.append(current_device)
                    current_device = {}

                # Extract busid - format: " - busid 1-1 (1b1c:2b08)"
                busid_match = re.search(r'busid\s+(\S+)\s+\(([^)]+)\)', line)
                if busid_match:
                    current_device['busid'] = busid_match.group(1)
                    vendor_device = busid_match.group(2)
                    if ':' in vendor_device:
                        vendor, device_id = vendor_device.split(':', 1)
                        current_device['vendor'] = vendor
                        current_device['device'] = device_id

            # Look for description lines with format: "   Corsair : unknown product (1b1c:2b08)"
            elif line and not line.startswith('-') and line:
                # Remove any trailing vendor:device in parentheses and extra spaces
                clean_line = re.sub(r'\s*\([^)]+\)\s*$', '', line).strip()
                # Remove leading spaces
                clean_line = re.sub(r'^\s+', '', clean_line)
                if clean_line:
                    current_device['description'] = clean_line

        # Add the last device
        if current_device:
            devices.append(current_device)

        return devices

    def get_bound_usb_devices(self):
        """Get list of currently bound USB devices"""
        try:
            bound_devices = []

            # Method 1: Check usbip list -p output for bound devices
            result = subprocess.run(['usbip', 'list', '-p'],
                                    capture_output=True, text=True, timeout=10)

            if result.returncode == 0:
                print(f"DEBUG: usbip list -p output:\n{result.stdout}")  # Debug
                for line in result.stdout.split('\n'):
                    line = line.strip()
                    # Look for lines that contain bound devices - they typically have (usbip) marker
                    if line and 'busid:' in line:
                        # Check if this device is bound by looking for (usbip) marker
                        if '(usbip)' in line:
                            # Extract busid from "busid: 1-1 (05ac:024f) (usbip)"
                            busid_match = re.search(r'busid:\s*(\S+?)(?:\s|$)', line)
                            if busid_match:
                                busid = busid_match.group(1)
                                bound_devices.append(busid)
                                print(f"DEBUG: Found bound device in list -p: {busid}")  # Debug

            # Method 2: Check exported devices on localhost
            if not bound_devices:
                try:
                    result = subprocess.run(['usbip', 'list', '-r', 'localhost'],
                                            capture_output=True, text=True, timeout=10)
                    if result.returncode == 0:
                        print(f"DEBUG: usbip list -r localhost output:\n{result.stdout}")  # Debug
                        for line in result.stdout.split('\n'):
                            line = line.strip()
                            if line and ':' in line and not line.startswith('-'):
                                # Format: "1-1: Some Device Description"
                                parts = line.split(':', 1)
                                if len(parts) > 0:
                                    busid = parts[0].strip()
                                    if busid and busid not in bound_devices:
                                        bound_devices.append(busid)
                                        print(f"DEBUG: Found bound device in list -r: {busid}")  # Debug
                except Exception as e:
                    print(f"DEBUG: Error checking localhost exports: {e}")

            # Method 3: Check sysfs for bound devices
            if not bound_devices:
                try:
                    usbip_driver_path = '/sys/bus/usb/drivers/usbip/'
                    if os.path.exists(usbip_driver_path):
                        for item in os.listdir(usbip_driver_path):
                            # Bound devices appear as directories like "1-1", "2-1", etc.
                            if re.match(r'^\d+-\d+(\.\d+)*$', item):
                                bound_devices.append(item)
                                print(f"DEBUG: Found bound device in sysfs: {item}")  # Debug
                except Exception as e:
                    print(f"DEBUG: Error checking sysfs: {e}")

            print(f"DEBUG: Final bound devices list: {bound_devices}")  # Debug
            return bound_devices

        except Exception as e:
            print(f"Error getting bound devices: {e}")
            return []

    def verify_device_binding(self, busid):
        """Verify if a device is actually bound by checking multiple methods"""
        try:
            # Method 1: Check usbip list -p
            result = subprocess.run(['usbip', 'list', '-p'],
                                    capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                for line in result.stdout.split('\n'):
                    if busid in line and '(usbip)' in line:
                        return True

            # Method 2: Check localhost exports
            result = subprocess.run(['usbip', 'list', '-r', 'localhost'],
                                    capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                for line in result.stdout.split('\n'):
                    if line.strip().startswith(busid + ':'):
                        return True

            # Method 3: Check sysfs
            usbip_driver_path = f'/sys/bus/usb/drivers/usbip/{busid}'
            if os.path.exists(usbip_driver_path):
                return True

            return False

        except Exception as e:
            print(f"Error verifying binding for {busid}: {e}")
            return False

    def bind_usb_device(self):
        """Bind the selected USB device"""

        selection = self.usb_tree.selection()
        if not selection:
            messagebox.showwarning("Warning", "Please select a USB device to bind")
            return

        item = self.usb_tree.item(selection[0])
        values = item['values']

        if not values or len(values) < 3 or values[0] in ["Error", "No devices"]:
            messagebox.showwarning("Warning", "Please select a valid USB device")
            return

        busid = values[0]

        # First check if device is already bound
        if self.verify_device_binding(busid):
            messagebox.showinfo("Info", f"Device {busid} is already binded")
            self.refresh_usbip_devices()
            return

        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            # Check if USB/IP service is running
            if not self.check_service_status('usbipd'):
                response = messagebox.askyesno(
                    "USB/IP Service Not Running",
                    "USB/IP service is not running. The device binding may not work properly.\n"
                    "Do you want to start the USB/IP service now?"
                )
                if response:
                    self.manage_usbip_service('start')
                    # Wait a moment for service to start
                    self.root.after(2000, lambda: self.perform_bind(busid))
                    return
                else:
                    messagebox.showinfo("Info", "Binding attempted without service running")

            self.perform_bind(busid)

        except Exception as e:
            messagebox.showerror("Error", f"Error binding USB device: {str(e)}")

    def unbind_usb_device(self):
        """Unbind the selected USB device"""
        selection = self.usb_tree.selection()
        if not selection:
            messagebox.showwarning("Warning", "Please select a USB device to unbind")
            return

        item = self.usb_tree.item(selection[0])
        values = item['values']

        if not values or len(values) < 3 or values[0] in ["Error", "No devices"]:
            messagebox.showwarning("Warning", "Please select a valid USB device")
            return

        busid = values[0]

        # CHANGE: Check for "Not Bind" instead of "Available"
        if values[2] == "Not Bind":
            messagebox.showinfo("Info", f"Device {busid} is not binded")
            return

        try:
            if self.password is None:
                messagebox.showerror("Authentication Required",
                                     "Please authenticate first in the Authentication tab.")
                return

            # Unbind the device
            cmd = ['sudo', '-S', 'usbip', 'unbind', '-b', busid]
            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=10)

            if result.returncode == 0:
                messagebox.showinfo("Success", f"USB device {busid} unbinded successfully")
                self.refresh_usbip_devices()
            else:
                error_msg = result.stderr
                if "not bound" in error_msg.lower():
                    messagebox.showinfo("Info", f"Device {busid} is not binded")
                elif "not found" in error_msg.lower():
                    messagebox.showerror("Error", f"Device {busid} not found")
                else:
                    messagebox.showerror("Error", f"Failed to unbind device {busid}: {error_msg}")

                # Refresh anyway to update status
                self.refresh_usbip_devices()

        except Exception as e:
            messagebox.showerror("Error", f"Error unbinding USB device: {str(e)}")


    def perform_bind(self, busid):
        """Perform the actual device binding"""
        try:
            print(f"DEBUG: Performing bind for device: {busid}")

            # Bind the device
            cmd = ['sudo', '-S', 'usbip', 'bind', '-b', busid]
            result = subprocess.run(cmd, input=f"{self.password}\n",
                                    capture_output=True, text=True, timeout=10)

            print(f"DEBUG: Bind command result: returncode={result.returncode}")
            print(f"DEBUG: Bind stdout: {result.stdout}")
            print(f"DEBUG: Bind stderr: {result.stderr}")

            if result.returncode == 0:
                # Verify the binding actually worked
                if self.verify_device_binding(busid):
                    messagebox.showinfo("Success", f"USB device {busid} binded successfully")
                else:
                    messagebox.showwarning("Warning",
                                           f"Device {busid} binding command succeeded but device is not showing as bound.")
                self.refresh_usbip_devices()
            else:
                error_msg = result.stderr
                if "already bound" in error_msg:
                    messagebox.showinfo("Info", f"Device {busid} is already binded")
                    self.refresh_usbip_devices()
                else:
                    messagebox.showerror("Error", f"Failed to bind device {busid}: {error_msg}")

        except Exception as e:
            messagebox.showerror("Error", f"Error binding USB device: {str(e)}")

def main():
    # Check if running as root (warn if yes)
    if os.geteuid() == 0:
        if not messagebox.askyesno("Warning",
                                   "You are already running as root.\n"
                                   "This application is designed to elevate privileges.\n"
                                   "Continue anyway?"):
            sys.exit()

    root = tk.Tk()
    app = FirstBootApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()
