var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
// tslint:disable: no-implicit-dependencies
import { hexStringToBuffer } from '@iotize/common/byte-converter';
import { isCodeError } from '@iotize/common/error';
import { StepOperations } from '@iotize/common/task-manager';
import { deepCopy, sleep } from '@iotize/common/utility';
import '@iotize/tap';
import { AppPathType, SpecialFeature, TapError, } from '@iotize/tap';
import { DEFAULT_SCRAM_SALT_GENERATOR, hashLoginPassword, ScramAuth, } from '@iotize/tap/auth';
import { ResultCode, TapRequestFrame } from '@iotize/tap/client/api';
import { NumberConverter, TapStreamWriter } from '@iotize/tap/client/impl';
import { getConverterFromVariableType, variableDataTypeToByteSize, } from '@iotize/tap/data';
import '@iotize/tap/service/all';
import { converters, FirmwareState, VariableType, } from '@iotize/tap/service/all';
import { VariableMetaConfigConverter } from '@iotize/tap/service/impl/variable';
import { ADMIN_USER, DEFAULT_HASH_ITERATION_COUNT, SPECIAL_USERS, SUPERVISOR_USER, } from './default-config';
import { TapConfiguratorError } from './errors';
import { enumKeyToEnumValue, getProfileIdFromConfig, isSpecialProfileId, } from './util';
import { validateTapConfiguratorConfig } from './validate-tap-config';
import { WRITE_CONFIGURATOR_CONFIG, } from './write-configurator-config';
const variableMetaConverter = new VariableMetaConfigConverter();
const IGNORE_KEYS = ['version', 'tap.security'];
const USER_CREATE_KEY = 'data.profiles[]';
const CREATE_VARIABLE_CONFIG_KEY = 'data.variables[]';
function isHexString(input) {
    if (typeof input !== 'string') {
        return false;
    }
    return !!input.match(/^(0x)?([a-fA-F0-9])*$/);
}
export function tapConfigToServiceCalls(config, options) {
    var _a;
    function addCalls(calls, newCalls) {
        if (Array.isArray(newCalls)) {
            calls.push(...newCalls);
        }
        else {
            calls.push(newCalls);
        }
    }
    function createWriteConfigCall(key, callContext) {
        if (!(key in WRITE_CONFIGURATOR_CONFIG)) {
            throw new Error(`Invalid API configuration. Configuration key "${key}" does not exist`);
        }
        const callFactory = WRITE_CONFIGURATOR_CONFIG[key];
        return callFactory(callContext);
    }
    function baseConfigObjectToCalls(entry, configKey, pathParameter) {
        const calls = [];
        if (entry === undefined) {
            return calls;
        }
        else if (Array.isArray(entry)) {
            const newConfigKey = configKey + '[]';
            for (const itemValue of entry) {
                if (itemValue.id || itemValue.id === 0) {
                    pathParameter = itemValue.id;
                }
                if (pathParameter === undefined) {
                    throw new Error(`Item must have an id for key "${newConfigKey}`);
                    // TODO we need to know parent profile ?
                }
                // If there is a create instance function
                if (newConfigKey in WRITE_CONFIGURATOR_CONFIG) {
                    if (newConfigKey === USER_CREATE_KEY &&
                        isSpecialProfileId(pathParameter)) {
                        // If it's a special user profile, we dont need the create call
                    }
                    else {
                        // throw new Error(`Missing create method for config key "${newConfigKey}"`);
                        let createBody;
                        if (newConfigKey === CREATE_VARIABLE_CONFIG_KEY) {
                            if (itemValue.metaDataLength) {
                                createBody = itemValue.metaDataLength;
                            }
                            else if (itemValue.rawMeta) {
                                createBody = itemValue.rawMeta.length;
                            }
                        }
                        const createCallParam = {
                            firmwareVersion: options.firmwareVersion,
                            service: options.service,
                            value: createBody,
                            param: pathParameter,
                        };
                        if (createBody === undefined) {
                            delete createCallParam.value;
                        }
                        try {
                            const newCalls = WRITE_CONFIGURATOR_CONFIG[newConfigKey](createCallParam);
                            addCalls(calls, newCalls);
                        }
                        catch (err) {
                            throw TapConfiguratorError.internalError(`Cannot generate configuration requests from configuration key ${newConfigKey}. Cause: ${err.message}`, err);
                        }
                    }
                }
                calls.push(...baseConfigObjectToCalls(itemValue, newConfigKey, pathParameter));
            }
        }
        else {
            if (`${configKey}.$` in WRITE_CONFIGURATOR_CONFIG) {
                try {
                    addCalls(calls, createWriteConfigCall(`${configKey}.$`, {
                        firmwareVersion: options.firmwareVersion,
                        service: options.service,
                        value: entry,
                        param: pathParameter,
                        config,
                    }));
                }
                catch (err) {
                    throw TapConfiguratorError.internalError(`Cannot generate create resource request for configuration key ${configKey} for identifier "${pathParameter}". Cause: ${err.message}`, err);
                }
            }
            else {
                for (const subKey in entry) {
                    const newConfigKey = configKey ? `${configKey}.${subKey}` : subKey;
                    if (newConfigKey === `${CREATE_VARIABLE_CONFIG_KEY}.metaDataLength`) {
                        continue;
                    }
                    const value = entry[subKey];
                    // We skip version key as it's a special key
                    if (value === undefined) {
                        continue;
                    }
                    else if (IGNORE_KEYS.indexOf(newConfigKey) >= 0) {
                        continue;
                    }
                    else if (pathParameter !== undefined &&
                        subKey === 'id' &&
                        value === pathParameter) {
                        // Skip id field
                        continue;
                    }
                    else if (newConfigKey in WRITE_CONFIGURATOR_CONFIG) {
                        const callContext = {
                            firmwareVersion: options.firmwareVersion,
                            service: options.service,
                            value: value,
                            param: pathParameter,
                        };
                        addCalls(calls, createWriteConfigCall(newConfigKey, callContext));
                    }
                    else if (typeof value === 'object') {
                        calls.push(...baseConfigObjectToCalls(value, newConfigKey, pathParameter));
                    }
                    else {
                        throw new Error(`Invalid config key "${newConfigKey}" with value ${value}. ${pathParameter ? `Current path parameter: ${pathParameter}` : ''}`);
                    }
                }
            }
        }
        return calls;
    }
    const flattenConfig = toFlatTapConfig(config, options);
    const { service } = options;
    const calls = [
        service.interface.putConfigVersionCall('255.255.65535'),
    ];
    const security = ((_a = config.tap) === null || _a === void 0 ? void 0 : _a.security) || {};
    if (security.scramActivated) {
        // Usually security options are encoded on 2 bytes
        // However to enable scram during configuration, we must give 0x10 value
        // Don't know why
        calls.push({
            method: TapRequestFrame.MethodType.PUT,
            path: '/1024//6',
            body: Uint8Array.from([0x10]),
        });
    }
    calls.push(...baseConfigObjectToCalls(flattenConfig, '', undefined));
    if (security.scramActivated) {
        security.hashPassword = true;
    }
    calls.push(service.interface.putSecurityOptionsCall(security));
    calls.push(service.interface.putConfigVersionCall(config.version || '1.0.0'));
    return calls;
}
function arrayPadEnd(data, length, padValue = 0) {
    if (data.length >= length) {
        return data;
    }
    else {
        return TapStreamWriter.create(length)
            .writeBytes(data)
            .writeBytes(new Uint8Array(length - data.length).fill(padValue, 0, length - data.length)).toBytes;
    }
}
function arrayPadStart(data, length, padValue = 0) {
    if (data.length >= length) {
        return data;
    }
    else {
        return TapStreamWriter.create(length)
            .writeBytes(new Uint8Array(length - data.length).fill(padValue, 0, length - data.length))
            .writeBytes(data).toBytes;
    }
}
function invalidVariableValueError(bundle, variable, msg) {
    return TapConfiguratorError.invalidConfiguration(`data.bundle[${bundle.id}].variable[${variable.id}].value ${msg}`);
}
export function encodeInitialVariableValue(variable, bundle) {
    const variableLength = variable.length || 1;
    const variableDataType = variable.dataType === undefined
        ? VariableType.Data.UINT8
        : VariableType.Data[variable.dataType];
    const itemByteSize = variableDataTypeToByteSize(variableDataType);
    function _encodeItem(value, index = 0) {
        let result;
        if (value instanceof Uint8Array) {
            result = value;
        }
        else if (isHexString(value)) {
            result = hexStringToBuffer(value);
        }
        else if (typeof value === 'number') {
            const converter = getConverterFromVariableType(variableDataType, 1);
            if (!converter) {
                throw invalidVariableValueError(bundle, variable, `cannot be converted to a buffer. No registered converter exist for this variable type.`);
            }
            result = converter.encode(value);
        }
        else {
            throw invalidVariableValueError(bundle, variable, `has type ${typeof value} which is not supported by the configurator`);
        }
        if (result.length > itemByteSize) {
            throw invalidVariableValueError(bundle, variable, `at index ${index} is on ${result.length} bytes but expecting a maximum length of ${itemByteSize} byte(s)`);
        }
        else {
            result = arrayPadStart(result, itemByteSize);
        }
        return result;
    }
    let encodedValue;
    if (typeof variable.value === 'string' &&
        variableDataType === VariableType.Data.ASCII) {
        encodedValue = converters.ascii.encode(variable.value);
    }
    else if (Array.isArray(variable.value)) {
        const buffers = variable.value.map((v, index) => {
            return _encodeItem(v, index);
        });
        encodedValue = TapStreamWriter.mergeArrays(...buffers);
    }
    else {
        encodedValue = _encodeItem(variable.value);
    }
    const byteLength = variableLength * itemByteSize;
    if (encodedValue.length > byteLength) {
        throw invalidVariableValueError(bundle, variable, `is encoded on ${encodedValue.length} byte(s) but you have declared a maximum length of ${byteLength} byte(s)`);
    }
    return arrayPadEnd(encodedValue, byteLength);
}
export function toVariableFlatConfig(variable, bundle) {
    const variableCopy = deepCopy(variable);
    if (variableCopy.length === undefined) {
        variableCopy.length = 1;
    }
    const variableFlatConfig = variableCopy;
    delete variableCopy.dataType;
    delete variableCopy.domain;
    variableFlatConfig.bundleId = bundle.id;
    if (variableFlatConfig.rawMeta !== undefined) {
        variableFlatConfig.rawMeta =
            typeof variableFlatConfig.rawMeta === 'string'
                ? hexStringToBuffer(variableFlatConfig.rawMeta)
                : variableFlatConfig.rawMeta;
    }
    else if (variableCopy.meta) {
        variableFlatConfig.rawMeta = variableMetaConverter.encode(variableCopy.meta);
        delete variableCopy.meta;
    }
    variableFlatConfig.type = {
        domain: variable.domain !== undefined ? variable.domain : 'TARGET',
        data: variable.dataType !== undefined ? variable.dataType : 'UINT8',
    };
    if (variable.value !== undefined && variable.value !== null) {
        variableFlatConfig.value = encodeInitialVariableValue(variable, bundle);
    }
    return variableFlatConfig;
}
export function toFlatTapConfig(config, options) {
    var _a, _b, _c, _d, _e, _f, _g;
    const configCopy = deepCopy(config);
    const flatProfiles = [];
    if (configCopy.target) {
        delete configCopy.target.type;
    }
    if (configCopy.data) {
        // Flaten profiles
        if (configCopy.data.profiles) {
            for (const profile of (_a = configCopy.data) === null || _a === void 0 ? void 0 : _a.profiles) {
                const flatenProfile = profile;
                if (flatenProfile.id === undefined) {
                    flatenProfile.id = getProfileIdFromConfig(flatenProfile);
                }
                if (isSpecialProfileId(flatenProfile.id)) {
                    delete flatenProfile.username;
                }
                const subProfiles = flatenProfile.users || [];
                delete flatenProfile.users;
                flatProfiles.push(flatenProfile);
                for (const subProfile of subProfiles) {
                    subProfile.alias = flatenProfile.id;
                    flatProfiles.push(subProfile);
                    if (isSpecialProfileId(subProfile.id)) {
                        delete subProfile.username;
                    }
                }
            }
        }
        // Flaten acls and special features
        const flatSpecialFeatures = [];
        const flatVariables = [];
        if (configCopy.data.bundles) {
            for (const bundle of configCopy.data.bundles) {
                const acls = bundle.acls || {};
                delete bundle.acls;
                const flatAcls = [];
                for (const username in acls) {
                    const acl = acls[username];
                    let profile = flatProfiles.find((p) => p.username === username);
                    if (!profile) {
                        profile = SPECIAL_USERS.find((p) => p.username === username);
                        if (!profile) {
                            throw new Error(`Cannot find profile with username "${username}"`); // TODO proper error
                        }
                    }
                    flatAcls.push({
                        groupId: profile.id,
                        read: acl.read,
                        write: acl.write,
                    });
                }
                if (flatAcls.length > 0) {
                    bundle.acl = flatAcls;
                }
                const variables = bundle.variables || [];
                delete bundle.variables;
                for (const variable of variables) {
                    flatVariables.push(toVariableFlatConfig(variable, bundle));
                }
                const features = bundle.features || [];
                delete bundle.features;
                for (const featureKey of features) {
                    const featureId = enumKeyToEnumValue(featureKey, SpecialFeature);
                    if (flatSpecialFeatures.find((f) => f.id === featureId)) {
                        throw new Error(`Special feature "${featureId}" has already be given to another bundle`);
                    }
                    flatSpecialFeatures.push({
                        id: featureId,
                        bundleId: bundle.id,
                    });
                }
            }
        }
        if (flatSpecialFeatures.length > 0) {
            configCopy.data.features = flatSpecialFeatures;
        }
        if (flatVariables.length > 0) {
            configCopy.data.variables = flatVariables;
        }
    }
    if ((_c = (_b = config.tap) === null || _b === void 0 ? void 0 : _b.security) === null || _c === void 0 ? void 0 : _c.scramActivated) {
        if (!configCopy.tap) {
            configCopy.tap = {};
        }
        if (!configCopy.tap.scram) {
            configCopy.tap.scram = {};
        }
        if (!configCopy.tap.scram.hashIteration) {
            configCopy.tap.scram.hashIteration = DEFAULT_HASH_ITERATION_COUNT;
        }
    }
    const hashIteration = (_e = (_d = configCopy.tap) === null || _d === void 0 ? void 0 : _d.scram) === null || _e === void 0 ? void 0 : _e.hashIteration;
    for (const specialProfile of [ADMIN_USER, SUPERVISOR_USER]) {
        if (!flatProfiles.find((p) => p.id === specialProfile.id)) {
            flatProfiles.push({
                id: specialProfile.id,
                password: specialProfile.password || specialProfile.username,
                lifeTime: specialProfile.lifeTime || 30,
            });
        }
    }
    for (const profile of flatProfiles) {
        prepareUserPassword(profile, ((_f = configCopy === null || configCopy === void 0 ? void 0 : configCopy.tap) === null || _f === void 0 ? void 0 : _f.security) || {}, (input) => {
            if (!hashIteration) {
                throw TapConfiguratorError.internalError(`Hash iteration value must be set`);
            }
            const salt = (options === null || options === void 0 ? void 0 : options.saltGenerator)
                ? options.saltGenerator()
                : DEFAULT_SCRAM_SALT_GENERATOR();
            return ScramAuth.createScramPasswordKey(input, {
                salt,
                iterationNumber: hashIteration,
            });
        });
    }
    if (!configCopy.data) {
        configCopy.data = {};
    }
    configCopy.data.profiles = flatProfiles;
    if ((_g = configCopy.application) === null || _g === void 0 ? void 0 : _g.uri) {
        if (typeof configCopy.application.uri === 'object') {
            const appUri = configCopy.application.uri;
            configCopy.application.uri = `${AppPathType[appUri.type]}${appUri.value}`;
        }
    }
    return configCopy;
}
function prepareUserPassword(profile, securityConfig, scramPasswordGenerator) {
    if (profile.password) {
        if (profile.key) {
            throw TapConfiguratorError.invalidConfiguration(`You cannot specify both password and passwordKey for profile configuration. Specify only one of those two options.`);
        }
        if (securityConfig.scramActivated) {
            const passwordBytes = scramPasswordGenerator(profile.password);
            // debug(
            //     `Writing SCRAM password for user id ${userId} with hash: ${bufferToHexString(passwordBytes)}`
            // );
            delete profile.password;
            profile.key = passwordBytes;
        }
        else if (securityConfig.hashPassword) {
            const passwordBytes = hashLoginPassword(profile.password);
            // debug(
            //     `Writing password for user id ${userId} with hash: ${bufferToHexString(
            //         passwordBytes
            //     )}`
            // );
            delete profile.password;
            profile.key = passwordBytes;
        }
        else {
            // debug(
            //     `Writing password for user id ${userId} without hash: ${password}`
            // );
            // OK nothing to do
        }
    }
    // console.log('profile.passwordKey', typeof profile.passwordKey, profile.passwordKey?.constructor?.name);
}
function stepEvent(observer, step, context, extraData) {
    observer.next(Object.assign({ step, progress: {
            loaded: context.index + 1,
            total: context.total,
        } }, (extraData || {})));
}
/**
 * Configure tap from a configuration file schema
 *
 */
export class TapConfiguratorWriter {
    constructor(options = {
        delayMs: 400,
        throwOnNotImplementedConfigKey: false,
    }, host) {
        this.options = options;
        this.host = host;
    }
    createConfiguratorForTap(tap, config, options) {
        return __awaiter(this, void 0, void 0, function* () {
            const firmwareVersion = (yield tap.service.device.getFirmwareVersion()).body();
            return this.configure(tap, firmwareVersion, config, options);
        });
    }
    configure(tap, firmwareVersion, config, options) {
        var _a, _b;
        const configureContext = {
            tap,
            options: config.meta || {},
            tapConfig: config.config,
        };
        const operations = [];
        config = this._adaptConfigurationToCurrentVersion(config);
        if (!(options === null || options === void 0 ? void 0 : options.skipSchemaValidation)) {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                stepEvent(observer, TapConfiguratorWriter.Step.validatesConfig, context);
                validateTapConfiguratorConfig(config);
            }));
        }
        if (!configureContext.options.skipFactoryReset) {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                stepEvent(observer, TapConfiguratorWriter.Step.factoryReset, context);
                (yield tap.service.device.factoryReset()).successful();
            }));
        }
        const useScram = !!((_b = (_a = configureContext.tapConfig.tap) === null || _a === void 0 ? void 0 : _a.security) === null || _b === void 0 ? void 0 : _b.scramActivated);
        if (useScram) {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                stepEvent(observer, TapConfiguratorWriter.Step.enableSecureCom, context);
                if (useScram) {
                    yield tap.encryption.start();
                }
            }));
        }
        const calls = tapConfigToServiceCalls(configureContext.tapConfig, {
            firmwareVersion,
            service: tap.service,
        });
        // operations.push(async (observer, context) => {
        //     observer.next({
        //         step: TapConfigurator.Step.
        //     } as TapConfigurator.Event);
        //     const firmwareVersion = (await context.tap.service.device.getFirmwareVersion()).body();
        // });
        // operations.push(
        //     async (observer, context) => {
        //         stepEvent(observer, TapConfiguratorWriter.Step.setupConfigurationState, context);
        //         await this.setupConfigState(configureContext.tap);
        //     }
        // );
        // if (useScram) {
        //     operations.push(async (observer, context) => {
        //         // To write user password keys, we need to put scram configuration first
        //         stepEvent(observer, TapConfiguratorWriter.Step.writeSecurityOptions, context);
        //         tap.encryption.pause();
        //         (await tap.service.interface.putSecurityOptions({
        //             scramActivated: true
        //         } as SecurityOptions)).successful();
        //         tap.encryption.resume();
        //     });
        // }
        this.addConfigurCalls(configureContext, calls, operations);
        // operations.push(
        //     async (observer, context) => {
        //         stepEvent(observer, TapConfiguratorWriter.Step.applyConfig, context);
        //         await this.applyConfig(configureContext.tap, configureContext.tapConfig.version || '1.0.0');
        //     }
        // );
        operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
            stepEvent(observer, TapConfiguratorWriter.Step.logout, context);
            yield configureContext.tap.auth.logout();
            tap.auth.clearCache();
        }));
        return StepOperations.sequential(operations);
    }
    setupConfigState(tap) {
        return __awaiter(this, void 0, void 0, function* () {
            const state = (yield tap.service.firmware.getState()).body();
            if (state !== FirmwareState.NORMAL) {
                throw TapConfiguratorError.unexpectedFirmwareState(state);
            }
            (yield tap.service.interface.putConfigVersion('255.255.65535')).successful();
        });
    }
    // TODO move from here
    isConfigured(tap) {
        return __awaiter(this, void 0, void 0, function* () {
            const configVersionCalled = yield tap.service.interface.getConfigVersion();
            configVersionCalled.successful();
            const intValue = configVersionCalled.body(NumberConverter.uint32());
            return intValue !== 0;
        });
    }
    /***
     *
     */
    applyConfig(tap, newVersion = '1.0.0') {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.sleep(this.options.delayMs);
            (yield tap.service.interface.putConfigVersion(newVersion)).successful();
            yield this.sleep(this.options.delayMs);
            (yield tap.service.interface.reloadConfig()).successful();
            yield this.sleep(this.options.delayMs);
        });
    }
    addConfigurCalls(configureContext, calls, operations) {
        calls.forEach((callOrError, index) => {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                const stepProgress = {
                    total: calls.length,
                    loaded: index + 1,
                };
                if (callOrError instanceof Error) {
                    stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                        error: callOrError,
                        stepProgress,
                    });
                }
                else {
                    stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                        stepProgress,
                        call: callOrError,
                    });
                    try {
                        (yield configureContext.tap.lwm2m.execute(callOrError)).successful();
                    }
                    catch (err) {
                        if (!this.options.throwOnNotImplementedConfigKey &&
                            isCodeError(TapError.Code.ResponseStatusError, err)) {
                            const responseStatusError = err;
                            if (responseStatusError.response.status ===
                                ResultCode.NOT_IMPLEMENTED) {
                                stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                                    error: err,
                                    stepProgress,
                                });
                                return;
                            }
                        }
                        throw err;
                    }
                }
            }));
        });
    }
    sleep(delayMs) {
        return sleep(delayMs);
    }
    _adaptConfigurationToCurrentVersion(config) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        if (config.config.wireless) {
            let blePairing = undefined;
            let nfcPairingMode;
            if (((_c = (_b = (_a = config.config.wireless) === null || _a === void 0 ? void 0 : _a.protocols) === null || _b === void 0 ? void 0 : _b.nfc) === null || _c === void 0 ? void 0 : _c.pairingMode) !== undefined) {
                nfcPairingMode = config.config.wireless.protocols.nfc.pairingMode;
                delete config.config.wireless.protocols.nfc.pairingMode;
            }
            if (((_f = (_e = (_d = config.config.wireless) === null || _d === void 0 ? void 0 : _d.protocols) === null || _e === void 0 ? void 0 : _e.ble) === null || _f === void 0 ? void 0 : _f.pairing) !== undefined) {
                blePairing = (_j = (_h = (_g = config.config.wireless) === null || _g === void 0 ? void 0 : _g.protocols) === null || _h === void 0 ? void 0 : _h.ble) === null || _j === void 0 ? void 0 : _j.pairing;
                (_k = config.config.wireless.protocols.ble) === null || _k === void 0 ? true : delete _k.pairing;
            }
            if (!config.config.wireless.options) {
                config.config.wireless.options = {};
            }
            if (blePairing !== undefined || nfcPairingMode !== undefined) {
                config.config.wireless.options.pairing = {
                    nfcPairingMode,
                    blePairing,
                };
            }
        }
        return config;
    }
}
(function (TapConfiguratorWriter) {
    let Step;
    (function (Step) {
        Step["validatesConfig"] = "TapConfiguratorStepValidatesConfig";
        Step["enableSecureCom"] = "TapConfiguratorStepenableSecureCommunication";
        Step["factoryReset"] = "TapConfiguratorStepFactoryReset";
        Step["setupConfigurationState"] = "TapConfiguratorStepSetupConfigurationState";
        Step["executeCall"] = "TapConfiguratorStepExecuteCall";
        Step["logout"] = "TapConfiguratorSteplogout";
        Step["applyConfig"] = "TapConfiguratorStepApplyConfig";
        Step["writeSecurityOptions"] = "TapConfiguratorStepWriteSecurityOptions";
    })(Step = TapConfiguratorWriter.Step || (TapConfiguratorWriter.Step = {}));
})(TapConfiguratorWriter || (TapConfiguratorWriter = {}));
//# sourceMappingURL=data:application/json;base64, 