/**
 * ./src/classes/keyboards.ts
 * penguins-eggs v.25.7.x / ecmascript 2020
 * author: Piero Proietti (modified)
 * email: piero.proietti@gmail.com
 * license: MIT
 */
import fs from 'node:fs';
import { exec } from '../lib/utils.js';
/**
 * Keyboard class - reads and manages X11 keyboard configuration
 */
export default class Keyboard {
    layouts = []; // New change #1: store typed objects instead of raw strings
    models = []; // New change #1
    options = []; // New change #1
    variants = []; // New change #1
    defaultKeyboardFile = '/etc/default/keyboard'; // New change #2: store default keyboard file path
    xorgLstFile = '/usr/share/X11/xkb/rules/xorg.lst';
    constructor() {
        // New change #3: Use a safer approach to read xorg.lst
        if (fs.existsSync(this.xorgLstFile)) {
            const content = fs.readFileSync(this.xorgLstFile, 'utf8');
            this.parseXorgLst(content);
        }
        else {
            this.setDefaults();
        }
    }
    // Get current layout
    async getLayout() {
        const layout = await this.readKeyboardConfig('XKBLAYOUT');
        return layout || 'us';
    }
    // Get all layouts
    getLayouts() {
        return this.layouts;
    }
    // Get current model
    async getModel() {
        const model = await this.readKeyboardConfig('XKBMODEL');
        return model || 'pc105';
    }
    // Get all models
    getModels() {
        return this.models;
    }
    // Get current option
    async getOption() {
        return await this.readKeyboardConfig('XKBOPTIONS');
    }
    // Get all options
    getOptions() {
        return this.options;
    }
    // Get current variant
    async getVariant() {
        return await this.readKeyboardConfig('XKBVARIANT');
    }
    // Get variants for a specific layout
    getVariants(layout) {
        return this.variants.filter((v) => v.lang === layout);
    }
    // New change #4: parse xorg.lst with regex instead of fixed slicing
    parseXorgLst(content) {
        const sections = ['model', 'layout', 'variant', 'option'];
        let currentSection = null;
        for (let line of content.split('\n')) {
            line = line.trim();
            if (!line)
                continue;
            if (line.startsWith('!')) {
                const sectionName = line.slice(2).toLowerCase();
                if (sections.includes(sectionName)) {
                    currentSection = sectionName;
                }
                else {
                    currentSection = null;
                }
                continue;
            }
            if (!currentSection)
                continue;
            // Separate code and description with regex
            const match = line.match(/^(\S+)\s+(.*)$/);
            if (!match)
                continue;
            const [_, code, description] = match;
            const desc = description || '';
            switch (currentSection) {
                case 'layout': {
                    this.layouts.push({ code, description: desc });
                    break;
                }
                case 'model': {
                    this.models.push({ code, description: desc });
                    break;
                }
                case 'option': {
                    this.options.push({ code, description: desc });
                    break;
                }
                case 'variant': {
                    // Extract language if possible
                    const langMatch = desc.match(/^(\S+):\s*(.*)$/);
                    this.variants.push({
                        code,
                        description: langMatch ? langMatch[2] : desc,
                        lang: langMatch ? langMatch[1] : ''
                    });
                    break;
                }
            }
        }
    }
    // New change #6: read keyboard configuration from file safely
    async readKeyboardConfig(variable) {
        if (!fs.existsSync(this.defaultKeyboardFile))
            return '';
        try {
            const cmd = `grep ^${variable}= ${this.defaultKeyboardFile} | cut -d= -f2 | tr -d '"'`;
            const result = await exec(cmd, { capture: true, echo: false, ignore: false });
            if (result.code === 0) {
                return result.data.trim();
            }
            return '';
        }
        catch {
            return '';
        }
    }
    // New change #5: set default keyboard data if xorg.lst not found
    setDefaults() {
        this.models.push({ code: 'pc105', description: 'Generic 105-key PC' });
        const defaultLayouts = ['us', 'fr', 'de', 'gb', 'es', 'it', 'ru', 'jp']; // shortened for example
        for (const l of defaultLayouts)
            this.layouts.push({ code: l, description: '' });
        this.variants.push({ code: 'none', description: 'none', lang: '' });
        this.options.push({ code: 'none', description: 'none' });
    }
}
