import { CodeError } from '@iotize/common/error';
import { FirmwareState } from '@iotize/tap/service/impl/firmware';
import { SpecialFeature, AppPathType } from '@iotize/tap';
import { CloudPlatform, LowPowerOptimizationLevel, TargetProtocol, HostProtocol, NfcConnectionPriority, NfcPairingMode, WifiKeyVisibility, WifiMode, WifiProtocol, WifiSSIDVisibility, VariableType, converters, FirmwareState as FirmwareState$1 } from '@iotize/tap/service/all';
import { deepCopy, sleep } from '@iotize/common/utility';
import { StepOperations } from '@iotize/common/task-manager';
import { hexStringToBuffer } from '@iotize/common/byte-converter';
import { DEFAULT_SCRAM_SALT_GENERATOR, ScramAuth, hashLoginPassword } from '@iotize/tap/auth';
import { TapStreamWriter, NumberConverter } from '@iotize/tap/client/impl';
import { TapConfigJsonSchema, CommonTypeJsonSchema, TapTypeJsonSchema } from '@iotize/tap/config/schema/v1';
import Ajv from 'ajv';
import { VariableMetaConfigConverter } from '@iotize/tap/service/impl/variable';
import { TapRequestFrame } from '@iotize/tap/client/api';
import { variableDataTypeToByteSize, getConverterFromVariableType } from '@iotize/tap/data';

/**
 * TODO move to TapConfiguratorError
 */
class ConfigKeyNotSupportedByFirmwareVersion extends Error {
    constructor(configKey, firmwareVersion, constraint) {
        super(`Configuration key "${configKey}" is not available for you firmware version (${firmwareVersion}). \
${constraint.minApiVersion ? `Minimal firmware version: ${constraint.minApiVersion}.` : ''}\
${constraint.maxApiVersion ? `Maximal firmware version: ${constraint.maxApiVersion}.` : ''}`);
        this.configKey = configKey;
        this.firmwareVersion = firmwareVersion;
        this.constraint = constraint;
    }
}
class TapConfiguratorError extends CodeError {
    constructor(code, msg, cause) {
        super(msg, code);
        this.cause = cause;
    }
    static internalError(msg, cause) {
        return new TapConfiguratorError(TapConfiguratorError.Code.InternalError, msg, cause);
    }
    static unexpectedFirmwareState(state) {
        return new TapConfiguratorError(TapConfiguratorError.Code.UnexpectedFirmwareState, `Firmware state is not in expected mode. It should be ${FirmwareState.NORMAL} but found ${state}`);
    }
    static invalidConfiguration(message) {
        return new TapConfiguratorError(TapConfiguratorError.Code.InvalidSchema, message);
    }
}
(function (TapConfiguratorError) {
    let Code;
    (function (Code) {
        Code["UnexpectedFirmwareState"] = "TapConfiguratorErrorUnexpectedFirmwareState";
        Code["InvalidSchema"] = "TapConfiguratorErrorIvalidSchema";
        Code["InternalError"] = "TapConfiguratorErrorInternalError";
    })(Code = TapConfiguratorError.Code || (TapConfiguratorError.Code = {}));
    class InvalidSchemaError extends TapConfiguratorError {
        constructor(validate) {
            super(Code.InvalidSchema, `\
Invalid Tap configuration file:
${InvalidSchemaError.ajvErrorsToString(validate.errors)}`);
            this.validate = validate;
            this.errors = this.validate.errors || [];
        }
        static ajvErrorsToString(errors) {
            // console.log('errors', JSON.stringify(errors, undefined, 4));
            return errors
                ? errors
                    .map(error => {
                    let message;
                    switch (error.keyword) {
                        case 'additionalProperties':
                            const params = error.params;
                            message = `${error.dataPath} should not have additional property "${params.additionalProperty}"`;
                            break;
                        default:
                            message = `${error.dataPath} ${error.message} (keyword: ${error.keyword})`;
                    }
                    return `\t- ${message}`;
                })
                    .join('\n')
                : 'Unknown errors';
        }
    }
    TapConfiguratorError.InvalidSchemaError = InvalidSchemaError;
})(TapConfiguratorError || (TapConfiguratorError = {}));

const ANONYMOUS_USER = {
    username: 'anonymous',
    password: '',
    id: 0,
    lifeTime: 30
};
const ADMIN_USER = {
    username: 'admin',
    password: 'admin',
    id: 0xffff,
    lifeTime: 30
};
const SUPERVISOR_USER = {
    username: 'supervisor',
    password: 'supervisor',
    id: 0xfffe,
    lifeTime: 30
};
const SPECIAL_USERS = [
    ANONYMOUS_USER,
    ADMIN_USER,
    SUPERVISOR_USER
];
const DEFAULT_HASH_ITERATION_COUNT = 5000;

function getProfileIdFromConfig(profile) {
    const specialUserInfo = SPECIAL_USERS.find(v => profile.username === v.username);
    if (specialUserInfo) {
        return specialUserInfo.id;
    }
    const profileId = profile['id']; // TODO check
    if (profileId === undefined) {
        throw TapConfiguratorError.invalidConfiguration(`Profile id is required for ${profile['username']}`);
    }
    return profileId;
}
function isTapFirmwareVersionGreaterThanOrEqual(fwVersionString, version) {
    fwVersionString = fwVersionString
        .split(' ', 1)[0]
        .padStart(10, '0')
        .padEnd(10, '0');
    version = version.padStart(10, '0').padEnd(10, '0');
    // console.info(`${fwVersionString} >= ${version}`)
    return fwVersionString >= version;
}
function isTapFirmwareVersionLessThanOrEqual(fwVersionString, version) {
    fwVersionString = fwVersionString
        .split(' ', 1)[0]
        .padStart(10, '0')
        .padEnd(10, '0');
    version = version.padStart(10, '0').padEnd(10, '0');
    // console.info(`${fwVersionString} >= ${version}`)
    return fwVersionString <= version;
}
function enumKeyToEnumValue(value, enumMapping) {
    return toEnum(value, enumMapping);
}
function enumKeysToEnumValues(values, enumMapping) {
    return values.map(value => enumKeyToEnumValue(value, enumMapping));
}
/**
 * Convert
 */
function toEnum(value, enumMapping) {
    if (!value) {
        throw new Error(`Missing first attribute for toEnum. ${Object.keys(enumMapping).join(', ')}`);
    }
    if (typeof value !== 'string') {
        throw new Error(`Enum key must be a string. Given: ${JSON.stringify(value)}. ${Object.keys(enumMapping).join(', ')}`);
    }
    value = value.toUpperCase();
    if (!(value in enumMapping)) {
        throw new Error(`Missing enum value "${value}". Available: ${Object.keys(enumMapping).join(', ')}`);
    }
    return enumMapping[value];
}
function enumToString(value, mapping) {
    if (!(value in mapping)) {
        throw new Error(`Missing mapping for ${value}. Available: ${Object.keys(mapping).join(', ')}`);
    }
    return mapping[value];
}
function isSpecialProfileUsername(username) {
    return SPECIAL_USERS.filter(v => username === v.username).length > 0;
}
function isSpecialProfileId(id) {
    return SPECIAL_USERS.filter(v => id === v.id).length > 0;
}
function configValueToBytes(input) {
    if (input instanceof Uint8Array) {
        return input;
    }
    else if (typeof input === 'string') {
        return hexStringToBuffer(input);
    }
    else {
        return Uint8Array.from(input);
    }
}
function getByAttr(filterKey, v, data) {
    let array;
    if (Array.isArray(data)) {
        array = data;
    }
    else {
        array = Object.keys(data).map(key => data[key]);
    }
    return array.filter((value) => value[filterKey] == v)[0] || undefined;
}

/**
 *   Generated file. Do not edit
 */
const ɵ0 = (context) => {
    return context.service.interface.putApplicationDataCall(configValueToBytes(context.value));
}, ɵ1 = (context) => {
    return context.service.interface.putAppNameCall(context.value);
}, ɵ2 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.113")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("application.productCode", context.firmwareVersion, {
                minApiVersion: "1.113",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.putProductCodeCall(context.value);
}, ɵ3 = (context) => {
    return context.service.interface.putUniversalLinkCall(context.value);
}, ɵ4 = (context) => {
    return context.service.interface.putAppPathCall(context.value);
}, ɵ5 = (context) => {
    return context.service.cloud.putDataLogPublishTopicCall(context.value);
}, ɵ6 = (context) => {
    return context.service.cloud.putDataLogSubscribeTopicCall(context.value);
}, ɵ7 = (context) => {
    return context.service.cloud.putDataLogUploadPeriodCall(context.value);
}, ɵ8 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.brokerPort", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.putMqttBrokerPortCall(context.value);
}, ɵ9 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.clientId", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.putMqttClientIdCall(context.value);
}, ɵ10 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.password", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.putMqttPasswordCall(context.value);
}, ɵ11 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.username", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.putMqttUsernameCall(context.value);
}, ɵ12 = (context) => {
    return context.service.cloud.putPlatformCall(enumKeyToEnumValue(context.value, CloudPlatform));
}, ɵ13 = (context) => {
    return context.service.bundle.createCall(context.param);
}, ɵ14 = (context) => {
    return context.service.bundle.putAclCall(context.param, context.value);
}, ɵ15 = (context) => {
    return context.service.bundle.putDataLogPeriodCall(context.param, context.value);
}, ɵ16 = (context) => {
    return context.service.bundle.putNameCall(context.param, context.value);
}, ɵ17 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.23")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("data.features[].bundleId", context.firmwareVersion, {
                minApiVersion: "1.23",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.setSpecialFeatureProfileCall(context.param, context.value);
}, ɵ18 = (context) => {
    return context.service.group.createCall(context.param);
}, ɵ19 = (context) => {
    return context.service.group.putAliasCall(context.param, context.value);
}, ɵ20 = (context) => {
    return context.service.group.changePasswordKeyCall(context.param, configValueToBytes(context.value));
}, ɵ21 = (context) => {
    return context.service.group.putSessionLifetimeCall(context.param, context.value);
}, ɵ22 = (context) => {
    return context.service.group.changePasswordCall(context.param, context.value);
}, ɵ23 = (context) => {
    return context.service.group.putNameCall(context.param, context.value);
}, ɵ24 = (context) => {
    return context.service.variable.createCall(context.param, context.value);
}, ɵ25 = (context) => {
    return context.service.variable.putVariableAddressCall(context.param, context.value);
}, ɵ26 = (context) => {
    return context.service.variable.putBundleIdCall(context.param, context.value);
}, ɵ27 = (context) => {
    return context.service.variable.putNumberOfElementsCall(context.param, context.value);
}, ɵ28 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.73")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("data.variables[].meta", context.firmwareVersion, {
                minApiVersion: "1.73",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.variable.putMetaCall(context.param, context.value);
}, ɵ29 = (context) => {
    return context.service.variable.putModbusVariableAddressCall(context.param, context.value);
}, ɵ30 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.73")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("data.variables[].rawMeta", context.firmwareVersion, {
                minApiVersion: "1.73",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.variable.putRawMetaCall(context.param, configValueToBytes(context.value));
}, ɵ31 = (context) => {
    return context.service.variable.putTypeCall(context.param, context.value);
}, ɵ32 = (context) => {
    return context.service.variable.setValueCall(context.param, configValueToBytes(context.value));
}, ɵ33 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.90")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("jvm.code", context.firmwareVersion, {
                minApiVersion: "1.90",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.jvm.appendCodeAppendCalls(configValueToBytes(context.value));
}, ɵ34 = (context) => {
    return context.service.jvm.putProfileIdCall(context.value);
}, ɵ35 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.certificate.privateKey", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.putCertificatePrivateKeyAppendCalls(configValueToBytes(context.value));
}, ɵ36 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.certificate.publicKey", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.putCertificatePublicKeyAppendCalls(configValueToBytes(context.value));
}, ɵ37 = (context) => {
    return context.service.interface.putPowerOptimisationLevelCall(enumKeyToEnumValue(context.value, LowPowerOptimizationLevel));
}, ɵ38 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.11")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.scram.hashIteration", context.firmwareVersion, {
                minApiVersion: "1.11",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.scram.putHashIterationCall(context.value);
}, ɵ39 = (context) => {
    return context.service.interface.putSecurityOptionsCall(context.value);
}, ɵ40 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.107")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.time.ntpServer", context.firmwareVersion, {
                minApiVersion: "1.107",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.time.putNtpServerCall(context.value);
}, ɵ41 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.107")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.time.zone", context.firmwareVersion, {
                minApiVersion: "1.107",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.time.putTimeZoneCall(context.value);
}, ɵ42 = (context) => {
    return context.service.target.putFirmwareVersionCall(context.value);
}, ɵ43 = (context) => {
    return context.service.target.putSerialModbusConfigurationCall(context.value);
}, ɵ44 = (context) => {
    return context.service.target.putProtocolCall(enumKeyToEnumValue(context.value, TargetProtocol));
}, ɵ45 = (context) => {
    return context.service.interface.putConfigVersionCall(context.value);
}, ɵ46 = (context) => {
    return context.service.interface.putAuthorizedHostProtocolCall(enumKeysToEnumValues(context.value, HostProtocol));
}, ɵ47 = (context) => {
    return context.service.interface.putHostInactivityPeriodCall(context.value);
}, ɵ48 = (context) => {
    return context.service.lora.putConfigCall(context.value);
}, ɵ49 = (context) => {
    return context.service.lora.putIdsCall(configValueToBytes(context.value));
}, ɵ50 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.brokerCertificate", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.putBrokerCertificateAppendCalls(configValueToBytes(context.value));
}, ɵ51 = (context) => {
    return context.service.mqtt.putBrokerHostnameCall(context.value);
}, ɵ52 = (context) => {
    return context.service.mqtt.putBrokerPortCall(context.value);
}, ɵ53 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.clientId", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.putClientIdCall(context.value);
}, ɵ54 = (context) => {
    return context.service.mqtt.putPasswordCall(context.value);
}, ɵ55 = (context) => {
    return context.service.mqtt.putRelayNetKeyCall(context.value);
}, ɵ56 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.requestTopic", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.putRequestTopicCall(context.value);
}, ɵ57 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.107")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.responseTopic", context.firmwareVersion, {
                minApiVersion: "1.107",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.putResponseTopicCall(context.value);
}, ɵ58 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.topicPrefix", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.putTopicPrefixCall(context.value);
}, ɵ59 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.username", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.putUsernameCall(context.value);
}, ɵ60 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.55")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.nfc.autoLogProfileId", context.firmwareVersion, {
                minApiVersion: "1.55",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.putNfcAutologProfileIdCall(context.value);
}, ɵ61 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.85")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.nfc.connectionPriority", context.firmwareVersion, {
                minApiVersion: "1.85",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.putNfcConnectionPriorityCall(enumKeyToEnumValue(context.value, NfcConnectionPriority));
}, ɵ62 = (context) => {
    return context.service.interface.putNfcPairingModeCall(enumKeyToEnumValue(context.value, NfcPairingMode));
}, ɵ63 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.countryCode", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.putCountryCodeCall(context.value);
}, ɵ64 = (context) => {
    return context.service.wifi.putGatewayIpCall(context.value);
}, ɵ65 = (context) => {
    return context.service.wifi.putIpCall(context.value);
}, ɵ66 = (context) => {
    return context.service.wifi.putKeyCall(context.value);
}, ɵ67 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.keyVisibility", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.putKeyVisibilityCall(enumKeyToEnumValue(context.value, WifiKeyVisibility));
}, ɵ68 = (context) => {
    return context.service.wifi.putIpMaskCall(context.value);
}, ɵ69 = (context) => {
    return context.service.wifi.putModeCall(enumKeyToEnumValue(context.value, WifiMode));
}, ɵ70 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.protocol", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.putProtocolCall(enumKeysToEnumValues(context.value, WifiProtocol));
}, ɵ71 = (context) => {
    return context.service.wifi.putSSIDCall(context.value);
}, ɵ72 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.ssidVisibility", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.putSSIDVisibilityCall(enumKeyToEnumValue(context.value, WifiSSIDVisibility));
}, ɵ73 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.txPower", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.putTxPowerCall(context.value);
};
const WRITE_CONFIGURATOR_CONFIG = {
    "application.data": ɵ0,
    "application.name": ɵ1,
    "application.productCode": ɵ2,
    "application.universalLink": ɵ3,
    "application.uri": ɵ4,
    "cloud.dataLog.mqttPublishTopic": ɵ5,
    "cloud.dataLog.mqttSubscribeTopic": ɵ6,
    "cloud.dataLog.uploadPeriod": ɵ7,
    "cloud.mqtt.brokerPort": ɵ8,
    "cloud.mqtt.clientId": ɵ9,
    "cloud.mqtt.password": ɵ10,
    "cloud.mqtt.username": ɵ11,
    "cloud.platform": ɵ12,
    "data.bundles[]": ɵ13,
    "data.bundles[].acl[].$": ɵ14,
    "data.bundles[].dataLog.period": ɵ15,
    "data.bundles[].name": ɵ16,
    "data.features[].bundleId": ɵ17,
    "data.profiles[]": ɵ18,
    "data.profiles[].alias": ɵ19,
    "data.profiles[].key": ɵ20,
    "data.profiles[].lifeTime": ɵ21,
    "data.profiles[].password": ɵ22,
    "data.profiles[].username": ɵ23,
    "data.variables[]": ɵ24,
    "data.variables[].address": ɵ25,
    "data.variables[].bundleId": ɵ26,
    "data.variables[].length": ɵ27,
    "data.variables[].meta": ɵ28,
    "data.variables[].modbusAddress": ɵ29,
    "data.variables[].rawMeta": ɵ30,
    "data.variables[].type": ɵ31,
    "data.variables[].value": ɵ32,
    "jvm.code": ɵ33,
    "jvm.profileId": ɵ34,
    "tap.certificate.privateKey": ɵ35,
    "tap.certificate.publicKey": ɵ36,
    "tap.powerOptimization": ɵ37,
    "tap.scram.hashIteration": ɵ38,
    "tap.security": ɵ39,
    "tap.time.ntpServer": ɵ40,
    "tap.time.zone": ɵ41,
    "target.firmwareVersion": ɵ42,
    "target.protocol.config": ɵ43,
    "target.protocol.type": ɵ44,
    version: ɵ45,
    "wireless.options.authorizedProtocols": ɵ46,
    "wireless.options.inactivityTimeout": ɵ47,
    "wireless.protocols.lora.config": ɵ48,
    "wireless.protocols.lora.ids": ɵ49,
    "wireless.protocols.mqtt.brokerCertificate": ɵ50,
    "wireless.protocols.mqtt.brokerHostname": ɵ51,
    "wireless.protocols.mqtt.brokerPort": ɵ52,
    "wireless.protocols.mqtt.clientId": ɵ53,
    "wireless.protocols.mqtt.password": ɵ54,
    "wireless.protocols.mqtt.relayNetKey": ɵ55,
    "wireless.protocols.mqtt.requestTopic": ɵ56,
    "wireless.protocols.mqtt.responseTopic": ɵ57,
    "wireless.protocols.mqtt.topicPrefix": ɵ58,
    "wireless.protocols.mqtt.username": ɵ59,
    "wireless.protocols.nfc.autoLogProfileId": ɵ60,
    "wireless.protocols.nfc.connectionPriority": ɵ61,
    "wireless.protocols.nfc.pairingMode": ɵ62,
    "wireless.protocols.wifi.countryCode": ɵ63,
    "wireless.protocols.wifi.gatewayIp": ɵ64,
    "wireless.protocols.wifi.ip": ɵ65,
    "wireless.protocols.wifi.key": ɵ66,
    "wireless.protocols.wifi.keyVisibility": ɵ67,
    "wireless.protocols.wifi.mask": ɵ68,
    "wireless.protocols.wifi.mode": ɵ69,
    "wireless.protocols.wifi.protocol": ɵ70,
    "wireless.protocols.wifi.ssid": ɵ71,
    "wireless.protocols.wifi.ssidVisibility": ɵ72,
    "wireless.protocols.wifi.txPower": ɵ73
};

const TSTYPE_CLASS = {
    Uint8Array
};
const ɵ0$1 = (schema) => {
    const classObject = TSTYPE_CLASS[schema];
    return function (data) {
        return !classObject || data instanceof classObject;
    };
};
const tsTypeKeyword = {
    compile: ɵ0$1
};
function getJsonSchemaValidator(schemas) {
    schemas = schemas || [
        TapConfigJsonSchema,
        CommonTypeJsonSchema,
        TapTypeJsonSchema
    ];
    const ajv = new Ajv({
        schemas
    });
    ajv.addKeyword('tsType', tsTypeKeyword);
    const schemaId = 'http://iotize.com/schemas/v1/tap-config.json'; // TODO config must match schema api file value
    const validator = ajv.getSchema(schemaId);
    if (!validator) {
        throw new Error(`Cannot create JSON validator function from schema ${schemaId}`);
    }
    return validator;
}
// export function checkErrors(config: Object) {
//     const validator = getJsonSchemaValidator();
//     validator(config);
//     return validator.errors;
// }
/**
 * Validate schema. Throw error if schema is not valid
 * @throws @{link TapConfiguratorError}
 * @param config the tap config object
 * @param schemas optial schema used for validation. If not provided, default one will be used
 *
 * @returns validator function
 */
function validateTapConfiguratorConfig(config, schemas) {
    const validator = getJsonSchemaValidator(schemas);
    const valid = validator(config);
    if (!valid) {
        throw new TapConfiguratorError.InvalidSchemaError(validator);
    }
    return validator;
}
function parseTapConfiguratorConfig(input) {
    let config;
    try {
        config = JSON.parse(input);
    }
    catch (err) {
        throw new Error(`Cannot parse Tap configurator config content. ${err.message}`);
    }
    validateTapConfiguratorConfig(config);
    return config;
}

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());
    });
};
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])*$/);
}
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.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
                    }));
                }
                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;
                    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}`);
}
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);
}
function toVariableFlatConfig(variable, bundle) {
    const variableLength = variable.length || 1;
    const variableDataType = variable.dataType === undefined ? VariableType.Data.UINT8 : VariableType.Data[variable.dataType];
    const variableType = {
        domain: variable.domain === undefined ? VariableType.Domain.TARGET : VariableType.Domain[variable.domain],
        data: variableDataType
    };
    const variableFlatConfig = {
        id: variable.id,
        length: variableLength,
        type: {
            domain: VariableType.Domain[variableType.domain],
            data: VariableType.Data[variableType.data]
        },
        bundleId: bundle.id
    };
    if (variable.address !== undefined) {
        variableFlatConfig.address = variable.address;
    }
    if (variable.rawMeta !== undefined) {
        variableFlatConfig.rawMeta = typeof variable.rawMeta === 'string' ? hexStringToBuffer(variable.rawMeta) : variable.rawMeta;
    }
    if (variable.modbusAddress !== undefined) {
        variableFlatConfig.modbusAddress = variable.modbusAddress;
    }
    if (variable.meta) {
        if (typeof variable.meta === 'object') {
            variableFlatConfig.rawMeta = variableMetaConverter.encode(variable.meta);
        }
        else {
            variableFlatConfig.rawMeta = hexStringToBuffer(variable.meta);
        }
        // delete variable.meta;
    }
    if (variable.value !== undefined && variable.value !== null) {
        variableFlatConfig.value = encodeInitialVariableValue(variable, bundle);
    }
    return variableFlatConfig;
}
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
 *
 */
class TapConfiguratorWriter {
    constructor(options = {
        delayMs: 400
    }, 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 = [];
        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$1.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* () {
                if (callOrError instanceof Error) {
                    // TODO 
                    stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                        error: callOrError,
                        stepProgress: {
                            total: calls.length,
                            loaded: index + 1
                        }
                        // call: callOrError
                    });
                }
                else {
                    stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                        stepProgress: {
                            total: calls.length,
                            loaded: index + 1
                        },
                        call: callOrError
                    });
                    (yield configureContext.tap.lwm2m.execute(callOrError)).successful();
                }
            }));
        });
    }
    sleep(delayMs) {
        return sleep(delayMs);
    }
}
(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 = {}));

/**
 *   Generated file. Do not edit
 */
const ɵ0$2 = (context) => {
    return context.service.interface.getApplicationDataCall();
}, ɵ1$1 = (context) => {
    return context.service.interface.getAppNameCall();
}, ɵ2$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.113")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("application.productCode", context.firmwareVersion, {
                minApiVersion: "1.113",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.getProductCodeCall();
}, ɵ3$1 = (context) => {
    return context.service.interface.getUniversalLinkCall();
}, ɵ4$1 = (context) => {
    return context.service.interface.getAppPathCall();
}, ɵ5$1 = (context) => {
    return context.service.cloud.getDataLogPublishTopicCall();
}, ɵ6$1 = (context) => {
    return context.service.cloud.getDataLogSubscribeTopicCall();
}, ɵ7$1 = (context) => {
    return context.service.cloud.getDataLogUploadPeriodCall();
}, ɵ8$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.brokerPort", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.getMqttBrokerPortCall();
}, ɵ9$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.clientId", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.getMqttClientIdCall();
}, ɵ10$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.password", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.getMqttPasswordCall();
}, ɵ11$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionLessThanOrEqual(context.firmwareVersion, "1.103")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("cloud.mqtt.username", context.firmwareVersion, {
                minApiVersion: undefined,
                maxApiVersion: "1.103"
            });
        }
    }
    return context.service.cloud.getMqttUsernameCall();
}, ɵ12$1 = (context) => {
    return context.service.cloud.getPlatformCall();
}, ɵ13$1 = (context) => {
    return context.service.interface.getConfigFormatVersionCall();
}, ɵ14$1 = (context) => {
    return context.service.bundle.getDataLogPeriodCall(context.param);
}, ɵ15$1 = (context) => {
    return context.service.bundle.getNameCall(context.param);
}, ɵ16$1 = (context) => {
    return context.service.group.getAliasCall(context.param);
}, ɵ17$1 = (context) => {
    return context.service.group.getSessionLifetimeCall(context.param);
}, ɵ18$1 = (context) => {
    return context.service.group.getNameCall(context.param);
}, ɵ19$1 = (context) => {
    return context.service.variable.getVariableAddressCall(context.param);
}, ɵ20$1 = (context) => {
    return context.service.variable.getBundleIdCall(context.param);
}, ɵ21$1 = (context) => {
    return context.service.variable.getNumberOfElementsCall(context.param);
}, ɵ22$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.73")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("data.variables[].meta", context.firmwareVersion, {
                minApiVersion: "1.73",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.variable.getMetaCall(context.param);
}, ɵ23$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.73")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("data.variables[].rawMeta", context.firmwareVersion, {
                minApiVersion: "1.73",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.variable.getRawMetaCall(context.param);
}, ɵ24$1 = (context) => {
    return context.service.variable.getTypeCall(context.param);
}, ɵ25$1 = (context) => {
    return context.service.jvm.getProfileIdCall();
}, ɵ26$1 = (context) => {
    return context.service.interface.getPowerOptimisationLevelCall();
}, ɵ27$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.11")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.scram.hashIteration", context.firmwareVersion, {
                minApiVersion: "1.11",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.scram.getHashIterationCall();
}, ɵ28$1 = (context) => {
    return context.service.interface.getSecurityOptionsCall();
}, ɵ29$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.107")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.time.ntpServer", context.firmwareVersion, {
                minApiVersion: "1.107",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.time.getNtpServerCall();
}, ɵ30$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.107")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("tap.time.zone", context.firmwareVersion, {
                minApiVersion: "1.107",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.time.getTimeZoneCall();
}, ɵ31$1 = (context) => {
    return context.service.target.getFirmwareVersionCall();
}, ɵ32$1 = (context) => {
    return context.service.target.getSerialModbusConfigurationCall();
}, ɵ33$1 = (context) => {
    return context.service.target.getProtocolCall();
}, ɵ34$1 = (context) => {
    return context.service.interface.getConfigVersionCall();
}, ɵ35$1 = (context) => {
    return context.service.interface.getAuthorizedHostProtocolCall();
}, ɵ36$1 = (context) => {
    return context.service.interface.getHostInactivityPeriodCall();
}, ɵ37$1 = (context) => {
    return context.service.lora.getConfigCall();
}, ɵ38$1 = (context) => {
    return context.service.lora.getIdsCall();
}, ɵ39$1 = (context) => {
    return context.service.mqtt.getBrokerHostnameCall();
}, ɵ40$1 = (context) => {
    return context.service.mqtt.getBrokerPortCall();
}, ɵ41$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.clientId", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.getClientIdCall();
}, ɵ42$1 = (context) => {
    return context.service.mqtt.getPasswordCall();
}, ɵ43$1 = (context) => {
    return context.service.mqtt.getRelayNetKeyCall();
}, ɵ44$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.86")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.mqtt.username", context.firmwareVersion, {
                minApiVersion: "1.86",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.mqtt.getUsernameCall();
}, ɵ45$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.55")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.nfc.autoLogProfileId", context.firmwareVersion, {
                minApiVersion: "1.55",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.getNfcAutologProfileIdCall();
}, ɵ46$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.85")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.nfc.connectionPriority", context.firmwareVersion, {
                minApiVersion: "1.85",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.interface.getNfcConnectionPriorityCall();
}, ɵ47$1 = (context) => {
    return context.service.interface.getNfcPairingModeCall();
}, ɵ48$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.countryCode", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.getCountryCodeCall();
}, ɵ49$1 = (context) => {
    return context.service.wifi.getGatewayIpCall();
}, ɵ50$1 = (context) => {
    return context.service.wifi.getIpCall();
}, ɵ51$1 = (context) => {
    return context.service.wifi.getKeyCall();
}, ɵ52$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.keyVisibility", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.getKeyVisibilityCall();
}, ɵ53$1 = (context) => {
    return context.service.wifi.getIpMaskCall();
}, ɵ54$1 = (context) => {
    return context.service.wifi.getModeCall();
}, ɵ55$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.protocol", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.getProtocolCall();
}, ɵ56$1 = (context) => {
    return context.service.wifi.getSSIDCall();
}, ɵ57$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.ssidVisibility", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.getSSIDVisibilityCall();
}, ɵ58$1 = (context) => {
    if (context.firmwareVersion) {
        if (!isTapFirmwareVersionGreaterThanOrEqual(context.firmwareVersion, "1.88")) {
            return new ConfigKeyNotSupportedByFirmwareVersion("wireless.protocols.wifi.txPower", context.firmwareVersion, {
                minApiVersion: "1.88",
                maxApiVersion: undefined
            });
        }
    }
    return context.service.wifi.getTxPowerCall();
};
const READ_CONFIGURATOR_CONFIG = {
    "application.data": ɵ0$2,
    "application.name": ɵ1$1,
    "application.productCode": ɵ2$1,
    "application.universalLink": ɵ3$1,
    "application.uri": ɵ4$1,
    "cloud.dataLog.mqttPublishTopic": ɵ5$1,
    "cloud.dataLog.mqttSubscribeTopic": ɵ6$1,
    "cloud.dataLog.uploadPeriod": ɵ7$1,
    "cloud.mqtt.brokerPort": ɵ8$1,
    "cloud.mqtt.clientId": ɵ9$1,
    "cloud.mqtt.password": ɵ10$1,
    "cloud.mqtt.username": ɵ11$1,
    "cloud.platform": ɵ12$1,
    configFormatVersion: ɵ13$1,
    "data.bundles[].dataLog.period": ɵ14$1,
    "data.bundles[].name": ɵ15$1,
    "data.profiles[].alias": ɵ16$1,
    "data.profiles[].lifeTime": ɵ17$1,
    "data.profiles[].username": ɵ18$1,
    "data.variables[].address": ɵ19$1,
    "data.variables[].bundleId": ɵ20$1,
    "data.variables[].length": ɵ21$1,
    "data.variables[].meta": ɵ22$1,
    "data.variables[].rawMeta": ɵ23$1,
    "data.variables[].type": ɵ24$1,
    "jvm.profileId": ɵ25$1,
    "tap.powerOptimization": ɵ26$1,
    "tap.scram.hashIteration": ɵ27$1,
    "tap.security": ɵ28$1,
    "tap.time.ntpServer": ɵ29$1,
    "tap.time.zone": ɵ30$1,
    "target.firmwareVersion": ɵ31$1,
    "target.protocol.config": ɵ32$1,
    "target.protocol.type": ɵ33$1,
    version: ɵ34$1,
    "wireless.options.authorizedProtocols": ɵ35$1,
    "wireless.options.inactivityTimeout": ɵ36$1,
    "wireless.protocols.lora.config": ɵ37$1,
    "wireless.protocols.lora.ids": ɵ38$1,
    "wireless.protocols.mqtt.brokerHostname": ɵ39$1,
    "wireless.protocols.mqtt.brokerPort": ɵ40$1,
    "wireless.protocols.mqtt.clientId": ɵ41$1,
    "wireless.protocols.mqtt.password": ɵ42$1,
    "wireless.protocols.mqtt.relayNetKey": ɵ43$1,
    "wireless.protocols.mqtt.username": ɵ44$1,
    "wireless.protocols.nfc.autoLogProfileId": ɵ45$1,
    "wireless.protocols.nfc.connectionPriority": ɵ46$1,
    "wireless.protocols.nfc.pairingMode": ɵ47$1,
    "wireless.protocols.wifi.countryCode": ɵ48$1,
    "wireless.protocols.wifi.gatewayIp": ɵ49$1,
    "wireless.protocols.wifi.ip": ɵ50$1,
    "wireless.protocols.wifi.key": ɵ51$1,
    "wireless.protocols.wifi.keyVisibility": ɵ52$1,
    "wireless.protocols.wifi.mask": ɵ53$1,
    "wireless.protocols.wifi.mode": ɵ54$1,
    "wireless.protocols.wifi.protocol": ɵ55$1,
    "wireless.protocols.wifi.ssid": ɵ56$1,
    "wireless.protocols.wifi.ssidVisibility": ɵ57$1,
    "wireless.protocols.wifi.txPower": ɵ58$1
};

var __awaiter$1 = (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());
    });
};
function stepEvent$1(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
 *
 */
class TapConfiguratorReader {
    constructor(calls = READ_CONFIGURATOR_CONFIG) {
        this.calls = calls;
    }
    createReadOperations(tap) {
        const configureContext = {
            tap
        };
        const operations = [];
        // const calls = READ_CONFIGURATOR_CONFIG;
        const outputConfig = {};
        this.addConfigurCalls(configureContext, this.calls, operations, outputConfig, tap);
        return StepOperations.sequential(operations);
    }
    addConfigurCalls(configureContext, calls, operations, outputConfig, tap) {
        let index = 0;
        for (const key in calls) {
            const context = {
                firmwareVersion: '9999.9999',
                service: tap.service,
                param: undefined // TODO 
            };
            const configKey = key;
            const factoryFct = calls[configKey];
            if (!factoryFct) {
                index++;
                continue;
            }
            const callOrError = factoryFct(context);
            operations.push((observer, context) => __awaiter$1(this, void 0, void 0, function* () {
                if (callOrError instanceof Error) {
                    stepEvent$1(observer, TapConfiguratorReader.Step.readKeyError, context, {
                        configKey,
                        error: callOrError,
                    });
                }
                else {
                    try {
                        outputConfig[configKey] = (yield configureContext.tap.lwm2m.execute(callOrError)).body();
                        stepEvent$1(observer, TapConfiguratorReader.Step.readKeySuccess, context, {
                            configKey,
                            value: outputConfig[configKey],
                            call: callOrError
                        });
                    }
                    catch (error) {
                        stepEvent$1(observer, TapConfiguratorReader.Step.readKeyError, context, {
                            configKey,
                            call: callOrError,
                            error
                        });
                    }
                }
            }));
            index++;
        }
        operations.push((observer, context) => __awaiter$1(this, void 0, void 0, function* () {
            stepEvent$1(observer, TapConfiguratorReader.Step.done, context, {
                config: outputConfig
            });
        }));
    }
    sleep(delayMs) {
        return sleep(delayMs);
    }
}
(function (TapConfiguratorReader) {
    let Step;
    (function (Step) {
        Step["readKeySuccess"] = "TapConfiguratorReaderreadKeySuccess";
        Step["readKeyError"] = "TapConfiguratorReaderReadKeyError";
        Step["done"] = "TapConfiguratorReaderDone";
    })(Step = TapConfiguratorReader.Step || (TapConfiguratorReader.Step = {}));
})(TapConfiguratorReader || (TapConfiguratorReader = {}));

/**
 * Utility class to build a configuration
 */
class TapConfiguratorConfigBuilder {
    constructor(_schema) {
        this._schema = _schema;
    }
    get configData() {
        if (!this._schema.config.data) {
            this._schema.config.data = {};
        }
        return this._schema.config.data;
    }
    get profiles() {
        if (!this.configData.profiles) {
            this.configData.profiles = [];
        }
        return this.configData.profiles;
    }
    get tapConfig() {
        if (!this._schema.config.tap) {
            this._schema.config.tap = {};
        }
        return this._schema.config.tap;
    }
    /**
     * @deprecated
     * TODO move from here as factory method should not polute the class
     */
    static default() {
        return new TapConfiguratorConfigBuilder({
            meta: {},
            config: {
                application: {
                    name: "TAP"
                },
                version: "1.0.0",
                tap: {
                    security: {
                        disableHardwareFactoryReset: false,
                        hashPassword: true,
                        disableLoginWithUID: false,
                        disableResourceFactoryReset: false,
                        scramActivated: false
                    },
                    scram: {
                        hashIteration: 5000
                    }
                },
                data: {
                    profiles: SPECIAL_USERS
                }
            }
        });
    }
    /**
     * Set application name
     * @param appName
     */
    appName(appName) {
        if (!this._schema.config.application) {
            this._schema.config.application = {};
        }
        this._schema.config.application.name = appName;
        return this;
    }
    /**
     * Edit user identified by username
     * If user does not it will be created with default values
     * @param username
     * @param editor
     */
    user(username, editor) {
        const userDataIndex = this.profiles.findIndex(p => p.username === username);
        let userData = userDataIndex >= 0 ? this.profiles[userDataIndex] : undefined;
        if (!userData) {
            // TODO check SpecialProfileConfig
            userData = {
                username,
                lifeTime: 300,
                password: username,
            };
        }
        userData = editor(userData);
        this.profiles[userDataIndex] = userData;
        return this;
    }
    /**
     * Enable/disable scram
     * @param enabled true to enable scram
     */
    scram(enabled) {
        // TODO hash iteration count ? 
        if (!this.tapConfig.security) {
            this.tapConfig.security = {
                scramActivated: false,
                disableHardwareFactoryReset: false,
                hashPassword: true,
                disableResourceFactoryReset: false,
                disableLoginWithUID: false
            };
        }
        else {
            this.tapConfig.security.scramActivated = enabled;
            if (enabled) {
                this.tapConfig.security.hashPassword = true;
            }
        }
        return this;
    }
    build() {
        return this._schema;
    }
}

/**
 * Generated bundle index. Do not edit.
 */

export { ADMIN_USER, ANONYMOUS_USER, READ_CONFIGURATOR_CONFIG, SPECIAL_USERS, SUPERVISOR_USER, TapConfiguratorConfigBuilder, TapConfiguratorError, TapConfiguratorReader, TapConfiguratorWriter, WRITE_CONFIGURATOR_CONFIG, isSpecialProfileUsername as isSpecialUser, parseTapConfiguratorConfig, tapConfigToServiceCalls, validateTapConfiguratorConfig };
//# sourceMappingURL=iotize-tap-configurator.js.map
