"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
const path = require("path");
const checkSanity_1 = require("../shared/checkSanity");
const AppConfigApi_1 = require("../shared/config/AppConfigApi");
const AppConfigFile_1 = require("../shared/config/AppConfigFile");
const LogMainApi_1 = require("../shared/Log/LogMainApi");
const BackgroundServices_1 = require("./background/BackgroundServices");
const MainWindow_1 = require("./MainWindow");
const AppPreferencesMain_1 = require("./preferences/AppPreferencesMain");
const Util = require("./Util");
class Main {
    constructor() {
        this._mainWindow = new MainWindow_1.default(this);
        this._preferences = new AppPreferencesMain_1.AppPreferencesMain();
        this._log = new LogMainApi_1.LogMainApi(this.sendToMainWindowRenderer.bind(this));
        // Add app event listeners
        electron_1.app.once('ready', this.onAppReady.bind(this));
        electron_1.app.once('window-all-closed', this.onAppWindowAllClosed.bind(this));
        electron_1.app.once('will-quit', this.onAppWillQuit.bind(this));
        electron_1.app.once('web-contents-created', this.onAppWebContentsCreated.bind(this));
        // Add IPC event listeners
        electron_1.ipcMain.on(AppConfigApi_1.AppConfigApi.ipcRequestSync, this.onGetConfigSync.bind(this));
        this._log.bindListeners();
        // Connect preferences to log
        this._preferences.on('log', this.pushLogData.bind(this));
        // Load config and preferences
        this.loadConfig()
            .then(async () => { await this._preferences.load(); })
            .then(async () => {
            // Check if we are ready to launch or not.
            // @TODO Launch the setup wizard when a check failed.
            checkSanity_1.default(this.config)
                .then(console.log, console.error);
            // Start background services
            this._backgroundServices = new BackgroundServices_1.default();
            this._backgroundServices.on('output', this.pushLogData.bind(this));
            this._backgroundServices.start(this.config);
            // Create main window when ready
            this._backgroundServices.waitUntilDoneStarting()
                .then(Util.waitUntilReady)
                .then(() => { this._mainWindow.createWindow(); });
        })
            .catch(console.error);
    }
    get config() {
        if (!this._config) {
            throw new Error('You must not try to access config before it is loaded!');
        }
        return this._config;
    }
    get preferences() {
        return this._preferences;
    }
    onAppReady() {
        if (!electron_1.session.defaultSession) {
            throw new Error('Default session is missing!');
        }
        // Reject all permission requests since we don't need any permissions.
        electron_1.session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => callback(false));
        // Stop non-local resources from being fetched (as long as their response has at least one header?)
        // Only allow local scripts to execute (Not sure what this allows? "file://"? "localhost"?)
        // (TypeScript type information is missing, check the link below for the type info)
        // https://github.com/electron/electron/blob/master/docs/api/web-request.md#webrequestonheadersreceivedfilter-listener
        electron_1.session.defaultSession.webRequest.onHeadersReceived((details, callback) => callback({
            responseHeaders: `script-src 'self'`,
            cancel: true
        }));
    }
    onAppWindowAllClosed() {
        // On OS X it is common for applications and their menu bar
        // to stay active until the user quits explicitly with Cmd + Q
        if (process.platform !== 'darwin') {
            electron_1.app.quit();
        }
    }
    onAppWillQuit() {
        if (this._backgroundServices) {
            this._backgroundServices.stop();
        }
    }
    onAppWebContentsCreated(event, webContents) {
        // Open links to web pages in the OS-es default browser
        // (instead of navigating to it with the electron window that opened it)
        webContents.on('will-navigate', (event, navigationUrl) => {
            event.preventDefault();
            electron_1.shell.openExternal(navigationUrl);
        });
    }
    /**
     * Append the output to the internal log data object and tell the main window
     * about the updated log data. The main window will display the log data in
     * the "Logs" tab. Also print the output to stdout.
     * @param output The log entry to be added. Must end with a new line.
     */
    pushLogData(output) {
        //process.stdout.write(output);
        this._log.addEntry(output);
    }
    /** Load the application config asynchronously */
    async loadConfig() {
        let error;
        let data;
        const onError = (e) => this.pushLogData({ source: 'Config', content: e });
        try {
            data = await AppConfigFile_1.AppConfig.readConfigFile(onError);
        }
        catch (e) {
            error = e;
        }
        // Check if config data failed to load
        if (error || !data) {
            // Set the config data to the default
            data = AppConfigFile_1.AppConfig.createCopyOfDefaults(process.platform);
            // Create a new config file with the default configs
            AppConfigFile_1.AppConfig.saveConfigFile(data);
        }
        // Set config data
        this._config = data;
        console.log('Configs:', data);
    }
    /** Get the config object synchronously */
    onGetConfigSync(event) {
        const data = {
            data: this.config,
            fullFlashpointPath: path.resolve(this.config.flashpointPath),
        };
        event.returnValue = data;
    }
    /** Send a message to the main windows renderer */
    sendToMainWindowRenderer(channel, ...rest) {
        if (!this._mainWindow.window) {
            return false;
        }
        this._mainWindow.window.webContents.send(channel, ...rest);
        return true;
    }
}
exports.Main = Main;
//# sourceMappingURL=Main.js.map