"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const definitions_1 = require("./definitions");
const meta_1 = require("./angular-utility/meta");
const generator_1 = require("./generator");
const schema_json_1 = __importDefault(require("../schema.json"));
const icons_1 = require("../assets/icons");
const tap_config_parser_1 = require("./tap-config-parser");
const iotize_config_factory_1 = require("@iotize/device-config.js/iotize-config-factory");
const dot_accessor_1 = require("@iotize/device-admin.js/configuration/dot-accessor");
const config_adapter_1 = require("./iotize-studio/config-adapter");
function sanitizeFilename(input) {
    return input.replace(/[^a-zA-Z_\-]/g, '-');
}
function capitalize(s) {
    if (typeof s !== 'string' || s.length == 0)
        return '';
    return s.charAt(0).toUpperCase() + s.slice(1);
}
const defaultPageIcon = {
    "TapMonitoringPage": "analytics",
    "AboutPage": "help",
    "ProtocolConfigurationPage": "cog",
    "TapInfoPage": "help"
};
function createDefinitionsSchema(tapConfigSchema) {
    let icons = Object.keys(icons_1.ICONS);
    let data = tapConfigSchema.config.data || {};
    let bundles = data.bundles || [];
    let profiles = data.profiles || [];
    schema_json_1.default.definitions.icon.enum = icons;
    schema_json_1.default.definitions.TapProfileName.enum = profiles.map(profile => profile.username);
    let variablesList = bundles.reduce((acc, curr) => {
        curr.variables.forEach((variable) => {
            acc.push(variable.name || (variable.id).toString());
        });
        return acc;
    }, []);
    schema_json_1.default.definitions['variable-list'].enum = variablesList;
    return schema_json_1.default.definitions;
}
exports.createDefinitionsSchema = createDefinitionsSchema;
function createSchema(tapConfigSchema) {
    schema_json_1.default.definitions = createDefinitionsSchema(tapConfigSchema);
    return schema_json_1.default;
}
exports.createSchema = createSchema;
function createDefaultConfigGenerator(tapConfigSchema) {
    let profiles = [];
    if (tapConfigSchema.config && tapConfigSchema.config.data) {
        profiles = (tapConfigSchema.config.data.profiles || []).map((profile) => profile.username);
        if (!profiles.find(p => p === "anonymous")) {
            profiles.push('anonymous');
        }
    }
    let generator = ConfigGenerator.fromTapConfig(tapConfigSchema);
    generator.about();
    generator.connectionPage();
    generator.notFoundPage();
    if (profiles.length > 0) {
        generator.monitoringPage(undefined, profiles);
    }
    generator.infoPage();
    generator.protocolConfiguration();
    return generator;
}
exports.createDefaultConfigGenerator = createDefaultConfigGenerator;
function createDefaultAppConfig(tapConfigSchema) {
    let generator = createDefaultConfigGenerator(tapConfigSchema);
    return generator.schema;
}
exports.createDefaultAppConfig = createDefaultAppConfig;
function convertXMLNodeToType(dotAccessor) {
    return dotAccessor.data;
}
exports.convertXMLNodeToType = convertXMLNodeToType;
function createAppConfigFromIotizeStudioConfig(xmlConfigContent) {
    let tapConfigSchema = tap_config_parser_1.parseTapConfig(xmlConfigContent);
    let iotizeStudioConfigModel = iotize_config_factory_1.IotizeConfigFactory.fromXML(xmlConfigContent);
    let dotAccessor = new dot_accessor_1.DotAccessor(tap_config_parser_1.iotizeStudioConfigToJson(xmlConfigContent));
    let iotizeConfiguration = dotAccessor.get('IOTizeConfiguration');
    if (iotizeConfiguration.hasKey('GUI_XAppConfig')) {
        let configGenerator = ConfigGenerator.fromTapConfig(tapConfigSchema, iotizeStudioConfigModel);
        let xappConfig = iotizeConfiguration.get('GUI_XAppConfig');
        // let layoutOptions = convertXMLNodeToType<{ col: number }>('IOTizeConfiguration.GUI_XAppConfig.GUI_layout');
        let logoOptions = convertXMLNodeToType(xappConfig.get('GUI_logo'));
        if (logoOptions) {
            configGenerator.schema.app.logo = logoOptions;
        }
        let splashOptions = convertXMLNodeToType(xappConfig.get('GUI_splashScreen'));
        if (splashOptions) {
            configGenerator.schema.app.splashScreen = splashOptions;
        }
        let pages = xappConfig.get('GUI_pages');
        if (pages.has('GUI_TapInfoPage')) {
            let page = config_adapter_1.IoTizeStudioConfigAdapter.createTapInfoPage(pages.get('GUI_TapInfoPage'));
            configGenerator.infoPage(undefined, page);
        }
        if (pages.has('GUI_AboutPage')) {
            let page = config_adapter_1.IoTizeStudioConfigAdapter.createAboutPage(pages.get('GUI_AboutPage'));
            configGenerator.about(undefined, page);
        }
        if (pages.has('GUI_TargetProtocolConfPage')) {
            let page = config_adapter_1.IoTizeStudioConfigAdapter.createProtocolConfigurationPage(pages.get('GUI_TargetProtocolConfPage'));
            configGenerator.protocolConfiguration(undefined, page);
        }
        if (xappConfig.has('GUI_hostProtocols')) {
            let hostProtocolsNode = xappConfig.get('GUI_hostProtocols');
            configGenerator.connectionPage(undefined, {
                protocols: {
                    ble: {
                        enabled: hostProtocolsNode.has('GUI_ble') ? hostProtocolsNode.get('GUI_ble').value('enabled', 'string', "false") === "true" : false
                    },
                    nfc: {
                        enabled: hostProtocolsNode.has('GUI_nfc') ? hostProtocolsNode.get('GUI_nfc').value('enabled', 'string', "false") === "true" : false
                    },
                    socket: {
                        enabled: hostProtocolsNode.has('GUI_socket') ? hostProtocolsNode.get('GUI_socket').value('enabled', 'string', "false") === "true" : false
                    },
                    mqtt: {
                        enabled: hostProtocolsNode.has('GUI_mqtt') ? hostProtocolsNode.get('GUI_mqtt').value('enabled', 'string', "false") === "true" : false
                    }
                }
            });
        }
        configGenerator.notFoundPage();
        let profiles = iotizeStudioConfigModel.profiles()
            .filter(profile => {
            // console.info('PROFILE: ', profile.data.$.GUI_ManagedByApp,  profile);
            return profile.data && profile.data.$ && profile.data.$.GUI_ManagedByApp && profile.data.$.GUI_ManagedByApp.toLocaleLowerCase() === "yes";
        })
            .map(p => p.name());
        let variables = iotizeStudioConfigModel.variables();
        if (profiles.length > 0 && variables.length > 0) {
            configGenerator.monitoringPage(undefined, profiles);
        }
        else {
            configGenerator._logger.warn('No profiles');
        }
        return configGenerator;
    }
    else {
        return createDefaultConfigGenerator(tapConfigSchema);
    }
}
exports.createAppConfigFromIotizeStudioConfig = createAppConfigFromIotizeStudioConfig;
function createDefaultProjectConfig(iotizeStudioConfig) {
    let tapConfigSchema = tap_config_parser_1.parseTapConfig(iotizeStudioConfig);
    let appConfig = createDefaultAppConfig(tapConfigSchema);
    return {
        appConfig: appConfig,
        iotizeStudioConfig: iotizeStudioConfig,
        tapConfig: tapConfigSchema
    };
}
exports.createDefaultProjectConfig = createDefaultProjectConfig;
class ConfigGenerator {
    constructor(schema, tapConfig, iotizeStudioConfig, _logger = { warn: console.warn, info: console.info, debug: console.debug }) {
        this.schema = schema;
        this.tapConfig = tapConfig;
        this.iotizeStudioConfig = iotizeStudioConfig;
        this._logger = _logger;
        // TODO validate with ajv
        // console.info('ConfigGenerator', 'new instance SCHEMA', schema);
        if (typeof schema === "string") {
            throw new Error(`Invalid schema. Given a string but expecting an object`);
        }
        if (!this.schema.app) {
            throw new Error(`Invalid schema error. It does not contain property "app"`);
        }
        // TODO recover file here 
        if (!this.schema.app.menu) {
            this.schema.app.menu = [];
        }
        if (!this.schema.app.pages) {
            this.schema.app.pages = [];
        }
    }
    get appTheme() {
        if (!this.schema.app.theme) {
            this.schema.app.theme = {
                colors: DEFAULT_APP_THEME_COLORS
            };
        }
        return new AppThemeGenerator(this.schema.app.theme);
    }
    get pages() {
        return this.schema.app.pages;
    }
    get rootPageList() {
        return Object.values(this.schema.app.pages);
    }
    get pageList() {
        let routePages = this.rootPageList;
        let pages = [];
        for (let page of routePages) {
            this._pageList(page, pages);
        }
        return pages;
    }
    _pageList(page, extraPages) {
        extraPages.push(page);
        if (page.children) {
            let subPageArray = Array.isArray(page.children) ? page.children : Object.values(page.children);
            subPageArray.forEach((subPage) => this._pageList(subPage, extraPages));
        }
    }
    static fromTapConfig(tapConfig, iotizeStudioConfigModel) {
        let protocols = [
            definitions_1.AppProtocol.NFC
        ];
        if (tapConfig.config && tapConfig.config.tap && tapConfig.config.tap.availableHostProtocols) {
            let availableHostProtocols = tapConfig.config.tap.availableHostProtocols;
            if (Array.isArray(availableHostProtocols)) {
                availableHostProtocols.forEach(element => {
                    switch (element) {
                        case "BLE":
                            protocols.push(definitions_1.AppProtocol.BLE);
                            break;
                        case "NFC":
                            break;
                        case "LORA":
                            break;
                        case "WIFI":
                            protocols.push(definitions_1.AppProtocol.SOCKET);
                            protocols.push(definitions_1.AppProtocol.WIFI);
                            // protocols.push(AppProtocol.WEBSOCKET);
                            break;
                    }
                });
            }
            else if (availableHostProtocols === 'ALL') {
                protocols.push(definitions_1.AppProtocol.BLE);
                protocols.push(definitions_1.AppProtocol.SOCKET);
                protocols.push(definitions_1.AppProtocol.WIFI);
            }
        }
        let appName = tapConfig.config.application.name;
        let sanitizedAppName = sanitizeFilename(appName).replace('-', '');
        let appId = `com.iotize.generatedapp.${sanitizedAppName}`;
        let domain = tapConfig.config.application.universalLink || `www.iotize.com`;
        let appConfigSchema = {
            version: {
                generator: meta_1.meta.version()
            },
            app: {
                id: appId,
                version: `v1.0.0`,
                domain: domain,
                name: appName,
                platforms: {
                    android: {
                        enabled: true
                    },
                    browser: {
                        enabled: true,
                        PWA: true
                    },
                    ios: {
                        enabled: true
                    }
                },
                menu: [],
                pages: {},
                defaultPage: undefined
            },
            formMeta: {
                showAdvanceSettings: false
            }
        };
        let configGenerator = new ConfigGenerator(appConfigSchema, tapConfig, iotizeStudioConfigModel, undefined);
        return configGenerator;
    }
    notFoundPage(relativePath) {
        return this.getOrCreateAppPage({
            type: 'NotFoundPage',
            enabled: true,
            pageTitle: 'Not found',
            path: '**',
            projectPath: relativePath || 'pages/not-found'
        });
    }
    connectionPage(relativePath, override = {}) {
        let defaultOptions = {
            type: 'TapConnectionPage',
            enabled: true,
            pageTitle: 'Connection',
            path: 'connect',
            projectPath: relativePath || 'pages/tap-connect',
            protocols: {
                ble: {
                    enabled: true,
                },
                nfc: {
                    enabled: true
                },
                socket: {
                    enabled: true,
                    enableNetworkScan: true,
                    enableSoket: true,
                    enableWebsocket: true,
                    enableWifiAccessPointScan: true
                }
            }
        };
        return this.getOrCreateAppPage(Object.assign({}, defaultOptions, override));
    }
    infoPage(projectPath, override) {
        let infoPage = {
            type: "TapInfoPage",
            enabled: true,
            pageTitle: 'Device information',
            path: 'info',
            projectPath: projectPath,
            // loadChildren: `./${relativePath}/${sanitizeFilename(name)}.module#${classify(name)}Module`,
            items: [
                {
                    key: "appName"
                },
                {
                    key: "serialNumber"
                },
                {
                    key: "tapFirmwareVersion"
                },
                {
                    key: "configVersion"
                },
                {
                    key: "TargetProtocol"
                }
            ]
        };
        const parentPage = "TapDevicePage";
        if (!this.hasPageType(parentPage)) {
            this.tapDevicePage();
        }
        return this.getOrCreateSubPage(Object.assign({}, infoPage, override), parentPage, "tap-info-page");
    }
    // public refreshMenu() {
    //     for (let page of this.pageList) {
    //         this.addMenuForPage(page);
    //     }
    // }
    /**
     * Create a dashboard configuration according to Tap Schema.
     */
    addDashboard(profileName, path, projectPath) {
        this.logger.info(`Creating dashboard from config for profile "${profileName}"`);
        let iotizeStudioConfig = this.iotizeStudioConfig;
        let tapConfig = this.tapConfig;
        let columnNumber = 3;
        let rootLayout = {
            type: 'GridLayout',
            cols: columnNumber,
            elements: []
        };
        let pageTitle = profileName === 'anonymous'
            ? 'Public dashboard'
            : `${capitalize(profileName)} dashboard`;
        let page = {
            type: "MonitoringDashboardPage",
            pageTitle: pageTitle,
            enabled: true,
            path: path,
            projectPath: projectPath,
            profileName: profileName,
            content: rootLayout,
        };
        let bundles = tapConfig.config.data.bundles || [];
        for (let bundle of bundles) {
            let variables = bundle.variables || [];
            if (generator_1.hasReadOrWriteRights(bundle, profileName)) {
                for (let variable of variables) {
                    this.logger.debug(`Rendering variable ${variable.id.toString()} (iotize studio config ? ${Boolean(iotizeStudioConfig)})`);
                    let iotizeStudioVariableConfig = iotizeStudioConfig ? iotizeStudioConfig.variable(variable.id.toString()) : undefined;
                    if (iotizeStudioVariableConfig) {
                        if (iotizeStudioVariableConfig.attribute('GUI_Display') === 'No') {
                            this.logger.info(`Skip variable in dashboard: "${variable.name}"`);
                        }
                    }
                    let cardTitle = iotizeStudioVariableConfig ? (iotizeStudioVariableConfig.alias() || iotizeStudioVariableConfig.name()) : variable.name;
                    let isVariableEditable = generator_1.isEditable(bundle, variable, profileName, iotizeStudioVariableConfig);
                    // console.log('iotizeStudioVariableConfig.data', iotizeStudioVariableConfig!.data);
                    if (iotizeStudioVariableConfig && iotizeStudioVariableConfig.data.XAppRender) {
                        this.logger.info(`XAppRender found for variable ${variable.id.toString()}`);
                        let renderOptions = Object.assign({}, iotizeStudioVariableConfig.data.XAppRender[0], iotizeStudioVariableConfig.data.XAppRender[0].$);
                        let component = config_adapter_1.IoTizeStudioConfigAdapter.renderOptionsToComponent(variable, renderOptions, isVariableEditable);
                        if (component) {
                            rootLayout.elements.push(component);
                        }
                    }
                    else {
                        let card = {
                            type: 'CardLayout',
                            description: undefined,
                            icon: undefined,
                            title: cardTitle,
                            content: []
                        };
                        // let cardVariable: TapVariableCardComponent = {
                        //     type: 'VariableCard',
                        //     editable: isVariableEditable,
                        //     unit: variable.unit,
                        //     variable: `${variable.name}`
                        // };
                        if (variable.length > 1) {
                            let layoutItemList = {
                                type: 'ListLayout',
                                items: []
                            };
                            card.content.push(layoutItemList); // TODO fix
                            for (let index = 0; index < variable.length; index++) {
                                let textVariable = {
                                    type: 'VariableText',
                                    editable: isVariableEditable,
                                    variableIndex: index,
                                    variable: `${variable.name}`
                                };
                                layoutItemList.items.push({
                                    title: index.toString(),
                                    value: textVariable
                                });
                            }
                        }
                        else {
                            card.content.push({
                                type: 'VariableText',
                                variable: `${variable.name}`,
                                editable: isVariableEditable,
                                unit: variable.unit
                            });
                        }
                        rootLayout.elements.push(card);
                    }
                }
            }
        }
        return page;
    }
    about(relativePath, override) {
        let defaultOptions = {
            type: "AboutPage",
            enabled: true,
            projectPath: relativePath || 'pages/about',
            items: [
                {
                    title: 'Developer',
                    value: 'IoTize SAS'
                },
                {
                    title: 'About us',
                    value: 'https://iotize.com'
                }
            ],
            pageTitle: 'About',
            path: 'about',
        };
        return this.getOrCreateAppPage(Object.assign({}, defaultOptions, override));
    }
    monitoringPage(projectPath, dashboardProfiles = []) {
        const DEFAULT_MONITORING_PAGE = {
            type: 'MonitoringPage',
            enabled: true,
            pageTitle: 'Monitoring',
            projectPath: projectPath,
            path: 'monitoring',
        };
        const parentPage = "TapDevicePage";
        if (!this.hasPageType(parentPage)) {
            this.tapDevicePage();
        }
        let monitoringPage = this.getOrCreateSubPage(DEFAULT_MONITORING_PAGE, parentPage, 'monitoring-page');
        dashboardProfiles.forEach(profileName => {
            this.getOrCreateDashboard(profileName, {
                reconfigure: false
            });
        });
        return monitoringPage;
    }
    tapDevicePage(projectPath) {
        let devicePage = this.getOrCreateAppPage({
            enabled: true,
            children: {},
            pageTitle: 'Device',
            path: 'device',
            projectPath: projectPath || 'pages/tap-device-page',
            type: 'TapDevicePage'
        });
        this.tapLoginPage();
        return devicePage;
    }
    protocolConfiguration(projectPath, override) {
        let targetProtocolConfig = this.tapConfig.config.target ? this.tapConfig.config.target.protocol : undefined;
        let protocolConfigurationList = [
            "MODBUS",
            "SERIAL_STANDARD",
            "SERIAL_VIA_TAPNPASS"
        ];
        let enabled = targetProtocolConfig ? protocolConfigurationList.indexOf(targetProtocolConfig) >= 0 : false;
        let protocolConfigurationPage = {
            enabled: enabled,
            type: 'ProtocolConfigurationPage',
            path: 'protocol-configuration',
            pageTitle: 'Protocol configuration',
            projectPath: projectPath,
            serialSettings: true,
            modbusSettings: targetProtocolConfig === "MODBUS" || targetProtocolConfig === "SERIAL_VIA_TAPNPASS",
            tapnpassSettings: targetProtocolConfig === "SERIAL_VIA_TAPNPASS"
        };
        const parentPage = "TapDevicePage";
        if (!this.hasPageType(parentPage)) {
            this.tapDevicePage();
        }
        return this.getOrCreateSubPage(Object.assign({}, protocolConfigurationPage, override), parentPage, "protocol-configuration");
    }
    tapLoginPage(projectPath) {
        return this.getOrCreateSubPage({
            enabled: true,
            children: {},
            pageTitle: 'Tap login',
            path: 'login',
            projectPath: projectPath,
            type: 'TapLoginPage'
        }, "TapDevicePage", "tap-login-page");
    }
    getOrCreateDashboard(profileName, _options) {
        let monitoringPage = this.getPageByType("MonitoringPage");
        if (!monitoringPage) {
            throw new Error(`Cannot create dashboard page. Monitoring page is not enabled. Available pages: ${this.pageList.map(page => page.type).join(',')}`);
        }
        const relativePath = _options.name || `${monitoringPage.projectPath}/${profileName}-dashboard`;
        if (!monitoringPage.children) {
            monitoringPage.children = [];
        }
        let defaultDashboardPath = `${profileName}`;
        let existingingDashboardIndex = monitoringPage.children.findIndex(item => item.path === defaultDashboardPath);
        let dashboard = undefined;
        if (existingingDashboardIndex >= 0) {
            if (_options.reconfigure) {
                let existingDashboard = monitoringPage.children[existingingDashboardIndex];
                this.logger.warn(`Deleting dashboard page "${existingDashboard.pageTitle}" (path="${existingDashboard.path}") at index ${existingingDashboardIndex}`);
                monitoringPage.children.splice(existingingDashboardIndex, 1);
                dashboard = this.addDashboard(profileName, defaultDashboardPath, relativePath);
                monitoringPage.children.push(dashboard);
            }
            else {
                this.logger.info(`Using existing dashboard configuration`);
                dashboard = monitoringPage.children[existingingDashboardIndex];
            }
        }
        if (!dashboard) {
            dashboard = this.addDashboard(profileName, defaultDashboardPath, relativePath);
            monitoringPage.children.push(dashboard);
        }
        return dashboard;
    }
    addMenuForSubPage(page, icon, parentPageString) {
        if (page.enabled) {
            let parentPage = this.getPageByType(parentPageString);
            let menuItem = {
                title: page.pageTitle,
                icon: icon,
                url: `${parentPage.path}/${page.path}`
            };
            this.addMenu(menuItem);
            return menuItem;
        }
        else {
            // TODO remove ? 
        }
    }
    addMenu(item) {
        if (!item.url.startsWith('/')) {
            item.url = `/${item.url}`;
        }
        if (!this.schema.app.menu.find(m => m.url === item.url)) {
            this.schema.app.menu.push(item);
        }
        else {
            this.logger.info(`Menu item ${item.title} (url: ${item.url}) already exists`);
        }
    }
    addMenuForPage(page, icon) {
        if (page.enabled) {
            this.logger.info(`Add menu for page: ${page.type}`);
            let menuItem = {
                title: page.pageTitle,
                icon: icon ? icon : defaultPageIcon[page.type],
                url: page.path
            };
            this.addMenu(menuItem);
            return menuItem;
        }
        else {
            // TODO remove ? 
        }
    }
    getPageByPath(path, pages = this.rootPageList) {
        // path = !Array.isArray(path) ? path.split('/') : path;
        // this._logger.info(`Search page "${path}"  in pages ${pages.map(p => `${p.type}:${p.path}`).join(', ')} `)
        if (path.startsWith('/')) {
            path = path.substring(1);
        }
        let page = pages.find((page) => {
            return path.startsWith(page.path);
        });
        if (!page) {
            this._logger.info(`Page NOT_FOUND "${path}"`);
            return undefined;
        }
        let subPath = path.substr(page.path.length);
        if (subPath.length === 0) {
            // this._logger.info(`Page FOUND "${path}"  ${page.type}:${page.path} `)
            return page;
        }
        else {
            return this.getPageByPath(subPath, Object.values(page.children) || []);
        }
    }
    getOrCreatePageByPath(path, defaultValue) {
        if (!this.hasPageByPath(path)) {
            this.addPage(defaultValue);
        }
        return this.getPageByPath(path);
    }
    getPageByType(type) {
        return this.pageList.find(page => page.type === type);
    }
    hasPageType(type) {
        return Boolean(this.rootPageList.find(page => page.type === type));
    }
    addPage(page) {
        this.logger.info(`Creating page ${page.path} (type=${page.type})`);
        if (!page.type) {
            throw new Error(`Cannot add page without a type attribute`);
        }
        this.schema.app.pages[page.type] = page;
    }
    getDefaultPage() {
        let defaultPage = this.schema.app.defaultPage;
        if (!defaultPage) {
            if (this.schema.app.menu.length == 0) {
                defaultPage = '';
            }
            else {
                defaultPage = this.schema.app.menu[0].url;
            }
        }
        return defaultPage;
    }
    /**
     * TODO
     * @param pageName
     */
    hasPageByPath(path) {
        return this.getPageByPath(path) !== undefined; // TODO check undefined
    }
    getOrCreateAppPage(appPage) {
        // this.logger.info(`Search page ${appPage.path} (type=${appPage.type})`);
        return this.getOrCreatePageByPath(appPage.path, appPage);
    }
    getOrCreateSubPage(appPage, parentPageOrString, defaultSubProjectPath, subPageKey = "children") {
        let parentPage;
        if (typeof parentPageOrString === "string") {
            parentPage = this.pages[parentPageOrString];
            if (!parentPage) {
                throw new Error(`Page "${parentPageOrString}" is required to create "${appPage.type}"`);
            }
        }
        else {
            parentPage = parentPageOrString;
        }
        // this.logger.debug(`Search sub page ${appPage.path} (type=${appPage.type})`);
        if (!parentPage[subPageKey]) {
            parentPage[subPageKey] = {};
        }
        let childrens = parentPage[subPageKey];
        if (!(appPage.type in childrens)) {
            if (!appPage.projectPath) {
                appPage.projectPath = `${parentPage.projectPath}/${defaultSubProjectPath}`;
            }
            this.logger.info(`\t- Creating sub page ${appPage.path} (type=${appPage.type})`);
            childrens[appPage.type] = appPage;
        }
        return childrens[appPage.type];
    }
    get logger() {
        return this._logger;
    }
}
exports.ConfigGenerator = ConfigGenerator;
function asHexString(input) {
    return typeof input === "number" ? `0x${input.toString(16)}` : input;
}
class AppThemeGenerator {
    constructor(theme) {
        this.options = {
            shadeFactor: 0.1,
            tintFactor: 0.1
        };
        this.theme = theme;
        if (!this.theme.colors) {
            this.theme.colors = DEFAULT_APP_THEME_COLORS;
        }
    }
    get colors() {
        return this.theme.colors;
    }
    setTheme(theme) {
        switch (theme) {
            default:
                this.theme.colors = DEFAULT_APP_THEME_COLORS;
        }
    }
    setColor(name, value) {
        value = typeof value === "string" ? parseInt(value, 16) : value;
        let colorIndex = this.theme.colors.findIndex(c => c.name === name);
        let color = {
            name: name,
            value: asHexString(value),
            contrast: asHexString(this.computeVariant(value, 'contrast')),
            shade: asHexString(this.computeVariant(value, 'shade')),
            tint: asHexString(this.computeVariant(value, 'tint'))
        };
        if (colorIndex >= 0) {
            this.theme.colors[colorIndex] = color;
        }
        else {
            this.theme.colors.push(color);
        }
    }
    /**
     * Inspired by https://maketintsandshades.com/about
     * @param color
     * @param variant
     */
    computeVariant(color, variant) {
        switch (variant) {
            case 'contrast':
                return (isDarkColor(color) ? 0xffffff : 0x000000);
            case 'shade':
                return this._applyFactor(color, (color) => Math.round(Math.max(color * this.options.shadeFactor, 255)));
            case 'tint':
                return this._applyFactor(color, (color) => Math.round(color + ((255 - color) * this.options.tintFactor)));
        }
        return color;
    }
    _applyFactor(color, fct) {
        let result = 0;
        for (let i of [16, 8, 0]) {
            let tmp = fct((color >> i) & 0xFF);
            result = result | (tmp << i);
            // console.info(i, color.toString(16), tmp.toString(16), (tmp << i).toString(16), result.toString(16));
        }
        return result;
    }
}
exports.AppThemeGenerator = AppThemeGenerator;
const DEFAULT_APP_THEME_COLORS = [
    {
        name: "primary",
        value: "0x3880ff",
        contrast: "0xffffff",
        shade: "0x3171e0",
        tint: "0x4c8dff"
    },
    {
        name: "secondary",
        value: "0x0cd1e8",
        contrast: "0xffffff",
        shade: "0x0bb8cc",
        tint: "0x24d6ea"
    },
    {
        name: "tertiary",
        value: "0x7044ff",
        contrast: "0xffffff",
        shade: "0x633ce0",
        tint: "0x7e57ff"
    },
    {
        name: "success",
        value: "0x10dc60",
        contrast: "0xffffff",
        shade: "0x0ec254",
        tint: "0x28e070"
    },
    {
        name: "warning",
        value: "0xffce00",
        contrast: "0xffffff",
        shade: "0xe0b500",
        tint: "0xffd31a"
    },
    {
        name: "danger",
        value: "0xf04141",
        contrast: "0xffffff",
        shade: "0xd33939",
        tint: "0xf25454"
    },
    {
        name: "dark",
        value: "0x222428",
        contrast: "0xffffff",
        shade: "0x1e2023",
        tint: "0x383a3e"
    },
    {
        name: "medium",
        value: "0x989aa2",
        contrast: "0xffffff",
        shade: "0x86888f",
        tint: "0xa2a4ab"
    },
    {
        name: "light",
        value: "0xf4f5f8",
        contrast: "0xffffff",
        shade: "0xd7d8da",
        tint: "0xf5f6f9"
    }
];
function isDarkColor(hexColor) {
    const { r, g, b } = hexToRgb(hexColor);
    let colorArray = [r / 255, g / 255, b / 255].map(v => {
        if (v <= 0.03928) {
            return v / 12.92;
        }
        return Math.pow((v + 0.055) / 1.055, 2.4);
    });
    const luminance = 0.2126 * colorArray[0] + 0.7152 * colorArray[1] + 0.0722 * colorArray[2];
    return luminance <= 0.179;
}
exports.isDarkColor = isDarkColor;
function hexToRgb(c) {
    return {
        r: (c << 16) & 0xFF,
        g: (c << 8) & 0xFF,
        b: c & 0xFF
    };
}
exports.hexToRgb = hexToRgb;
//# sourceMappingURL=config-generator.js.map