ui_device-settings.js

/**
 * DeviceSettings - UI component for configuring device-specific parameters
 * This component allows users to configure and save parameters specific
 * to their GNSS device.
 */
export class DeviceSettings {
  /**
   * Create a device settings component
   * @param {Object} options - Configuration options
   * @param {EventEmitter} options.events - Event emitter for communication
   * @param {Settings} options.settings - Settings manager
   * @param {string} options.selector - CSS selector for the container element
   */
  constructor(options = {}) {
    this.events = options.events;
    this.settings = options.settings;
    this.deviceConnected = false;
    
    // Find container element if selector provided
    if (options.selector) {
      this.container = document.querySelector(options.selector);
    }
    
    // If no container, don't initialize UI
    if (!this.container) {
      console.warn('DeviceSettings: No container element found. UI will not be initialized.');
      return;
    }
    
    // Cache frequently used elements
    this.elements = {};
    
    // Add CSS for styling
    this.addStyles();
    
    // Create UI elements
    this.initializeUI();
    
    // Set up event listeners
    this.setupEventListeners();
    
    // Listen for connection events
    this.registerEventListeners();
    
    // Load saved configuration
    this.loadSavedConfig();
  }

  /**
   * Add required CSS styles to the document
   */
  addStyles() {
    // Check if styles already exist
    if (document.getElementById('device-settings-styles')) {
      return;
    }
    
    // Create style element
    const style = document.createElement('style');
    style.id = 'device-settings-styles';
    style.textContent = `
      .device-settings-container {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
        margin: 0 auto;
        padding: 15px;
        background-color: #f7f7f7;
        border-radius: 5px;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
      }
      
      .device-settings-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 15px;
        padding-bottom: 10px;
        border-bottom: 1px solid #e0e0e0;
      }
      
      .device-settings-title {
        font-size: 18px;
        font-weight: 500;
        margin: 0;
      }
      
      .device-settings-form {
        display: grid;
        grid-gap: 10px;
      }
      
      .form-group {
        display: flex;
        flex-direction: column;
        margin-bottom: 10px;
      }
      
      .form-group label {
        font-size: 14px;
        color: #555;
        margin-bottom: 5px;
      }
      
      .form-group input, .form-group select {
        padding: 8px 10px;
        border: 1px solid #ccc;
        border-radius: 4px;
        font-size: 14px;
      }
      
      .form-group input:focus, .form-group select:focus {
        outline: none;
        border-color: #4285F4;
        box-shadow: 0 0 0 2px rgba(66, 133, 244, 0.25);
      }
      
      .device-settings-actions {
        display: flex;
        justify-content: space-between;
        margin-top: 15px;
      }
      
      .device-presets {
        margin-bottom: 15px;
        padding: 10px;
        background-color: #f0f0f0;
        border-radius: 4px;
      }
      
      .device-presets h4 {
        margin-top: 0;
        margin-bottom: 8px;
      }
      
      .device-status {
        display: flex;
        align-items: center;
        margin-top: 15px;
        padding: 10px;
        background-color: #f0f0f0;
        border-radius: 4px;
      }
      
      .device-status-indicator {
        width: 12px;
        height: 12px;
        border-radius: 50%;
        margin-right: 8px;
      }
      
      .device-status-indicator.disconnected { background-color: #9e9e9e; }
      .device-status-indicator.connected { background-color: #4caf50; }
      
      .device-button {
        padding: 8px 16px;
        border: none;
        border-radius: 4px;
        font-size: 14px;
        font-weight: 500;
        cursor: pointer;
        transition: background-color 0.2s;
      }
      
      .device-button:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }
      
      .device-button.primary {
        background-color: #4285F4;
        color: white;
      }
      
      .device-button.secondary {
        background-color: #f1f1f1;
        color: #333;
      }
      
      .help-text {
        font-size: 12px;
        color: #666;
        margin-top: 3px;
      }
      
      @media (min-width: 768px) {
        .device-settings-form {
          grid-template-columns: 1fr 1fr;
          grid-gap: 15px;
        }
      }
    `;
    
    // Add style to document
    document.head.appendChild(style);
  }

  /**
   * Initialize the UI elements
   */
  initializeUI() {
    if (!this.container) return;
    
    // Clear container
    this.container.innerHTML = '';
    
    // Create main container
    const settingsContainer = document.createElement('div');
    settingsContainer.className = 'device-settings-container';
    
    // Create header
    const header = document.createElement('div');
    header.className = 'device-settings-header';
    
    const title = document.createElement('h2');
    title.className = 'device-settings-title';
    title.textContent = 'Device Settings';
    
    header.appendChild(title);
    settingsContainer.appendChild(header);
    
    // Device presets section
    const presets = document.createElement('div');
    presets.className = 'device-presets';
    
    const presetsTitle = document.createElement('h4');
    presetsTitle.textContent = 'Device Presets';
    
    const presetsDescription = document.createElement('p');
    presetsDescription.textContent = 'Select your device model to load recommended settings:';
    
    const presetsSelect = document.createElement('select');
    presetsSelect.id = 'device-preset';
    
    // Add common device presets
    const defaultOption = document.createElement('option');
    defaultOption.value = '';
    defaultOption.textContent = '-- Select Device --';
    presetsSelect.appendChild(defaultOption);
    
    const presetUBloxF9P = document.createElement('option');
    presetUBloxF9P.value = 'ublox-f9p';
    presetUBloxF9P.textContent = 'u-blox ZED-F9P';
    presetsSelect.appendChild(presetUBloxF9P);
    
    const presetUBloxM8P = document.createElement('option');
    presetUBloxM8P.value = 'ublox-m8p';
    presetUBloxM8P.textContent = 'u-blox NEO-M8P';
    presetsSelect.appendChild(presetUBloxM8P);
    
    const presetSimpleRTK = document.createElement('option');
    presetSimpleRTK.value = 'simplertk2b';
    presetSimpleRTK.textContent = 'Ardusimple SimpleRTK2B';
    presetsSelect.appendChild(presetSimpleRTK);
    
    const presetCustom = document.createElement('option');
    presetCustom.value = 'custom';
    presetCustom.textContent = 'Custom Device';
    presetsSelect.appendChild(presetCustom);
    
    // Load preset button
    const loadPresetButton = document.createElement('button');
    loadPresetButton.id = 'load-preset';
    loadPresetButton.className = 'device-button secondary';
    loadPresetButton.textContent = 'Load Preset';
    loadPresetButton.style.marginLeft = '10px';
    
    presets.appendChild(presetsTitle);
    presets.appendChild(presetsDescription);
    
    const presetRow = document.createElement('div');
    presetRow.style.display = 'flex';
    presetRow.style.alignItems = 'center';
    presetRow.appendChild(presetsSelect);
    presetRow.appendChild(loadPresetButton);
    
    presets.appendChild(presetRow);
    settingsContainer.appendChild(presets);
    
    // Create form
    const form = document.createElement('form');
    form.className = 'device-settings-form';
    form.id = 'device-settings-form';
    
    // Device name
    const deviceNameGroup = document.createElement('div');
    deviceNameGroup.className = 'form-group';
    
    const deviceNameLabel = document.createElement('label');
    deviceNameLabel.htmlFor = 'device-name';
    deviceNameLabel.textContent = 'Device Name';
    
    const deviceNameInput = document.createElement('input');
    deviceNameInput.type = 'text';
    deviceNameInput.id = 'device-name';
    deviceNameInput.placeholder = 'My GNSS Receiver';
    
    const deviceNameHelp = document.createElement('p');
    deviceNameHelp.className = 'help-text';
    deviceNameHelp.textContent = 'Custom name for this device';
    
    deviceNameGroup.appendChild(deviceNameLabel);
    deviceNameGroup.appendChild(deviceNameInput);
    deviceNameGroup.appendChild(deviceNameHelp);
    
    form.appendChild(deviceNameGroup);
    
    // GNSS Systems
    const gnssSystemsGroup = document.createElement('div');
    gnssSystemsGroup.className = 'form-group';
    
    const gnssSystemsLabel = document.createElement('label');
    gnssSystemsLabel.htmlFor = 'gnss-systems';
    gnssSystemsLabel.textContent = 'GNSS Systems';
    
    const gnssSystemsSelect = document.createElement('select');
    gnssSystemsSelect.id = 'gnss-systems';
    gnssSystemsSelect.multiple = true;
    gnssSystemsSelect.size = 5;
    gnssSystemsSelect.style.height = 'auto';
    
    const gnssGPS = document.createElement('option');
    gnssGPS.value = 'gps';
    gnssGPS.textContent = 'GPS (USA)';
    gnssSystemsSelect.appendChild(gnssGPS);
    
    const gnssGLONASS = document.createElement('option');
    gnssGLONASS.value = 'glonass';
    gnssGLONASS.textContent = 'GLONASS (Russia)';
    gnssSystemsSelect.appendChild(gnssGLONASS);
    
    const gnssGalileo = document.createElement('option');
    gnssGalileo.value = 'galileo';
    gnssGalileo.textContent = 'Galileo (EU)';
    gnssSystemsSelect.appendChild(gnssGalileo);
    
    const gnssBeiDou = document.createElement('option');
    gnssBeiDou.value = 'beidou';
    gnssBeiDou.textContent = 'BeiDou (China)';
    gnssSystemsSelect.appendChild(gnssBeiDou);
    
    const gnssQZSS = document.createElement('option');
    gnssQZSS.value = 'qzss';
    gnssQZSS.textContent = 'QZSS (Japan)';
    gnssSystemsSelect.appendChild(gnssQZSS);
    
    const gnssHelp = document.createElement('p');
    gnssHelp.className = 'help-text';
    gnssHelp.textContent = 'Hold Ctrl/Cmd to select multiple systems';
    
    gnssSystemsGroup.appendChild(gnssSystemsLabel);
    gnssSystemsGroup.appendChild(gnssSystemsSelect);
    gnssSystemsGroup.appendChild(gnssHelp);
    
    form.appendChild(gnssSystemsGroup);
    
    // Baud Rate
    const baudRateGroup = document.createElement('div');
    baudRateGroup.className = 'form-group';
    
    const baudRateLabel = document.createElement('label');
    baudRateLabel.htmlFor = 'baud-rate';
    baudRateLabel.textContent = 'Baud Rate';
    
    const baudRateSelect = document.createElement('select');
    baudRateSelect.id = 'baud-rate';
    
    const baudRates = [4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600];
    baudRates.forEach(rate => {
      const option = document.createElement('option');
      option.value = rate.toString();
      option.textContent = rate.toString();
      if (rate === 115200) {
        option.selected = true;
      }
      baudRateSelect.appendChild(option);
    });
    
    const baudRateHelp = document.createElement('p');
    baudRateHelp.className = 'help-text';
    baudRateHelp.textContent = 'Serial communication speed';
    
    baudRateGroup.appendChild(baudRateLabel);
    baudRateGroup.appendChild(baudRateSelect);
    baudRateGroup.appendChild(baudRateHelp);
    
    form.appendChild(baudRateGroup);
    
    // Output Rate
    const outputRateGroup = document.createElement('div');
    outputRateGroup.className = 'form-group';
    
    const outputRateLabel = document.createElement('label');
    outputRateLabel.htmlFor = 'output-rate';
    outputRateLabel.textContent = 'Output Rate (Hz)';
    
    const outputRateSelect = document.createElement('select');
    outputRateSelect.id = 'output-rate';
    
    const rates = [1, 2, 5, 10, 20];
    rates.forEach(rate => {
      const option = document.createElement('option');
      option.value = rate.toString();
      option.textContent = rate.toString();
      if (rate === 1) {
        option.selected = true;
      }
      outputRateSelect.appendChild(option);
    });
    
    const outputRateHelp = document.createElement('p');
    outputRateHelp.className = 'help-text';
    outputRateHelp.textContent = 'Positioning output frequency';
    
    outputRateGroup.appendChild(outputRateLabel);
    outputRateGroup.appendChild(outputRateSelect);
    outputRateGroup.appendChild(outputRateHelp);
    
    form.appendChild(outputRateGroup);
    
    // Dynamic Model
    const dynamicModelGroup = document.createElement('div');
    dynamicModelGroup.className = 'form-group';
    
    const dynamicModelLabel = document.createElement('label');
    dynamicModelLabel.htmlFor = 'dynamic-model';
    dynamicModelLabel.textContent = 'Dynamic Model';
    
    const dynamicModelSelect = document.createElement('select');
    dynamicModelSelect.id = 'dynamic-model';
    
    const dynamicModels = [
      { value: 'portable', text: 'Portable' },
      { value: 'stationary', text: 'Stationary' },
      { value: 'pedestrian', text: 'Pedestrian' },
      { value: 'automotive', text: 'Automotive' },
      { value: 'sea', text: 'Sea' },
      { value: 'airborne-1g', text: 'Airborne (<1g)' },
      { value: 'airborne-2g', text: 'Airborne (<2g)' },
      { value: 'airborne-4g', text: 'Airborne (<4g)' },
      { value: 'wrist', text: 'Wrist' },
      { value: 'bike', text: 'Bike' }
    ];
    
    dynamicModels.forEach(model => {
      const option = document.createElement('option');
      option.value = model.value;
      option.textContent = model.text;
      if (model.value === 'pedestrian') {
        option.selected = true;
      }
      dynamicModelSelect.appendChild(option);
    });
    
    const dynamicModelHelp = document.createElement('p');
    dynamicModelHelp.className = 'help-text';
    dynamicModelHelp.textContent = 'Optimizes positioning for motion type';
    
    dynamicModelGroup.appendChild(dynamicModelLabel);
    dynamicModelGroup.appendChild(dynamicModelSelect);
    dynamicModelGroup.appendChild(dynamicModelHelp);
    
    form.appendChild(dynamicModelGroup);
    
    // NMEA Sentences
    const nmeaSentencesGroup = document.createElement('div');
    nmeaSentencesGroup.className = 'form-group';
    
    const nmeaSentencesLabel = document.createElement('label');
    nmeaSentencesLabel.htmlFor = 'nmea-sentences';
    nmeaSentencesLabel.textContent = 'NMEA Sentences';
    
    const nmeaSentencesSelect = document.createElement('select');
    nmeaSentencesSelect.id = 'nmea-sentences';
    nmeaSentencesSelect.multiple = true;
    nmeaSentencesSelect.size = 7;
    nmeaSentencesSelect.style.height = 'auto';
    
    const nmeaSentences = [
      { value: 'GGA', text: 'GGA (Position & Fix)' },
      { value: 'RMC', text: 'RMC (Position & Time)' },
      { value: 'GSA', text: 'GSA (DOP & Active Satellites)' },
      { value: 'GSV', text: 'GSV (Satellites in View)' },
      { value: 'VTG', text: 'VTG (Course & Speed)' },
      { value: 'GST', text: 'GST (Position Error)' },
      { value: 'ZDA', text: 'ZDA (Date & Time)' }
    ];
    
    nmeaSentences.forEach(sentence => {
      const option = document.createElement('option');
      option.value = sentence.value;
      option.textContent = sentence.text;
      // Default to GGA, RMC, GSA, and GSV
      if (['GGA', 'RMC', 'GSA', 'GSV'].includes(sentence.value)) {
        option.selected = true;
      }
      nmeaSentencesSelect.appendChild(option);
    });
    
    const nmeaSentencesHelp = document.createElement('p');
    nmeaSentencesHelp.className = 'help-text';
    nmeaSentencesHelp.textContent = 'NMEA messages to output';
    
    nmeaSentencesGroup.appendChild(nmeaSentencesLabel);
    nmeaSentencesGroup.appendChild(nmeaSentencesSelect);
    nmeaSentencesGroup.appendChild(nmeaSentencesHelp);
    
    form.appendChild(nmeaSentencesGroup);
    
    // RTK Settings
    // Elevation mask
    const elevationMaskGroup = document.createElement('div');
    elevationMaskGroup.className = 'form-group';
    
    const elevationMaskLabel = document.createElement('label');
    elevationMaskLabel.htmlFor = 'elevation-mask';
    elevationMaskLabel.textContent = 'Elevation Mask (°)';
    
    const elevationMaskInput = document.createElement('input');
    elevationMaskInput.type = 'number';
    elevationMaskInput.id = 'elevation-mask';
    elevationMaskInput.min = 0;
    elevationMaskInput.max = 60;
    elevationMaskInput.value = 10;
    
    const elevationMaskHelp = document.createElement('p');
    elevationMaskHelp.className = 'help-text';
    elevationMaskHelp.textContent = 'Ignore satellites below this elevation';
    
    elevationMaskGroup.appendChild(elevationMaskLabel);
    elevationMaskGroup.appendChild(elevationMaskInput);
    elevationMaskGroup.appendChild(elevationMaskHelp);
    
    form.appendChild(elevationMaskGroup);
    
    // SNR mask
    const snrMaskGroup = document.createElement('div');
    snrMaskGroup.className = 'form-group';
    
    const snrMaskLabel = document.createElement('label');
    snrMaskLabel.htmlFor = 'snr-mask';
    snrMaskLabel.textContent = 'SNR Mask (dB-Hz)';
    
    const snrMaskInput = document.createElement('input');
    snrMaskInput.type = 'number';
    snrMaskInput.id = 'snr-mask';
    snrMaskInput.min = 0;
    snrMaskInput.max = 50;
    snrMaskInput.value = 35;
    
    const snrMaskHelp = document.createElement('p');
    snrMaskHelp.className = 'help-text';
    snrMaskHelp.textContent = 'Ignore satellites below this signal strength';
    
    snrMaskGroup.appendChild(snrMaskLabel);
    snrMaskGroup.appendChild(snrMaskInput);
    snrMaskGroup.appendChild(snrMaskHelp);
    
    form.appendChild(snrMaskGroup);
    
    settingsContainer.appendChild(form);
    
    // Create device status
    const deviceStatus = document.createElement('div');
    deviceStatus.className = 'device-status';
    
    const deviceStatusIndicator = document.createElement('div');
    deviceStatusIndicator.className = 'device-status-indicator disconnected';
    
    const deviceStatusText = document.createElement('div');
    deviceStatusText.textContent = 'No device connected';
    
    deviceStatus.appendChild(deviceStatusIndicator);
    deviceStatus.appendChild(deviceStatusText);
    
    settingsContainer.appendChild(deviceStatus);
    
    // Create action buttons
    const actions = document.createElement('div');
    actions.className = 'device-settings-actions';
    
    const saveButton = document.createElement('button');
    saveButton.type = 'button';
    saveButton.id = 'save-settings';
    saveButton.className = 'device-button secondary';
    saveButton.textContent = 'Save Settings';
    
    const applyButton = document.createElement('button');
    applyButton.type = 'button';
    applyButton.id = 'apply-settings';
    applyButton.className = 'device-button primary';
    applyButton.textContent = 'Apply to Device';
    applyButton.disabled = true;
    
    actions.appendChild(saveButton);
    actions.appendChild(applyButton);
    
    settingsContainer.appendChild(actions);
    
    // Add to container
    this.container.appendChild(settingsContainer);
    
    // Store references to elements
    this.elements = {
      deviceNameInput,
      presetsSelect,
      loadPresetButton,
      gnssSystemsSelect,
      baudRateSelect,
      outputRateSelect,
      dynamicModelSelect,
      nmeaSentencesSelect,
      elevationMaskInput,
      snrMaskInput,
      saveButton,
      applyButton,
      deviceStatusIndicator,
      deviceStatusText,
      form
    };
  }

  /**
   * Set up UI event listeners
   */
  setupEventListeners() {
    if (!this.elements) {
      console.warn('DeviceSettings: No UI elements found. Event listeners not set up.');
      return;
    }
    
    // Safely add event listener to an element if it exists
    const safeAddListener = (elementKey, eventType, handler) => {
      const element = this.elements[elementKey];
      if (element) {
        element.addEventListener(eventType, handler);
      } else {
        console.warn(`DeviceSettings: Element ${elementKey} not found`);
      }
    };
    
    // Load preset button
    safeAddListener('loadPresetButton', 'click', () => {
      this.loadDevicePreset();
    });
    
    // Save settings button
    safeAddListener('saveButton', 'click', () => {
      this.saveConfig();
    });
    
    // Apply settings button
    safeAddListener('applyButton', 'click', () => {
      this.applySettings();
    });
    
    // Form change event to enable/disable save button
    safeAddListener('form', 'change', () => {
      // Enable save button when any form field changes
      if (this.elements.saveButton) {
        this.elements.saveButton.disabled = false;
      }
    });
  }

  /**
   * Register event listeners for GNSS events
   */
  registerEventListeners() {
    if (!this.events) {
      console.warn('DeviceSettings: No events emitter provided. Settings will not update.');
      return;
    }
    
    // Connection status change events
    this.events.on('connection:connected', this.handleConnected.bind(this));
    this.events.on('connection:disconnected', this.handleDisconnected.bind(this));
  }

  /**
   * Handle connected event
   * @param {Object} data - Event data
   */
  handleConnected(data) {
    this.deviceConnected = true;
    
    this.elements.deviceStatusIndicator.className = 'device-status-indicator connected';
    this.elements.deviceStatusText.textContent = `Connected to ${data.deviceInfo?.name || 'device'}`;
    
    // Enable the apply button
    this.elements.applyButton.disabled = false;
  }

  /**
   * Handle disconnected event
   */
  handleDisconnected() {
    this.deviceConnected = false;
    
    this.elements.deviceStatusIndicator.className = 'device-status-indicator disconnected';
    this.elements.deviceStatusText.textContent = 'No device connected';
    
    // Disable the apply button
    this.elements.applyButton.disabled = true;
  }

  /**
   * Load saved configuration from settings
   */
  loadSavedConfig() {
    if (!this.settings || !this.elements) return;
    
    // Initialize device settings in settings storage if not present
    if (!this.settings.getSection('device')) {
      this.settings.set('device', 'name', '');
      this.settings.set('device', 'gnssSystems', ['gps', 'glonass']);
      this.settings.set('device', 'baudRate', 115200);
      this.settings.set('device', 'outputRate', 1);
      this.settings.set('device', 'dynamicModel', 'pedestrian');
      this.settings.set('device', 'nmeaSentences', ['GGA', 'RMC', 'GSA', 'GSV']);
      this.settings.set('device', 'elevationMask', 10);
      this.settings.set('device', 'snrMask', 35);
      this.settings.set('device', 'preset', '');
    }
    
    const deviceSettings = this.settings.getSection('device');
    
    // Safely set value if the element exists
    const safeSetValue = (elementKey, value, isMultiSelect = false) => {
      const element = this.elements[elementKey];
      if (!element) return;
      
      if (isMultiSelect && Array.isArray(value)) {
        // For multi-select elements, we need to set each option's selected state
        Array.from(element.options).forEach(option => {
          option.selected = value.includes(option.value);
        });
      } else if (element.type === 'checkbox') {
        element.checked = Boolean(value);
      } else {
        element.value = value !== undefined ? value : '';
      }
    };
    
    // Update UI elements
    safeSetValue('deviceNameInput', deviceSettings.name);
    safeSetValue('presetsSelect', deviceSettings.preset);
    safeSetValue('gnssSystemsSelect', deviceSettings.gnssSystems, true);
    safeSetValue('baudRateSelect', deviceSettings.baudRate);
    safeSetValue('outputRateSelect', deviceSettings.outputRate);
    safeSetValue('dynamicModelSelect', deviceSettings.dynamicModel);
    safeSetValue('nmeaSentencesSelect', deviceSettings.nmeaSentences, true);
    safeSetValue('elevationMaskInput', deviceSettings.elevationMask);
    safeSetValue('snrMaskInput', deviceSettings.snrMask);
    
    // Disable save button initially
    if (this.elements.saveButton) {
      this.elements.saveButton.disabled = true;
    }
  }

  /**
   * Save configuration to settings
   */
  saveConfig() {
    if (!this.settings || !this.elements) return;
    
    // Safely get value from an element if it exists
    const safeGetValue = (elementKey, defaultValue = '', isMultiSelect = false) => {
      const element = this.elements[elementKey];
      if (!element) return defaultValue;
      
      if (isMultiSelect) {
        return Array.from(element.selectedOptions).map(option => option.value);
      } else if (element.type === 'checkbox') {
        return element.checked;
      } else if (element.type === 'number') {
        return parseInt(element.value, 10);
      } else {
        return element.value;
      }
    };
    
    // Get values from form
    const config = {
      name: safeGetValue('deviceNameInput', ''),
      preset: safeGetValue('presetsSelect', ''),
      gnssSystems: safeGetValue('gnssSystemsSelect', ['gps'], true),
      baudRate: safeGetValue('baudRateSelect', 115200),
      outputRate: safeGetValue('outputRateSelect', 1),
      dynamicModel: safeGetValue('dynamicModelSelect', 'pedestrian'),
      nmeaSentences: safeGetValue('nmeaSentencesSelect', ['GGA', 'RMC'], true),
      elevationMask: safeGetValue('elevationMaskInput', 10),
      snrMask: safeGetValue('snrMaskInput', 35)
    };
    
    // Save to settings
    for (const [key, value] of Object.entries(config)) {
      this.settings.set('device', key, value);
    }
    
    // Emit settings update event
    if (this.events) {
      this.events.emit('device:settings:update', config);
    }
    
    // Disable save button after saving
    if (this.elements.saveButton) {
      this.elements.saveButton.disabled = true;
    }
    
    // Show confirmation
    alert('Device settings saved successfully!');
  }

  /**
   * Apply settings to the connected device
   */
  async applySettings() {
    if (!this.deviceConnected) {
      alert('No device connected. Please connect a device first.');
      return;
    }
    
    // Get current settings
    const deviceSettings = this.settings.getSection('device');
    
    // Emit event to apply settings to device
    if (this.events) {
      this.events.emit('device:apply:settings', deviceSettings);
    }
    
    // Show confirmation
    alert('Settings are being applied to the device. This may take a moment...');
  }

  /**
   * Load settings from a device preset
   */
  loadDevicePreset() {
    if (!this.elements.presetsSelect) return;
    
    const preset = this.elements.presetsSelect.value;
    if (!preset) {
      alert('Please select a device preset first.');
      return;
    }
    
    let presetSettings = {};
    
    // Define preset configurations
    switch (preset) {
      case 'ublox-f9p':
        presetSettings = {
          name: 'u-blox ZED-F9P',
          gnssSystems: ['gps', 'glonass', 'galileo', 'beidou'],
          baudRate: 115200,
          outputRate: 5,
          dynamicModel: 'pedestrian',
          nmeaSentences: ['GGA', 'RMC', 'GSA', 'GSV', 'VTG', 'GST'],
          elevationMask: 10,
          snrMask: 35
        };
        break;
        
      case 'ublox-m8p':
        presetSettings = {
          name: 'u-blox NEO-M8P',
          gnssSystems: ['gps', 'glonass'],
          baudRate: 115200,
          outputRate: 5,
          dynamicModel: 'pedestrian',
          nmeaSentences: ['GGA', 'RMC', 'GSA', 'GSV', 'VTG'],
          elevationMask: 10,
          snrMask: 35
        };
        break;
        
      case 'simplertk2b':
        presetSettings = {
          name: 'SimpleRTK2B',
          gnssSystems: ['gps', 'glonass', 'galileo', 'beidou'],
          baudRate: 115200,
          outputRate: 5,
          dynamicModel: 'pedestrian',
          nmeaSentences: ['GGA', 'RMC', 'GSA', 'GSV', 'VTG', 'GST'],
          elevationMask: 10,
          snrMask: 35
        };
        break;
        
      case 'custom':
        // Just update the device name field but leave other settings as is
        presetSettings = {
          name: 'Custom GNSS Device'
        };
        break;
        
      default:
        alert('Unknown preset selected.');
        return;
    }
    
    // Apply preset settings to form
    if (this.elements.deviceNameInput && presetSettings.name) {
      this.elements.deviceNameInput.value = presetSettings.name;
    }
    
    // Update GNSS systems
    if (this.elements.gnssSystemsSelect && presetSettings.gnssSystems) {
      const options = this.elements.gnssSystemsSelect.options;
      for (let i = 0; i < options.length; i++) {
        options[i].selected = presetSettings.gnssSystems.includes(options[i].value);
      }
    }
    
    // Update baud rate
    if (this.elements.baudRateSelect && presetSettings.baudRate) {
      this.elements.baudRateSelect.value = presetSettings.baudRate;
    }
    
    // Update output rate
    if (this.elements.outputRateSelect && presetSettings.outputRate) {
      this.elements.outputRateSelect.value = presetSettings.outputRate;
    }
    
    // Update dynamic model
    if (this.elements.dynamicModelSelect && presetSettings.dynamicModel) {
      this.elements.dynamicModelSelect.value = presetSettings.dynamicModel;
    }
    
    // Update NMEA sentences
    if (this.elements.nmeaSentencesSelect && presetSettings.nmeaSentences) {
      const options = this.elements.nmeaSentencesSelect.options;
      for (let i = 0; i < options.length; i++) {
        options[i].selected = presetSettings.nmeaSentences.includes(options[i].value);
      }
    }
    
    // Update elevation mask
    if (this.elements.elevationMaskInput && presetSettings.elevationMask) {
      this.elements.elevationMaskInput.value = presetSettings.elevationMask;
    }
    
    // Update SNR mask
    if (this.elements.snrMaskInput && presetSettings.snrMask) {
      this.elements.snrMaskInput.value = presetSettings.snrMask;
    }
    
    // Enable save button
    if (this.elements.saveButton) {
      this.elements.saveButton.disabled = false;
    }
    
    // Update preset in settings
    this.settings.set('device', 'preset', preset);
    
    // Show confirmation
    alert(`Loaded preset settings for ${presetSettings.name}`);
  }
}

export default DeviceSettings;