"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigManager = exports.ConfigSections = void 0;
const events_1 = require("events");
const fs = require("fs");
const path = require("path");
const LogTypes_1 = require("../common/LogTypes");
const CONFIG_DIR = '/home/pi/.psBroadcastController';
const CONFIG_FILE = 'config.json';
const TEMP_CONFIG_FILE = 'config.tmp';
const BACKUP_DIR = 'backups';
var ConfigSections;
(function (ConfigSections) {
    ConfigSections["Devices"] = "devices";
    ConfigSections["Mappings"] = "mappings";
    ConfigSections["Videohub"] = "videohub";
    ConfigSections["AtemKeySync"] = "atemKeySync";
})(ConfigSections || (exports.ConfigSections = ConfigSections = {}));
class ConfigManager extends events_1.EventEmitter {
    constructor(logger) {
        super();
        this.loaded = false;
        this.backups = [];
        this.logger = logger;
        this.configFilePath = path.join(CONFIG_DIR, CONFIG_FILE);
        this.configFileTempPath = path.join(CONFIG_DIR, TEMP_CONFIG_FILE);
        this.configBackupDirPath = path.join(CONFIG_DIR, BACKUP_DIR);
    }
    isLoaded() {
        return this.loaded;
    }
    loadFile(fileName, callback) {
        fs.exists(fileName, (exists) => {
            if (!exists)
                return;
            fs.readFile(fileName, { encoding: 'utf8' }, (err, data) => {
                if (err)
                    return;
                try {
                    this.config = JSON.parse(data);
                    this.emit(ConfigManager.Events.Loaded, this.config);
                    this.loaded = true;
                    this.logger.log('Configuration loaded.', LogTypes_1.LogLevel.Info, { type: 'CONFIG', id: '' });
                    if (callback) {
                        callback();
                    }
                }
                catch (e) {
                    this.logger.log(`Error loading the configuration: ${e}`, LogTypes_1.LogLevel.Error, { type: 'CONFIG', id: '' });
                }
            });
        });
    }
    load() {
        this.loadFile(this.configFilePath);
        fs.exists(this.configBackupDirPath, (exists) => {
            if (!exists) {
                fs.mkdirSync(this.configBackupDirPath, { recursive: true });
                return;
            }
            fs.readdir(this.configBackupDirPath, (err, files) => {
                if (err)
                    return;
                this.backups.splice(0, this.backups.length);
                try {
                    files.forEach(file => {
                        if (file.endsWith('.json')) {
                            const backupName = file.substring(0, file.lastIndexOf('.json'));
                            this.backups.push(backupName);
                            this.emit(ConfigManager.Events.BackupListChanged);
                        }
                    });
                }
                catch (e) {
                    this.logger.log(`Error reading config backups: ${e}`, LogTypes_1.LogLevel.Error, { type: 'CONFIG', id: '' });
                }
            });
        });
    }
    save() {
        if (!this.config)
            return;
        const saveAction = () => {
            try {
                const data = JSON.stringify(this.config);
                fs.writeFile(this.configFileTempPath, data, { encoding: 'utf8' }, () => {
                    fs.copyFile(this.configFileTempPath, this.configFilePath, () => { });
                });
            }
            catch (e) {
                this.logger.log(`Error saving the configuration: ${e}`, LogTypes_1.LogLevel.Error, { type: 'CONFIG', id: '' });
            }
        };
        fs.exists(CONFIG_DIR, (exists) => {
            if (!exists) {
                fs.mkdir(CONFIG_DIR, () => saveAction());
            }
            else {
                saveAction();
            }
        });
    }
    backup(name) {
        if (!this.config)
            return;
        this.save();
        const fileName = this.sanitize(name);
        const backupFilePath = path.join(this.configBackupDirPath, fileName + '.json');
        const backupAction = () => {
            try {
                fs.copyFile(this.configFilePath, backupFilePath, () => { });
            }
            catch (e) {
                this.logger.log(`Error creating backup: ${e}`, LogTypes_1.LogLevel.Error, { type: 'CONFIG', id: '' });
            }
        };
        fs.exists(this.configBackupDirPath, (exists) => {
            if (!exists) {
                fs.mkdir(CONFIG_DIR, () => backupAction());
            }
            else {
                backupAction();
            }
            this.backups.push(fileName);
            this.emit(ConfigManager.Events.BackupListChanged);
        });
    }
    deleteBackup(name) {
        const restoreFileName = path.join(this.configBackupDirPath, name + '.json');
        fs.exists(restoreFileName, (exists) => {
            if (!exists) {
                this.logger.log('Backup file does not exist.', LogTypes_1.LogLevel.Error, { type: 'CONFIG', id: '' });
            }
            else {
                fs.unlink(restoreFileName, (err) => {
                    if (err) {
                        this.logger.log('Error deleting backup file: ' + err, LogTypes_1.LogLevel.Error, { type: 'CONFIG', id: '' });
                    }
                    else {
                        const index = this.backups.indexOf(name);
                        if (index > -1) {
                            this.backups.splice(index, 1);
                            this.emit(ConfigManager.Events.BackupListChanged);
                        }
                        this.logger.log('Backup file deleted: ' + name, LogTypes_1.LogLevel.Info, { type: 'CONFIG', id: '' });
                    }
                });
            }
        });
    }
    getBackupData(name) {
        const restoreFileName = path.join(this.configBackupDirPath, name + '.json');
        if (fs.existsSync(restoreFileName)) {
            return fs.readFileSync(restoreFileName, { encoding: 'utf8' });
        }
        return '';
    }
    restore(name) {
        const restoreFileName = path.join(this.configBackupDirPath, name + '.json');
        fs.exists(restoreFileName, (exists) => {
            if (!exists) {
                this.logger.log('Backup file does not exist.', LogTypes_1.LogLevel.Error, { type: 'CONFIG', id: '' });
            }
            else {
                this.loadFile(restoreFileName, () => this.save());
            }
        });
    }
    getBackups() {
        return [...this.backups];
    }
    getConfig() {
        if (!this.config) {
            this.config = {
                devices: [],
                mappings: [],
                videohub: [],
                atemKeySync: []
            };
        }
        return this.config;
    }
    getConfigSection(section) {
        const config = this.getConfig();
        return config[section];
    }
    updateConfigSection(section, data) {
        const config = this.getConfig();
        config[section] = data;
        this.save();
    }
    sanitize(input) {
        const illegalRe = /[\/\?<>\\:\*\|"]/g;
        const controlRe = /[\x00-\x1f\x80-\x9f]/g;
        const reservedRe = /^\.+$/;
        const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
        const windowsTrailingRe = /[\. ]+$/;
        if (typeof input !== 'string') {
            throw new Error('Input must be string');
        }
        const replacement = '';
        var sanitized = input
            .replace(illegalRe, replacement)
            .replace(controlRe, replacement)
            .replace(reservedRe, replacement)
            .replace(windowsReservedRe, replacement)
            .replace(windowsTrailingRe, replacement);
        return sanitized;
    }
}
exports.ConfigManager = ConfigManager;
ConfigManager.Events = {
    Loaded: 'loaded',
    BackupListChanged: 'backupListChanged'
};
//# sourceMappingURL=ConfigManager.js.map