import { __awaiter } from 'tslib';
import * as i1$2 from '@angular/forms';
import { Validators, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { bufferToHexString, hexStringToBuffer } from '@iotize/common/byte-converter';
import * as i1 from '@iotize/ionic';
import { TapInfo, FACTORY_RESET_MODE_VERSION, TAP_MANAGER_APP_ID, createCacheKey, toTapInfoKeyObject, LibError, isTapResultCodeError, PendingCallManager, LibCommonModule, CONFIGURATION_MODE_VERSION } from '@iotize/ionic';
import { HostProtocol, TargetProtocol, TapResponse, SpecialFeature, TapError, TapResponseStatusError, PathParameter } from '@iotize/tap';
import { converters } from '@iotize/tap/service/core';
import { NfcConnectionPriority, NfcPairingMode } from '@iotize/tap/service/impl/interface';
import { WifiSSIDVisibility, WifiKeyVisibility, WifiMode } from '@iotize/tap/service/impl/wifi';
import { combineLatest, of, BehaviorSubject, Subject, defer, concat } from 'rxjs';
import { map, switchMap, distinctUntilChanged, shareReplay, tap, filter, first } from 'rxjs/operators';
import * as i0 from '@angular/core';
import { Injectable, Pipe, EventEmitter, Component, Output, Input, NgModule } from '@angular/core';
import { deepEqual, deepCopy, listEnumValues } from '@iotize/common/utility';
import { ResultCode, TapRequestFrame } from '@iotize/tap/client/api';
import { createDebugger } from '@iotize/common/debug';
import * as i3 from '@ionic/angular';
import * as i5 from '@angular/common';
import * as i6 from '@iotize/app-common';
import { FormErrorItemModule } from '@iotize/app-common';
import { isCodeError } from '@iotize/common/error';
import { tapResponseStatusToString } from '@iotize/tap/client/impl';
import * as i1$1 from '@ngx-translate/core';
import { TranslateModule } from '@ngx-translate/core';
import { TapResourceMetaData } from '@iotize/tap/service/all';
import { DotAccessor } from '@iotize/common/data-accessor';
import { xmlToJson } from '@iotize/common/xml';
import { IoTizeStudioToTapConfigConverter } from '@iotize/tap/config/iotize-studio';
import { ADMIN_USER } from '@iotize/tap/configurator';
import { ConnectionState } from '@iotize/tap/protocol/api';

function enumToOptions(mapping) {
    const keys = Object.keys(mapping).filter((k) => typeof mapping[k] === 'number');
    return keys.map((key) => {
        return { key: mapping[key], text: key };
    });
}
function tapResourceTranslateKey(path, subKey) {
    return `tap.lwm2m.paths.${path}.${subKey}`;
}

const TAP_CONFIG_PATTERN = /^([0-9]+)\.([0-9]+)\.([0-9]+)$/;
const IPV4_PATTERN = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
const IPV4_MASK_PATTERN = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
const SSID_PATTERN = /^[^ !#;+\]\/"\t][^+\]\/"\t]{0,30}[^ !#;+\]\/"\t]$|^[^ !#;+\]\/"\t]$/;
function regexValidator(pattern, message) {
    return (control) => {
        const value = control.value;
        const valueMatchPattern = pattern.test(value);
        return !valueMatchPattern
            ? { invalidFormat: { value: control.value, message } }
            : null;
    };
}
const validateTapVersion = regexValidator(TAP_CONFIG_PATTERN, `Must be a valid semantic version (Major.Minor.Patch).`);
function enumFormatter(data) {
    return (value) => {
        if (Array.isArray(value)) {
            if (value.length === 0) {
                return '-';
            }
            return value.map((key) => HostProtocol[key]).join(', ');
        }
        else {
            return data[value];
        }
    };
}
function isTapConfigured(version) {
    return !(version.major === 0 && version.minor === 0 && version.patch === 0);
}
function stringToEnumArray(v, mapping) {
    return v
        .split(',')
        .map((item) => item.trim())
        .map((item) => {
        if (!(item in mapping)) {
            throw new Error(`Invalid value "${item}". Must one of the following: ${Object.keys(mapping).join(', ')}`);
        }
        return mapping[item];
    });
}
var WifiTxPowerEnum;
(function (WifiTxPowerEnum) {
    WifiTxPowerEnum[WifiTxPowerEnum["default"] = 0] = "default";
    WifiTxPowerEnum[WifiTxPowerEnum["10 dBm"] = 40] = "10 dBm";
    WifiTxPowerEnum[WifiTxPowerEnum["12.5 dBm"] = 50] = "12.5 dBm";
    WifiTxPowerEnum[WifiTxPowerEnum["15 dBm"] = 60] = "15 dBm";
    WifiTxPowerEnum[WifiTxPowerEnum["17.5 dBm"] = 70] = "17.5 dBm";
    WifiTxPowerEnum[WifiTxPowerEnum["20 dBm"] = 80] = "20 dBm";
})(WifiTxPowerEnum || (WifiTxPowerEnum = {}));
const IPV4_VALIDATOR = regexValidator(IPV4_PATTERN, `Not a valid IPv4 address (eg 192.168.20.1)`);
const defaultInfoResolverConfig = [
    {
        key: TapInfo.HostProtocol,
        input: createEnumField('HostProtocol', HostProtocol),
        viewFormatter: enumFormatter(HostProtocol),
    },
    {
        key: TapInfo.configVersion,
        input: {
            formValidators: [validateTapVersion],
        },
        viewFormatter: (v) => {
            if (v === FACTORY_RESET_MODE_VERSION) {
                return 'FACTORY RESET';
            }
            else if (v === '255.255.65535') {
                return 'CONFIGURATION MODE';
            }
            else if (v) {
                return `v${v}`;
            }
            else {
                return 'UNKNOWN';
            }
        },
        editFormatter: {
            read: (input) => {
                return input;
            },
            write: (v) => {
                return v || FACTORY_RESET_MODE_VERSION;
            },
        },
    },
    {
        key: TapInfo.CloudEndpoint,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const hostname = (yield tap.service.mqtt.getBrokerHostname()).body();
            const port = (yield tap.service.mqtt.getBrokerPort()).body();
            return `${hostname}:${port}`;
        }),
        putValue: (tap, value) => __awaiter(void 0, void 0, void 0, function* () {
            const [hostname, port] = value.split(':');
            const setPort = yield tap.service.mqtt.putBrokerPort(port || '1883');
            setPort.successful();
            return tap.service.mqtt.putBrokerHostname(hostname);
        }),
    },
    {
        key: TapInfo.TargetProtocolConfiguration,
        viewFormatter: (v) => `${bufferToHexString(v)}`,
        editFormatter: {
            read: (input) => {
                return input ? hexStringToBuffer(input) : new Uint8Array();
            },
            write: (v) => {
                return v ? bufferToHexString(v) : '';
            },
        },
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const result = yield tap.service.target.getModbusTcpConfiguration();
            result.successful();
            return result.rawBody();
        }),
        putValue: (tap, value) => __awaiter(void 0, void 0, void 0, function* () {
            return yield tap.lwm2m.put('/1027//21', value);
        }),
    },
    {
        input: {
            type: 'toggle',
        },
        key: TapInfo.NFCConnectionPriority,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const value = (yield tap.service.interface.getNfcConnectionPriority()).body();
            return value === NfcConnectionPriority.NFC_PRIORITY;
        }),
        putValue: (tap, val) => {
            const mode = val
                ? NfcConnectionPriority.NFC_NON_PRIORITY
                : NfcConnectionPriority.NFC_PRIORITY;
            return tap.service.interface.putNfcConnectionPriority(mode);
        },
    },
    {
        key: TapInfo.NFCPairingMode,
        input: createEnumField('NfcPairingMode', NfcPairingMode),
    },
    {
        key: TapInfo.DataLogMaxPacketCount,
        viewFormatter: (v) => {
            return v === 0 ? 'NO LIMIT' : v.toString();
        },
        input: {
            type: 'number',
        },
    },
    {
        key: TapInfo.IsTargetConnected,
        // viewFormatter: (v: boolean) => v ? 'YES' : 'NO',
        getValue: (tap) => tap.service.target.isConnected(),
        putValue: (tap, enabled) => {
            if (enabled) {
                return tap.service.target.connect();
            }
            else {
                return tap.service.target.disconnect();
            }
        },
        input: {
            type: 'toggle',
        },
    },
    {
        key: TapInfo.universalLink,
        icon: 'link',
    },
    {
        key: TapInfo.androidApplicationRecord,
        // TODO replace with getAndroidApplicationId()
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const appPath = (yield tap.service.interface.getAppPath()).body();
            if (appPath.startsWith('$4/')) {
                return appPath.substring(3);
            }
            else {
                return TAP_MANAGER_APP_ID;
            }
        }),
        viewFormatter: (input) => {
            if (input === TAP_MANAGER_APP_ID) {
                return `${input} (Tap Manager)`;
            }
            return input;
        },
        putValue: (tap, value) => __awaiter(void 0, void 0, void 0, function* () {
            return tap.service.interface.putAppPath(`$4/${value}`);
        }),
    },
    {
        key: TapInfo.useEncryption,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return lockOptions.scramActivated;
        }),
    },
    {
        key: TapInfo.lockFactoryReset,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return !lockOptions.disableHardwareFactoryReset;
        }),
    },
    {
        key: TapInfo.InterfaceSecurityScramActivated,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return lockOptions.scramActivated;
        }),
    },
    {
        key: TapInfo.InterfaceSecurityDisableHardwareFactoryReset,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return lockOptions.disableHardwareFactoryReset;
        }),
    },
    {
        key: TapInfo.InterfaceSecurityDisabledResourceFactoryReset,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return lockOptions.disableResourceFactoryReset;
        }),
    },
    {
        key: TapInfo.InterfaceSecurityDisabledLoginWithUID,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return lockOptions.disableLoginWithUID;
        }),
    },
    {
        key: TapInfo.hashPassword,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return lockOptions.hashPassword;
        }),
    },
    {
        key: TapInfo.isLoginWithUIDEnabled,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return !lockOptions.disableLoginWithUID;
        }),
    },
    {
        key: TapInfo.isLWM2MFactoryResetEnabled,
        input: {
            type: 'toggle',
        },
        editable: false,
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const lockOptions = (yield tap.service.interface.getSecurityOptions()).body();
            return !lockOptions.disableResourceFactoryReset;
        }),
    },
    {
        key: TapInfo.appPath,
        putValue: (tap, value) => {
            return tap.service.interface.putAppPath(value);
        },
        getValue: (tap) => tap.service.interface.getAppPathResolved(),
    },
    {
        key: TapInfo.TargetProtocol,
        getValue: (tap) => {
            return tap.service.target.getProtocol();
        },
        putValue: (tap, protocol) => {
            return tap.service.target.putProtocol(protocol);
        },
        setValue: (tap, protocol) => {
            return tap.service.target.setProtocol(protocol);
        },
        viewFormatter: enumFormatter(TargetProtocol),
        input: {
            type: 'select',
            options: enumToOptions(TargetProtocol).filter((f) => {
                return f.key !== TargetProtocol.JTAG;
            }),
        },
    },
    {
        key: '/interface/available-host-protocols',
        viewFormatter: enumFormatter(HostProtocol),
        editFormatter: {
            write: (v) => {
                // console.log('Host protocols: ', v);
                if (!v || v.length === 0) {
                    return 'NONE';
                }
                return v.map((key) => HostProtocol[key]).join(', ');
            },
            read: (v) => {
                return stringToEnumArray(v, HostProtocol);
            },
        },
    },
    {
        key: TapInfo.authorizedHostProtocols,
        input: {
            type: 'select',
            multiple: true,
            options: [],
        },
        viewFormatter: enumFormatter(HostProtocol),
        init: (_service, config, infoResolver) => __awaiter(void 0, void 0, void 0, function* () {
            const hostProtocols = yield infoResolver.getValue(TapInfo.availableHostProtocols);
            if (config.input !== undefined) {
                config.input.options = hostProtocols.map((key) => {
                    return { key: key, text: HostProtocol[key] };
                });
            }
        }),
    },
    {
        key: TapInfo.AdpVersion,
        getValue: (tap) => tap.service.tapnpass.getStatus(),
        viewFormatter: (stats) => {
            const v = stats.header.version;
            return `${v.major}.${v.minor}.${v.patch}`;
        },
    },
    {
        key: TapInfo.WifiHostname,
        viewFormatter: (v) => {
            if (v === '0.0.0.0') {
                return 'NO IP';
            }
            return v;
        },
    },
    {
        key: TapInfo.WifiSSID,
        input: {
            formValidators: [
                regexValidator(SSID_PATTERN, `This is not a valid SSID. It can be any alphanumeric, case-sensitive entry from 1 to 32 characters. Trailing or leading spaces are not allowed.`),
            ],
        },
    },
    {
        key: TapInfo.WifiSSIDVisibility,
        input: createEnumField('WifiSSIDVisibility', WifiSSIDVisibility),
        viewFormatter: enumFormatter(WifiSSIDVisibility),
    },
    {
        key: TapInfo.WifiKeyVisibility,
        input: createEnumField('WifiKeyVisibility', WifiKeyVisibility),
        viewFormatter: enumFormatter(WifiKeyVisibility),
    },
    {
        key: TapInfo.WifiTxPower,
        viewFormatter: enumFormatter(WifiTxPowerEnum),
        input: createEnumField('WifiTxPowerEnum', WifiTxPowerEnum),
    },
    {
        key: TapInfo.NetworkInfraIp,
        input: {
            formValidators: [IPV4_VALIDATOR],
        },
        viewFormatter: (value) => {
            if (value === '0.0.0.0') {
                return 'Dynamic (DHCP)';
            }
            return value;
        },
    },
    {
        key: TapInfo.NetworkIpMask,
        input: {
            formValidators: [
                regexValidator(IPV4_MASK_PATTERN, `Not a valid IPv4 mask (eg 192.168.20.1)`),
            ],
        },
        isDisplayed: ({ tapConfigItemStateService }) => {
            return combineLatest([
                tapConfigItemStateService.valueChange(TapInfo.WifiMode),
                tapConfigItemStateService.valueChange(TapInfo.NetworkInfraIp),
            ]).pipe(map(([mode, ip]) => {
                return mode === WifiMode.NETWORK && ip !== '0.0.0.0';
            }));
        },
    },
    {
        key: TapInfo.NetworkGatewayIp,
        input: {
            formValidators: [IPV4_VALIDATOR],
        },
        isDisplayed: ({ tapConfigItemStateService }) => {
            return combineLatest([
                tapConfigItemStateService.valueChange(TapInfo.WifiMode),
                tapConfigItemStateService.valueChange(TapInfo.NetworkInfraIp),
            ]).pipe(map(([mode, ip]) => {
                return mode === WifiMode.NETWORK && ip !== '0.0.0.0';
            }));
        },
    },
    {
        key: TapInfo.NetworkDNSIp,
        input: {
            formValidators: [IPV4_VALIDATOR],
        },
        isDisplayed: ({ tapConfigItemStateService }) => {
            return combineLatest([
                tapConfigItemStateService.valueChange(TapInfo.WifiMode),
                tapConfigItemStateService.valueChange(TapInfo.NetworkInfraIp),
            ]).pipe(map(([mode, ip]) => {
                return mode === WifiMode.NETWORK && ip !== '0.0.0.0';
            }));
        },
    },
    {
        key: TapInfo.WifiMode,
        input: createEnumField('WifiMode', WifiMode),
    },
    {
        key: TapInfo.isHostProtocolAuthorized,
        input: {
            type: 'toggle',
        },
        getValue: (tap, protocol) => __awaiter(void 0, void 0, void 0, function* () {
            if (protocol === undefined) {
                throw new Error('Illegal argument error: missing protocol');
            }
            const protocols = (yield tap.service.interface.getAuthorizedHostProtocol()).body();
            return protocols.find((p) => p === protocol) !== undefined;
        }),
        putValue: (tap, value, protocol) => __awaiter(void 0, void 0, void 0, function* () {
            const protocols = (yield tap.service.interface.getAuthorizedHostProtocol()).body();
            if (protocol === undefined) {
                throw new Error('Illegal argument error: missing protocol');
            }
            const indexOfProtocol = protocols.findIndex((p) => p === protocol);
            if (value) {
                if (indexOfProtocol === -1) {
                    protocols.push(protocol);
                }
            }
            else {
                if (indexOfProtocol >= 0) {
                    protocols.splice(indexOfProtocol, 1);
                }
            }
            return tap.service.interface.putAuthorizedHostProtocol(protocols);
        }),
    },
    {
        key: TapInfo.WifiKey,
        input: {
            type: 'password',
            formValidators: [Validators.minLength(8), Validators.maxLength(128)],
        },
    },
    {
        key: TapInfo.variableMetaData,
        input: {},
        getValue: (tap, variableId) => __awaiter(void 0, void 0, void 0, function* () {
            const metaData = (yield tap.service.variable.getRawMeta(variableId)).body();
            return converters.ascii.decode(metaData);
        }),
        putValue: (tap, value, bundleId) => {
            const data = converters.ascii.encode(value);
            return tap.service.variable.putRawMeta(bundleId, data);
        },
    },
    {
        key: TapInfo.profilePassword,
        input: {
            type: 'password',
            formValidators: [Validators.minLength(1), Validators.maxLength(16)],
        },
        viewFormatter: () => {
            return '********';
        },
        putValue: (tap, value, profileId) => __awaiter(void 0, void 0, void 0, function* () {
            yield tap.auth.changePassword(value, profileId);
            return TapResponse.SUCCESS();
        }),
    },
    {
        key: TapInfo.DeviceMemoryFree,
        viewFormatter(value) {
            return Math.floor((value / 1024) * 100) / 100 + ' KB';
        },
    },
    {
        key: TapInfo.TimeLocalTime,
        viewFormatter(localTime) {
            if (!localTime) {
                return '';
            }
            const date = new Date(Date.UTC(localTime.year, 0, localTime.dayOfYear));
            date.setHours(localTime.hours);
            date.setMinutes(localTime.minutes);
            date.setSeconds(localTime.seconds);
            // {"seconds":54,"minutes":3,"hours":8,"dayOfMonth":8,"month":8,"year":122,"dayOfWeek":4,"dayOfYear":250,"isdst":0}
            return `${date.toUTCString()}`;
        },
    },
    Object.assign({ key: TapInfo.InterfaceSpecialFeatureSWDDirect }, createSpecialFeatureDAO(SpecialFeature.SWD_DIRECT_ACCESS)),
    Object.assign({ key: TapInfo.InterfaceSpecialFeatureSerial }, createSpecialFeatureDAO(SpecialFeature.SERIAL_ACCESS)),
    Object.assign({ key: TapInfo.InterfaceSpecialFeatureModbusDirect }, createSpecialFeatureDAO(SpecialFeature.MODBUS_DIRECT_ACCESS)),
    {
        key: '/wifi/enabled',
        input: {
            type: 'toggle',
        },
        getValue: (tap) => __awaiter(void 0, void 0, void 0, function* () {
            const response = yield tap.service.wifi.getDisabled();
            return !response.body();
        }),
        putValue: (tap, enabled) => {
            return tap.service.wifi.putDisabled(!enabled);
        },
    },
];
function createSpecialFeatureDAO(feature) {
    return {
        input: {
            type: 'number',
            formValidators: [Validators.min(0), Validators.max(65535)],
        },
        getValue: (tap) => __awaiter(this, void 0, void 0, function* () {
            const result = (yield tap.service.interface.getSpecialFeatureProfile(feature)).body();
            if (result === 65535 - (feature - 100)) {
                return 'UNAUTHORIZED';
            }
            else {
                return result;
            }
        }),
        putValue: (tap, body) => __awaiter(this, void 0, void 0, function* () {
            return yield tap.service.interface.putSpecialFeatureProfile(feature, body);
        }),
    };
}
function createEnumField(enumId, enumData) {
    return {
        type: 'select',
        enum: {
            id: enumId,
            data: enumData,
        },
    };
}

class TapConfigItemStateService {
    /**
     * Value change taking into acccount the edited value.
     * If no editaded value for the key, it will take the lasted fetched value from the Tap
     * @param key
     * @returns
     */
    valueChange(key) {
        return this._pendingChanges.pipe(switchMap((changes) => {
            const hashKey = createCacheKey(toTapInfoKeyObject(key));
            const editedValue = changes.find((entry) => createCacheKey(entry.key) === hashKey);
            if (editedValue !== undefined) {
                return of(editedValue.value);
            }
            else {
                return this.tapInfoCacheService.valueChange(key);
            }
        }), distinctUntilChanged(deepEqual), shareReplay(1));
    }
    getPendingChangeForKey(key) {
        return this._pendingChanges.pipe(map((changes) => {
            var _a;
            const hashKey = createCacheKey(toTapInfoKeyObject(key));
            return (_a = changes.find((entry) => createCacheKey(entry.key) === hashKey)) === null || _a === void 0 ? void 0 : _a.value;
        }), distinctUntilChanged(deepEqual), shareReplay(1));
    }
    get pendingChangesChange() {
        return this._pendingChanges.asObservable();
    }
    get saveProgress() {
        return this._saveProgress.asObservable();
    }
    constructor(tapInfoDAOService, tapInfoCacheService, tapInfoConfigService) {
        this.tapInfoDAOService = tapInfoDAOService;
        this.tapInfoCacheService = tapInfoCacheService;
        this.tapInfoConfigService = tapInfoConfigService;
        this._pendingChanges = new BehaviorSubject([]);
        this.loading = false;
        this.hasPendingChanges = this._pendingChanges.pipe(map((changes) => changes.length > 0));
        this.validationErrorsChange = this._pendingChanges.pipe(map((changes) => {
            return changes.reduce((acc, change) => {
                var _a, _b;
                const tapConfigItem = this.tapInfoConfigService.findByKey(change.key);
                if (!tapConfigItem) {
                    console.warn(`Failed to find Tap Config Item Key "${change.key}"`);
                    return acc;
                }
                (_b = (_a = tapConfigItem.input) === null || _a === void 0 ? void 0 : _a.formValidators) === null || _b === void 0 ? void 0 : _b.forEach((validator) => {
                    const error = validator(new FormControl(change.value));
                    if (error) {
                        acc.set(change.key, {
                            value: change.value,
                            errors: error,
                        });
                    }
                });
                return acc;
            }, new Map());
        }));
        this.validationErrorsCountChange = this.validationErrorsChange.pipe(map((changeErrors) => {
            return Array.from(changeErrors.keys()).length;
        }), shareReplay({ bufferSize: 1, refCount: true }));
        this.hasValidationErrors = this.validationErrorsCountChange.pipe(map((count) => {
            return count > 0;
        }));
        this._saveProgress = new Subject();
    }
    savePendingChanges() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                this.loading = true;
                yield this._savePendingChangesWithProgress().toPromise();
            }
            finally {
                this.loading = false;
            }
        });
    }
    _savePendingChangesWithProgress() {
        const configItemStateChanges = this.getPendingChangesSnapshot().filter(({ key }) => {
            return key.key !== TapInfo.configVersion;
        });
        const observables = configItemStateChanges.map(({ key, value }) => {
            return defer(() => __awaiter(this, void 0, void 0, function* () {
                yield this.tapInfoDAOService.put(key, value);
                this.tapInfoDAOService.get(key).catch((err) => { });
            }));
        });
        const total = configItemStateChanges.length;
        const saveProgress = concat(...observables).pipe(map((info, index) => {
            return {
                total,
                loaded: index + 1,
                payload: info,
            };
        }), tap(this._saveProgress));
        return saveProgress;
    }
    clearPendingChanges() {
        this._pendingChanges.next([]);
    }
    getPendingChangesSnapshot() {
        return deepCopy(this._pendingChanges.value);
    }
    clearPendingChange(tapInfoKey) {
        const hashKey = createCacheKey(tapInfoKey);
        const pendingChangesSnapshot = this._pendingChanges.value;
        const pendingChangeIndex = pendingChangesSnapshot.findIndex((entry) => createCacheKey(entry.key) === hashKey);
        if (pendingChangeIndex >= 0) {
            pendingChangesSnapshot.splice(pendingChangeIndex, 1);
            this._pendingChanges.next(pendingChangesSnapshot);
        }
    }
    setPendingChange(info, newValue) {
        // Make sure we don't store any other info otherwise deepCopy may failed
        info = {
            key: info.key,
            params: info.params,
        };
        const hashKey = createCacheKey(info);
        const pendingChangesSnapshot = this._pendingChanges.value;
        const item = pendingChangesSnapshot.find((entry) => createCacheKey(entry.key) === hashKey);
        if (!item) {
            pendingChangesSnapshot.push({
                key: info,
                value: newValue,
            });
            this._pendingChanges.next(pendingChangesSnapshot);
        }
        else {
            if (!deepEqual(item.value, newValue)) {
                item.value = newValue;
                this._pendingChanges.next(pendingChangesSnapshot);
            }
        }
    }
    removePendingChange(info) {
        const hashKey = createCacheKey(info);
        const pendingChangesSnapshot = this._pendingChanges.value;
        const indexOfItem = pendingChangesSnapshot.findIndex((entry) => createCacheKey(entry.key) === hashKey);
        if (indexOfItem >= 0) {
            pendingChangesSnapshot.splice(indexOfItem, 1);
            this._pendingChanges.next(pendingChangesSnapshot);
        }
    }
}
/** @nocollapse */ TapConfigItemStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemStateService, deps: [{ token: i1.TapInfoDAOService }, { token: i1.TapInfoCacheService }, { token: i1.TapInfoConfigService }], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ TapConfigItemStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemStateService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemStateService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }], ctorParameters: function () { return [{ type: i1.TapInfoDAOService }, { type: i1.TapInfoCacheService }, { type: i1.TapInfoConfigService }]; } });

const debug = createDebugger('@iotize/ionic:config');

class TapRequestErrorToStringPipe {
    transform(value, action = 'read') {
        if (!value) {
            return undefined;
        }
        return userFriendlyError(value, action).message;
    }
}
/** @nocollapse */ TapRequestErrorToStringPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapRequestErrorToStringPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
/** @nocollapse */ TapRequestErrorToStringPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: TapRequestErrorToStringPipe, name: "tapRequestErrorToString" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapRequestErrorToStringPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'tapRequestErrorToString',
                }]
        }] });
function userFriendlyError(error, action) {
    if (isCodeError(TapError.Code.ExecuteRequestError, error)) {
        error = error.cause || error;
    }
    if (isCodeError(TapResponseStatusError.Code.ResponseStatusError, error)) {
        const tapResponseStatusError = error;
        const statusCode = tapResponseStatusError.response.status;
        let message;
        switch (statusCode) {
            case ResultCode.UNAUTHORIZED:
                message = `You are not authorized to ${action} this value. Try to login first.`;
                break;
            case ResultCode.RESOURCE_LOCKED:
                message = `This value is ${action} protected`;
                break;
            case ResultCode.NOT_IMPLEMENTED:
                message = `This configuration is not available with your current firmware version or Tap model`;
                break;
            default:
                message = tapResponseStatusToString(statusCode);
        }
        error = new Error(message);
    }
    return error;
}

class TapResourceEnumTranslatePipe {
    transform(enumKey, part = 'title', meta) {
        if (meta) {
            let enumKeyString = typeof enumKey === 'number' ? meta.data[enumKey] : enumKey;
            const translationKey = `tap.lwm2m.enums.${meta.id}.${enumKeyString}.${part}`;
            return this.translate.stream(translationKey).pipe(map((v) => {
                return v === translationKey ? enumKeyString : v;
            }));
        }
        else {
            return of(enumKey.toString());
        }
    }
    constructor(translate) {
        this.translate = translate;
    }
}
/** @nocollapse */ TapResourceEnumTranslatePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapResourceEnumTranslatePipe, deps: [{ token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe });
/** @nocollapse */ TapResourceEnumTranslatePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: TapResourceEnumTranslatePipe, name: "tapResourceEnumTranslate" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapResourceEnumTranslatePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'tapResourceEnumTranslate',
                }]
        }], ctorParameters: function () { return [{ type: i1$1.TranslateService }]; } });

class ListEnumValuesPipe {
    transform(enumData) {
        if (!enumData) {
            return [];
        }
        return listEnumValues(enumData);
    }
}
/** @nocollapse */ ListEnumValuesPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ListEnumValuesPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
/** @nocollapse */ ListEnumValuesPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: ListEnumValuesPipe, name: "listEnumValues" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ListEnumValuesPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'listEnumValues',
                }]
        }] });

class TapConfigItemComponent {
    set info(configOrKey) {
        this._resetErrors();
        let config;
        if (typeof configOrKey === 'object') {
            const defaultConfig = this.tapInfoConfigService.findByKey(configOrKey);
            if (defaultConfig) {
                config = Object.assign(Object.assign({}, defaultConfig), configOrKey);
            }
            else {
                config = configOrKey;
            }
        }
        else {
            config = this.tapInfoConfigService.findByKey({
                key: configOrKey,
            });
            if (!config) {
                console.warn(`Failed to find configuration with key "${configOrKey}"`);
                return;
            }
        }
        this.onConfigChange(config);
        this.updateDisplayValue();
        // this.fetchValueIfRequired();
    }
    get info() {
        return this.config;
    }
    get originalValue() {
        var _a;
        return (_a = this.config.resolvedValue) === null || _a === void 0 ? void 0 : _a.value;
    }
    isEdited() {
        return this.field.value !== this.originalValue;
    }
    get config() {
        if (!this._config) {
            throw LibError.componentArgumentRequired('TapConfigItemComponent', 'info');
        }
        return this._config;
    }
    get inputOptions() {
        return this.info.input || {};
    }
    get isEditable() {
        var _a;
        return (((_a = this._config) === null || _a === void 0 ? void 0 : _a.editable) &&
            this.editable &&
            (!this.readError ||
                !isTapResultCodeError(this.readError, ResultCode.NOT_IMPLEMENTED)));
    }
    constructor(formBuilder, tapService, toastController, infoResolver, tapInfoDAOService, tapInfoCacheService, tapConfigItemState, tapInfoConfigService) {
        this.tapService = tapService;
        this.toastController = toastController;
        this.infoResolver = infoResolver;
        this.tapInfoDAOService = tapInfoDAOService;
        this.tapInfoCacheService = tapInfoCacheService;
        this.tapConfigItemState = tapConfigItemState;
        this.tapInfoConfigService = tapInfoConfigService;
        this.focusOut = new EventEmitter();
        this.onSubmit = new EventEmitter();
        this.refresh = false;
        this.editMode = false;
        this.globalSubmit = false;
        this.loading = false;
        this.placeholder = '';
        this.ressourceAvailable = true;
        const form = formBuilder.nonNullable.group({
            field: [''],
        });
        this.field = form.controls.field;
        this.pendingCallManager = PendingCallManager.create(this.tapService);
    }
    _resetErrors() {
        this.setReadError(undefined);
        this.writeError = undefined;
        this.ressourceAvailable = true;
    }
    get pendingEditCall() {
        return this.pendingCallManager.pendingCall;
    }
    onConfigChange(config) {
        var _a, _b, _c;
        (_a = this._valueSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
        (_b = this._cancelChangeSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
        this._config = config;
        this._cancelChangeSubscription = this.tapConfigItemState
            .getPendingChangeForKey(config)
            .subscribe((v) => {
            if (v === undefined) {
                this.setFieldValue(this.originalValue, {
                    emitEvent: false,
                });
            }
        });
        this.initializeConfig();
        if (config.input && config.input.type === 'password') {
            this.setDisplayValue('');
        }
        if ((_c = config.input) === null || _c === void 0 ? void 0 : _c.formValidators) {
            this.field.setValidators(config.input.formValidators);
        }
        this._valueSubscription = this.tapInfoCacheService
            .infoChange(config)
            .subscribe((newValue) => {
            config.resolvedValue = newValue;
            if (newValue.error !== undefined) {
                this.setReadError(newValue.error);
            }
            else {
                this.setReadError(undefined);
                if (newValue.value !== undefined) {
                    this.setDisplayValue(newValue.value);
                    this.setFieldValue(newValue.value);
                }
                else {
                    this.displayedValue = undefined;
                }
            }
        });
    }
    initializeConfig() {
        if (this.config.init) {
            this.config
                .init(this.tapService, this.config, this.infoResolver)
                .catch((err) => {
                this.setReadError(err);
            });
        }
    }
    setWriteError(error) {
        this.writeError = error;
    }
    setReadError(error) {
        this.readError = error;
        this.ressourceAvailable = error
            ? !isTapResultCodeError(error, ResultCode.NOT_IMPLEMENTED)
            : true;
    }
    ngOnInit() {
        this._formValueSubscription = this.field.valueChanges.subscribe((newValue) => {
            if (this.isEdited()) {
                this.tapConfigItemState.setPendingChange(this.info, newValue);
            }
            else {
                this.tapConfigItemState.removePendingChange(this.info);
            }
        });
    }
    ngOnDestroy() {
        var _a, _b, _c;
        (_a = this._valueSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
        (_b = this._formValueSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
        (_c = this._cancelChangeSubscription) === null || _c === void 0 ? void 0 : _c.unsubscribe();
        this.pendingCallManager.destroy();
    }
    submit($event) {
        if (!this.globalSubmit) {
            debug('submit', $event);
            this.field.updateValueAndValidity();
            if (!this.field.valid) {
                this.writeError = new Error('Invalid value');
                return;
            }
            // this.onSubmit.emit(event);
            const value = this.getFieldValue();
            // debug(`Creating call new value:`, value, `valid: ${this.field.valid}`)
            const call = () => __awaiter(this, void 0, void 0, function* () {
                yield this.tapInfoDAOService.put(this.info, value);
                if (this.info.getValue) {
                    this.tapInfoDAOService.get(this.info).catch((err) => { });
                }
                return value;
            });
            this.runCall(call);
        }
    }
    runCall(call) {
        this.loading = true;
        this.pendingCallManager
            .exec(call)
            .then((value) => __awaiter(this, void 0, void 0, function* () {
            yield this.showToast('Value saved!', 'success');
            this.config.resolvedValue = {
                loadDate: new Date(),
                value: value,
            };
            this.writeError = undefined;
            this.editMode = false;
            this.updateDisplayValue();
        }))
            .catch((err) => {
            this.setWriteError(err);
            this.field.setErrors({
                write: err.message,
            });
        })
            .finally(() => {
            this.loading = false;
        });
    }
    onValueClick($event) {
        $event.preventDefault();
        if (this.isEditable) {
            this.editMode = true;
        }
    }
    explainPendingCall() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.showToast('Please reconnect your Tap to save pending changes');
        });
    }
    onFocusOut() {
        this.focusOut.emit(this.field.value);
    }
    cancelEdit($event) {
        debug(this.config.key, 'cancel edit', $event);
        if (this.globalSubmit) {
            this.restaureValue();
        }
        else {
            this.writeError = undefined;
            if (this.pendingCallManager.hasPendingCall()) {
                this.pendingCallManager.cancel();
            }
            else {
                this.editMode = false;
                this.restaureValue();
            }
        }
    }
    getFieldValue() {
        let fieldValue = this.field.value;
        if (this.config.editFormatter) {
            fieldValue = this.config.editFormatter.read(fieldValue);
        }
        return fieldValue;
    }
    showToast(msg, color) {
        return __awaiter(this, void 0, void 0, function* () {
            const toast = yield this.toastController.create({
                message: msg,
                duration: 2000,
                position: 'bottom',
                color: color,
            });
            yield toast.present();
        });
    }
    refreshValue() {
        return this._execRefreshKey();
    }
    _execRefreshKey() {
        return this.infoResolver.refreshKey(this.config);
    }
    restaureValue() {
        this.setFieldValue(this.originalValue);
        this.tapConfigItemState.removePendingChange(this.config);
    }
    setFieldValue(value, options) {
        const formattedValue = this.config.editFormatter
            ? this.config.editFormatter.write(value)
            : value;
        debug(this.config.key, 'setFieldValue with', formattedValue);
        this.field.setValue(formattedValue, options);
    }
    updateDisplayValue() {
        if (this.config.resolvedValue) {
            if (this.config.resolvedValue.error) {
                this.displayedValue = this.config.resolvedValue.error.message;
            }
            else {
                const value = this.config.resolvedValue.value;
                this.setDisplayValue(value);
                this.setFieldValue(value);
            }
        }
        else {
            debug(this.config.key, 'Value is not loaded yet', this.config.resolvedValue);
            this.displayedValue = undefined;
        }
    }
    setDisplayValue(value) {
        var _a, _b;
        if (value instanceof Error) {
            return value.message;
        }
        else {
            let stringValue;
            if (this.config.viewFormatter) {
                stringValue = this.config.viewFormatter(value);
            }
            else if (typeof value === 'object') {
                stringValue = JSON.stringify(value);
            }
            else if (((_a = this.config.input) === null || _a === void 0 ? void 0 : _a.type) === 'select') {
                stringValue =
                    ((_b = this.getSelectedOption(value)) === null || _b === void 0 ? void 0 : _b.text) ||
                        (value !== undefined ? value.toString() : '');
            }
            else {
                stringValue = value !== undefined ? value.toString() : '';
            }
            // debug(`${this.config.key} setDisplayValue with`, stringValue);
            this.displayedValue = stringValue;
            return stringValue;
        }
    }
    getSelectedOption(value) {
        var _a, _b;
        return (_b = (_a = this.config.input) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.find((option) => option.key === value);
    }
    get selectedOption() {
        var _a;
        return this.getSelectedOption((_a = this.config.resolvedValue) === null || _a === void 0 ? void 0 : _a.value);
    }
    fetchValue() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.config.getValue) {
                this.infoResolver.refreshKey(this.config);
                const result = yield this.tapInfoCacheService
                    .infoChange(this.config)
                    .pipe(filter((v) => !!v.loadDate), first())
                    .toPromise();
            }
        });
    }
}
/** @nocollapse */ TapConfigItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemComponent, deps: [{ token: i1$2.FormBuilder }, { token: i1.CurrentDeviceService }, { token: i3.ToastController }, { token: i1.TapInfoRequestService }, { token: i1.TapInfoDAOService }, { token: i1.TapInfoCacheService }, { token: TapConfigItemStateService }, { token: i1.TapInfoConfigService }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TapConfigItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TapConfigItemComponent, selector: "tap-config-item", inputs: { editable: "editable", info: "info", refresh: "refresh", editMode: "editMode", globalSubmit: "globalSubmit" }, outputs: { focusOut: "focusOut", onSubmit: "onSubmit" }, ngImport: i0, template: "<ion-item *ngIf=\"_config\" [lines]=\"isEditable ? '' : 'none'\">\n  <ion-skeleton-text\n    animated\n    *ngIf=\"\n      displayedValue === undefined && readError === undefined;\n      else valueFetchedTemplate\n    \"\n  ></ion-skeleton-text>\n  <ng-template #valueFetchedTemplate>\n    <ng-container\n      *ngIf=\"ressourceAvailable; else ressourceNotAvailableTemplate\"\n    >\n      <ng-container *ngIf=\"!editMode || !isEditable; else editModeTemplate\">\n        <ion-text\n          color=\"warning\"\n          class=\"read-value-error\"\n          (click)=\"onValueClick($event)\"\n          [class]=\"isEditable ? 'cell' : ''\"\n          *ngIf=\"readError; else noReadErrorTemplate\"\n        >\n          <ion-icon name=\"alert-circle\"></ion-icon>\n          {{ readError | tapRequestErrorToString }}\n        </ion-text>\n        <ng-template #noReadErrorTemplate>\n          <ng-container [ngSwitch]=\"inputOptions.type\">\n            <ng-container *ngSwitchCase=\"'toggle'\">\n              <ion-toggle [disabled]=\"true\" [checked]=\"field.value\"></ion-toggle\n            ></ng-container>\n            <div\n              (click)=\"onValueClick($event)\"\n              *ngSwitchCase=\"'select'\"\n              class=\"item-value\"\n              [class]=\"isEditable ? 'cell' : ''\"\n            >\n              <ion-icon\n                *ngIf=\"selectedOption?.icon\"\n                [name]=\"selectedOption?.icon\"\n              ></ion-icon>\n              <ion-text class=\"tap-config-item-value\">\n                {{ displayedValue }}\n              </ion-text>\n            </div>\n            <ion-text\n              (click)=\"onValueClick($event)\"\n              class=\"item-value tap-config-item-value\"\n              *ngSwitchDefault\n              [class]=\"isEditable ? 'cell' : ''\"\n            >\n              {{ displayedValue }}\n            </ion-text>\n          </ng-container>\n        </ng-template>\n      </ng-container>\n      <ng-template #editModeTemplate>\n        <ng-container [ngSwitch]=\"inputOptions.type\">\n          <ion-toggle\n            *ngSwitchCase=\"'toggle'\"\n            [disabled]=\"loading || !!pendingEditCall\"\n            [formControl]=\"field\"\n          ></ion-toggle>\n          <ion-select\n            style=\"max-width: 100% !important\"\n            *ngSwitchCase=\"'select'\"\n            [formControl]=\"field\"\n            [multiple]=\"inputOptions.multiple\"\n          >\n            <ion-select-option\n              *ngFor=\"let option of inputOptions.options\"\n              [value]=\"option.key\"\n            >\n              <ion-icon *ngIf=\"option.icon\" [name]=\"option.icon\"></ion-icon>\n              {{ option.text }}\n            </ion-select-option>\n            <ion-select-option\n              *ngFor=\"let enumValue of inputOptions.enum?.data | listEnumValues\"\n              [value]=\"enumValue\"\n            >\n              <ion-icon\n                [name]=\"\n                  enumValue\n                    | tapResourceEnumTranslate : 'icon' : inputOptions.enum\n                    | async\n                \"\n              ></ion-icon>\n              {{\n                enumValue\n                  | tapResourceEnumTranslate : 'title' : inputOptions.enum\n                  | async\n              }}\n            </ion-select-option>\n          </ion-select>\n          <ion-input\n            *ngSwitchDefault\n            (keydown.enter)=\"submit($event)\"\n            (keydown.escape)=\"cancelEdit($event)\"\n            [disabled]=\"!!pendingEditCall\"\n            [maxlength]=\"inputOptions.maxLength\"\n            [minlength]=\"inputOptions.minLength\"\n            [max]=\"inputOptions.max\"\n            [min]=\"inputOptions.min\"\n            [pattern]=\"inputOptions.pattern\"\n            [placeholder]=\"placeholder\"\n            [type]=\"inputOptions.type\"\n            appAutofocus\n            class=\"cellInput\"\n            [formControl]=\"field\"\n          >\n          </ion-input>\n        </ng-container>\n      </ng-template>\n      <ion-buttons slot=\"end\">\n        <ion-button\n          (click)=\"explainPendingCall()\"\n          *ngIf=\"pendingEditCall\"\n          [disabled]=\"false\"\n          color=\"warning\"\n        >\n          <ion-icon name=\"alert-circle\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"editMode = true\"\n          *ngIf=\"!globalSubmit && !editMode && info.putValue\"\n        >\n          <ion-icon name=\"create\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"submit($event)\"\n          *ngIf=\"!globalSubmit && editMode && !pendingEditCall\"\n          [disabled]=\"loading || pendingEditCall\"\n        >\n          <ion-icon name=\"send\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"cancelEdit()\"\n          *ngIf=\"isEditable && editMode && (!globalSubmit || isEdited())\"\n          color=\"quaternary\"\n          [disabled]=\"loading\"\n        >\n          <ion-icon name=\"close\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"refreshValue()\"\n          *ngIf=\"refresh && info.getValue && !editMode\"\n          [disabled]=\"loading\"\n        >\n          <ion-icon name=\"sync\"></ion-icon>\n        </ion-button>\n      </ion-buttons>\n      <ion-spinner *ngIf=\"loading\" slot=\"end\"></ion-spinner>\n    </ng-container>\n    <ng-template #ressourceNotAvailableTemplate>\n      <ion-text color=\"warning\" class=\"read-value-error\">\n        <ion-icon name=\"alert-circle\"></ion-icon>\n        Not available with your firmware version or Tap model\n      </ion-text>\n    </ng-template>\n  </ng-template>\n</ion-item>\n<ion-item *ngIf=\"writeError\">\n  <ion-text color=\"danger\" class=\"tap-config-item-error\">\n    <ion-icon name=\"alert-circle\"></ion-icon>\n    Failed to write value: {{ writeError | tapRequestErrorToString }}\n  </ion-text>\n</ion-item>\n<app-common-form-error-item\n  [formControlRef]=\"field\"\n></app-common-form-error-item>\n", styles: [".cell{border:2px solid transparent;padding:11px 0;width:100%;height:100%}.cell:hover{cursor:pointer;border:2px dashed #c8c8c8}ion-item{--padding-start: 0px}.cellInput{border:2px solid transparent;padding:11px 20px;width:100%;height:100%}ion-select{min-width:150px}.read-value-error{font-weight:700}ion-buttons{margin-inline-start:5px}.item-value,ion-select,ion-input{font-weight:700;font-weight:1.05em}\n"], dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i5.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i3.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i3.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i3.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i3.IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: i3.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i3.IonSelect, selector: "ion-select", inputs: ["cancelText", "compareWith", "disabled", "interface", "interfaceOptions", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "value"] }, { kind: "component", type: i3.IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: i3.IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: i3.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i3.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i3.IonToggle, selector: "ion-toggle", inputs: ["checked", "color", "disabled", "enableOnOffLabels", "mode", "name", "value"] }, { kind: "directive", type: i3.BooleanValueAccessor, selector: "ion-checkbox,ion-toggle" }, { kind: "directive", type: i3.SelectValueAccessor, selector: "ion-range, ion-select, ion-radio-group, ion-segment, ion-datetime" }, { kind: "directive", type: i3.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar" }, { kind: "directive", type: i1.AutoFocusDirective, selector: "[appAutofocus]", inputs: ["appAutoFocus"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i6.FormErrorItemComponent, selector: "app-common-form-error-item", inputs: ["formControlRef"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: TapRequestErrorToStringPipe, name: "tapRequestErrorToString" }, { kind: "pipe", type: TapResourceEnumTranslatePipe, name: "tapResourceEnumTranslate" }, { kind: "pipe", type: ListEnumValuesPipe, name: "listEnumValues" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemComponent, decorators: [{
            type: Component,
            args: [{ selector: 'tap-config-item', template: "<ion-item *ngIf=\"_config\" [lines]=\"isEditable ? '' : 'none'\">\n  <ion-skeleton-text\n    animated\n    *ngIf=\"\n      displayedValue === undefined && readError === undefined;\n      else valueFetchedTemplate\n    \"\n  ></ion-skeleton-text>\n  <ng-template #valueFetchedTemplate>\n    <ng-container\n      *ngIf=\"ressourceAvailable; else ressourceNotAvailableTemplate\"\n    >\n      <ng-container *ngIf=\"!editMode || !isEditable; else editModeTemplate\">\n        <ion-text\n          color=\"warning\"\n          class=\"read-value-error\"\n          (click)=\"onValueClick($event)\"\n          [class]=\"isEditable ? 'cell' : ''\"\n          *ngIf=\"readError; else noReadErrorTemplate\"\n        >\n          <ion-icon name=\"alert-circle\"></ion-icon>\n          {{ readError | tapRequestErrorToString }}\n        </ion-text>\n        <ng-template #noReadErrorTemplate>\n          <ng-container [ngSwitch]=\"inputOptions.type\">\n            <ng-container *ngSwitchCase=\"'toggle'\">\n              <ion-toggle [disabled]=\"true\" [checked]=\"field.value\"></ion-toggle\n            ></ng-container>\n            <div\n              (click)=\"onValueClick($event)\"\n              *ngSwitchCase=\"'select'\"\n              class=\"item-value\"\n              [class]=\"isEditable ? 'cell' : ''\"\n            >\n              <ion-icon\n                *ngIf=\"selectedOption?.icon\"\n                [name]=\"selectedOption?.icon\"\n              ></ion-icon>\n              <ion-text class=\"tap-config-item-value\">\n                {{ displayedValue }}\n              </ion-text>\n            </div>\n            <ion-text\n              (click)=\"onValueClick($event)\"\n              class=\"item-value tap-config-item-value\"\n              *ngSwitchDefault\n              [class]=\"isEditable ? 'cell' : ''\"\n            >\n              {{ displayedValue }}\n            </ion-text>\n          </ng-container>\n        </ng-template>\n      </ng-container>\n      <ng-template #editModeTemplate>\n        <ng-container [ngSwitch]=\"inputOptions.type\">\n          <ion-toggle\n            *ngSwitchCase=\"'toggle'\"\n            [disabled]=\"loading || !!pendingEditCall\"\n            [formControl]=\"field\"\n          ></ion-toggle>\n          <ion-select\n            style=\"max-width: 100% !important\"\n            *ngSwitchCase=\"'select'\"\n            [formControl]=\"field\"\n            [multiple]=\"inputOptions.multiple\"\n          >\n            <ion-select-option\n              *ngFor=\"let option of inputOptions.options\"\n              [value]=\"option.key\"\n            >\n              <ion-icon *ngIf=\"option.icon\" [name]=\"option.icon\"></ion-icon>\n              {{ option.text }}\n            </ion-select-option>\n            <ion-select-option\n              *ngFor=\"let enumValue of inputOptions.enum?.data | listEnumValues\"\n              [value]=\"enumValue\"\n            >\n              <ion-icon\n                [name]=\"\n                  enumValue\n                    | tapResourceEnumTranslate : 'icon' : inputOptions.enum\n                    | async\n                \"\n              ></ion-icon>\n              {{\n                enumValue\n                  | tapResourceEnumTranslate : 'title' : inputOptions.enum\n                  | async\n              }}\n            </ion-select-option>\n          </ion-select>\n          <ion-input\n            *ngSwitchDefault\n            (keydown.enter)=\"submit($event)\"\n            (keydown.escape)=\"cancelEdit($event)\"\n            [disabled]=\"!!pendingEditCall\"\n            [maxlength]=\"inputOptions.maxLength\"\n            [minlength]=\"inputOptions.minLength\"\n            [max]=\"inputOptions.max\"\n            [min]=\"inputOptions.min\"\n            [pattern]=\"inputOptions.pattern\"\n            [placeholder]=\"placeholder\"\n            [type]=\"inputOptions.type\"\n            appAutofocus\n            class=\"cellInput\"\n            [formControl]=\"field\"\n          >\n          </ion-input>\n        </ng-container>\n      </ng-template>\n      <ion-buttons slot=\"end\">\n        <ion-button\n          (click)=\"explainPendingCall()\"\n          *ngIf=\"pendingEditCall\"\n          [disabled]=\"false\"\n          color=\"warning\"\n        >\n          <ion-icon name=\"alert-circle\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"editMode = true\"\n          *ngIf=\"!globalSubmit && !editMode && info.putValue\"\n        >\n          <ion-icon name=\"create\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"submit($event)\"\n          *ngIf=\"!globalSubmit && editMode && !pendingEditCall\"\n          [disabled]=\"loading || pendingEditCall\"\n        >\n          <ion-icon name=\"send\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"cancelEdit()\"\n          *ngIf=\"isEditable && editMode && (!globalSubmit || isEdited())\"\n          color=\"quaternary\"\n          [disabled]=\"loading\"\n        >\n          <ion-icon name=\"close\"></ion-icon>\n        </ion-button>\n        <ion-button\n          (click)=\"refreshValue()\"\n          *ngIf=\"refresh && info.getValue && !editMode\"\n          [disabled]=\"loading\"\n        >\n          <ion-icon name=\"sync\"></ion-icon>\n        </ion-button>\n      </ion-buttons>\n      <ion-spinner *ngIf=\"loading\" slot=\"end\"></ion-spinner>\n    </ng-container>\n    <ng-template #ressourceNotAvailableTemplate>\n      <ion-text color=\"warning\" class=\"read-value-error\">\n        <ion-icon name=\"alert-circle\"></ion-icon>\n        Not available with your firmware version or Tap model\n      </ion-text>\n    </ng-template>\n  </ng-template>\n</ion-item>\n<ion-item *ngIf=\"writeError\">\n  <ion-text color=\"danger\" class=\"tap-config-item-error\">\n    <ion-icon name=\"alert-circle\"></ion-icon>\n    Failed to write value: {{ writeError | tapRequestErrorToString }}\n  </ion-text>\n</ion-item>\n<app-common-form-error-item\n  [formControlRef]=\"field\"\n></app-common-form-error-item>\n", styles: [".cell{border:2px solid transparent;padding:11px 0;width:100%;height:100%}.cell:hover{cursor:pointer;border:2px dashed #c8c8c8}ion-item{--padding-start: 0px}.cellInput{border:2px solid transparent;padding:11px 20px;width:100%;height:100%}ion-select{min-width:150px}.read-value-error{font-weight:700}ion-buttons{margin-inline-start:5px}.item-value,ion-select,ion-input{font-weight:700;font-weight:1.05em}\n"] }]
        }], ctorParameters: function () { return [{ type: i1$2.FormBuilder }, { type: i1.CurrentDeviceService }, { type: i3.ToastController }, { type: i1.TapInfoRequestService }, { type: i1.TapInfoDAOService }, { type: i1.TapInfoCacheService }, { type: TapConfigItemStateService }, { type: i1.TapInfoConfigService }]; }, propDecorators: { focusOut: [{
                type: Output
            }], onSubmit: [{
                type: Output
            }], editable: [{
                type: Input
            }], info: [{
                type: Input
            }], refresh: [{
                type: Input
            }], editMode: [{
                type: Input
            }], globalSubmit: [{
                type: Input
            }] } });

class TapConfigItemDisplayedPipe {
    constructor(tapInfoCacheService, tapConfigItemStateService) {
        this.tapInfoCacheService = tapInfoCacheService;
        this.tapConfigItemStateService = tapConfigItemStateService;
    }
    transform(config) {
        if (!config || !config.isDisplayed) {
            return of(true);
        }
        return config.isDisplayed(this);
    }
}
/** @nocollapse */ TapConfigItemDisplayedPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemDisplayedPipe, deps: [{ token: i1.TapInfoCacheService }, { token: TapConfigItemStateService }], target: i0.ɵɵFactoryTarget.Pipe });
/** @nocollapse */ TapConfigItemDisplayedPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemDisplayedPipe, name: "tapConfigItemDisplayed" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemDisplayedPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'tapConfigItemDisplayed',
                }]
        }], ctorParameters: function () { return [{ type: i1.TapInfoCacheService }, { type: TapConfigItemStateService }]; } });

class TapConfigListComponent {
    set items(items) {
        if (!items) {
            items = [];
        }
        this._items = items.reduce((prev, item) => {
            var _a;
            if (typeof item === 'string') {
                item = {
                    key: item,
                };
            }
            let result = item;
            let defaultOption = defaultInfoResolverConfig.find((d) => item.key === d.key);
            if (defaultOption) {
                result = Object.assign(Object.assign({}, result), defaultOption);
            }
            result.title = this.translate.instant(tapResourceTranslateKey(result.key, 'title'));
            result.description = this.translate.instant(tapResourceTranslateKey(result.key, 'description'));
            if (result.editable === undefined) {
                result.editable = this.tapInfoDAOService.hasPut(result);
            }
            if (!result.input) {
                result.input = {};
            }
            const schema = (_a = TapResourceMetaData[item.key]) === null || _a === void 0 ? void 0 : _a.put.schema;
            if (schema) {
                fillFromSchema(result.input, schema);
            }
            prev.push(result);
            return prev;
        }, []);
    }
    constructor(translate, tapInfoDAOService) {
        this.translate = translate;
        this.tapInfoDAOService = tapInfoDAOService;
        this.itemRefresh = false;
        this.editMode = false;
        this.globalSubmit = false;
        this.lines = 'full';
        this._items = [];
    }
}
/** @nocollapse */ TapConfigListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigListComponent, deps: [{ token: i1$1.TranslateService }, { token: i1.TapInfoDAOService }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TapConfigListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TapConfigListComponent, selector: "tap-config-list", inputs: { itemRefresh: "itemRefresh", editMode: "editMode", globalSubmit: "globalSubmit", lines: "lines", items: "items" }, ngImport: i0, template: "<ion-grid *ngIf=\"_items && _items.length > 0\">\n  <ion-row *ngFor=\"let item of _items\" class=\"tap-config-row-{{ item.key }}\">\n    <ng-container *ngIf=\"item | tapConfigItemDisplayed | async\">\n      <ion-col size-xs=\"12\" size-sm=\"6\">\n        <ion-label>\n          <span class=\"item-title\"\n            ><ion-icon\n              slot=\"start\"\n              *ngIf=\"item.icon\"\n              [name]=\"item.icon\"\n            ></ion-icon>\n            {{ item.title }}</span\n          >\n          <br *ngIf=\"item.description\" />\n          <span class=\"item-description\">{{ item.description }}</span>\n        </ion-label>\n      </ion-col>\n      <ion-col size-xs=\"12\" size-sm=\"6\">\n        <tap-config-item\n          [info]=\"item\"\n          [refresh]=\"itemRefresh\"\n          [editable]=\"editMode\"\n          [editMode]=\"editMode\"\n          [globalSubmit]=\"globalSubmit\"\n        ></tap-config-item>\n      </ion-col>\n    </ng-container>\n  </ion-row>\n</ion-grid>\n", styles: [".item-title{display:inline-block;vertical-align:middle}.item-description{font-size:.8em;color:#777}@media (prefers-color-scheme: dark){:root .item-title{color:#eee}}@media (max-width: 575px){ion-row{border-bottom:1px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, .13))))}ion-grid{padding:0}}ion-col{padding-top:0;padding-bottom:0}\n"], dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i3.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i3.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i3.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i3.IonRow, selector: "ion-row" }, { kind: "component", type: TapConfigItemComponent, selector: "tap-config-item", inputs: ["editable", "info", "refresh", "editMode", "globalSubmit"], outputs: ["focusOut", "onSubmit"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: TapConfigItemDisplayedPipe, name: "tapConfigItemDisplayed" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigListComponent, decorators: [{
            type: Component,
            args: [{ selector: 'tap-config-list', template: "<ion-grid *ngIf=\"_items && _items.length > 0\">\n  <ion-row *ngFor=\"let item of _items\" class=\"tap-config-row-{{ item.key }}\">\n    <ng-container *ngIf=\"item | tapConfigItemDisplayed | async\">\n      <ion-col size-xs=\"12\" size-sm=\"6\">\n        <ion-label>\n          <span class=\"item-title\"\n            ><ion-icon\n              slot=\"start\"\n              *ngIf=\"item.icon\"\n              [name]=\"item.icon\"\n            ></ion-icon>\n            {{ item.title }}</span\n          >\n          <br *ngIf=\"item.description\" />\n          <span class=\"item-description\">{{ item.description }}</span>\n        </ion-label>\n      </ion-col>\n      <ion-col size-xs=\"12\" size-sm=\"6\">\n        <tap-config-item\n          [info]=\"item\"\n          [refresh]=\"itemRefresh\"\n          [editable]=\"editMode\"\n          [editMode]=\"editMode\"\n          [globalSubmit]=\"globalSubmit\"\n        ></tap-config-item>\n      </ion-col>\n    </ng-container>\n  </ion-row>\n</ion-grid>\n", styles: [".item-title{display:inline-block;vertical-align:middle}.item-description{font-size:.8em;color:#777}@media (prefers-color-scheme: dark){:root .item-title{color:#eee}}@media (max-width: 575px){ion-row{border-bottom:1px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, .13))))}ion-grid{padding:0}}ion-col{padding-top:0;padding-bottom:0}\n"] }]
        }], ctorParameters: function () { return [{ type: i1$1.TranslateService }, { type: i1.TapInfoDAOService }]; }, propDecorators: { itemRefresh: [{
                type: Input
            }], editMode: [{
                type: Input
            }], globalSubmit: [{
                type: Input
            }], lines: [{
                type: Input
            }], items: [{
                type: Input
            }] } });
function fillFromSchema(input, schema) {
    var _a;
    if (!input.type) {
        if (schema.type == 'string') {
            input.type = 'text';
        }
        else if (schema.type === 'number' || schema.type === 'integer') {
            input.type = 'number';
        }
    }
    if (!input.formValidators) {
        input.formValidators = [];
        if (schema.minLength) {
            input.formValidators.push(Validators.minLength(schema.minLength));
        }
        if (schema.maxLength) {
            input.formValidators.push(Validators.maxLength(schema.maxLength));
        }
        if (schema.minimum) {
            input.formValidators.push(Validators.min(schema.minimum));
            input.min = schema.minimum;
        }
        if (schema.maximum) {
            input.formValidators.push(Validators.max(schema.maximum));
            input.max = schema.maximum;
        }
        if (schema.pattern) {
            input.formValidators.push(Validators.pattern(schema.pattern));
        }
        if (schema.type === 'integer') {
            if ((_a = schema.format) === null || _a === void 0 ? void 0 : _a.startsWith('uint')) {
                input.formValidators.push(unsignedIntegerValidator);
            }
            else {
                input.formValidators.push(signedIntegerValidator);
            }
        }
    }
}
const unsignedIntegerValidator = customValidatorPattern(/^[0-9]*$/, 'unsignedInteger');
const signedIntegerValidator = customValidatorPattern(/^-?[0-9]*$/, 'signedInteger');
function customValidatorPattern(pattern, keyName) {
    return (control) => {
        const value = control.value;
        const valueMatchPattern = pattern.test(value);
        return !valueMatchPattern ? { [keyName]: { value: control.value } } : null;
    };
}

function parseTapConfiguratorConfig(fileContent) {
    if (isJsonString(fileContent)) {
        const config = JSON.parse(fileContent);
        // this.tapConfigPickerservice.onConfigSelected(config);
        return config;
    }
    else {
        // if (IotizeConfigFactory.fromXML(fileContent)) {
        return fromXml(fileContent);
    }
}
function isJsonString(str) {
    try {
        const json = JSON.parse(str);
        return typeof json === 'object';
    }
    catch (e) {
        return false;
    }
}
function fromXml(fileContent) {
    // console.log('File content', fileContent);
    // const parser = new DOMParser();
    // const xmlConfig = parser.parseFromString(fileContent, 'application/xml');
    // let xmlConfig = parse(fileContent);
    const xmlConfig = iotizeStudioConfigToJson(fileContent);
    const config = new IoTizeStudioToTapConfigConverter().convert(new DotAccessor(xmlConfig));
    return { config };
}
function iotizeStudioConfigToJson(fileContent) {
    return xmlToJson(fileContent, {
        attributeNamePrefix: '',
        ignoreAttributes: false,
    });
}

class TapServiceCallListPipe {
    constructor(apiExplorer, translate) {
        this.apiExplorer = apiExplorer;
        this.translate = translate;
    }
    transform(search, options) {
        const allPaths = this._getApiPaths();
        return computeFilteredOptions(allPaths, search, options);
    }
    _getApiPaths() {
        if (!this._paths) {
            this._paths = this.apiExplorer.listAllPaths().map((valueOrignal) => {
                const value = Object.assign({}, valueOrignal);
                value.tapRequestString = `${TapRequestFrame.MethodType[value.method]} ${value.pathAlias}`;
                value.pathParameters = PathParameter.extractParams(value.path).reduce((prev, key) => {
                    prev[key] = 0;
                    return prev;
                }, {});
                if (value.pathAlias) {
                    if (value.method === TapRequestFrame.MethodType.GET) {
                        const titleKey = tapResourceTranslateKey(value.pathAlias, 'title');
                        const titleValue = this.translate.instant(titleKey);
                        value.title = titleKey !== titleValue ? titleValue : undefined;
                    }
                    // value.description = this.translate.instant(
                    //   tapResourceTranslateKey(value.pathAlias, 'description')
                    // );
                }
                return value;
            });
        }
        return this._paths;
    }
}
/** @nocollapse */ TapServiceCallListPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapServiceCallListPipe, deps: [{ token: i1.TapApiExplorerService }, { token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe });
/** @nocollapse */ TapServiceCallListPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: TapServiceCallListPipe, name: "tapServiceCallList" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapServiceCallListPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'tapServiceCallList',
                }]
        }], ctorParameters: function () { return [{ type: i1.TapApiExplorerService }, { type: i1$1.TranslateService }]; } });
function computeFilteredOptions(allPaths, searchObject, options) {
    if ((options === null || options === void 0 ? void 0 : options.method) !== undefined) {
        allPaths = allPaths.filter((call) => call.method === options.method);
    }
    if (!searchObject) {
        return allPaths;
    }
    let search = typeof searchObject === 'string'
        ? searchObject
        : searchObject.tapRequestString;
    if (!search) {
        return allPaths;
    }
    search = search.trim();
    return allPaths.filter((call) => {
        return stringContains(`${call.tapRequestString}`.toLowerCase(), search.toLowerCase());
    });
}
function findBiggestSeq(input, search) {
    if (search.length == 0) {
        return 0;
    }
    for (let i = 1; i <= search.length; i++) {
        let substr = search.substr(0, i);
        if (input.indexOf(substr) == -1) {
            return i - 1;
        }
    }
    return search.length;
}
function stringContains(input, search) {
    if (search.length == 0) {
        return true;
    }
    else {
        let seqLength = findBiggestSeq(input, search);
        if (seqLength == 0) {
            return false;
        }
        else {
            let matchSearch = search.substring(0, seqLength);
            let newSearch = search.substring(seqLength);
            input = input.substr(input.indexOf(matchSearch));
            return stringContains(input, newSearch);
        }
    }
}

class TapConfigModule {
}
/** @nocollapse */ TapConfigModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
/** @nocollapse */ TapConfigModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: TapConfigModule, declarations: [TapConfigItemComponent,
        TapConfigListComponent,
        TapRequestErrorToStringPipe,
        TapConfigItemDisplayedPipe,
        TapResourceEnumTranslatePipe,
        ListEnumValuesPipe,
        TapServiceCallListPipe], imports: [LibCommonModule,
        FormsModule,
        ReactiveFormsModule,
        FormErrorItemModule,
        TranslateModule], exports: [TapRequestErrorToStringPipe,
        TapConfigItemComponent,
        TapConfigListComponent,
        TapResourceEnumTranslatePipe,
        TapServiceCallListPipe] });
/** @nocollapse */ TapConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigModule, imports: [LibCommonModule,
        FormsModule,
        ReactiveFormsModule,
        FormErrorItemModule,
        TranslateModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        TapConfigItemComponent,
                        TapConfigListComponent,
                        TapRequestErrorToStringPipe,
                        TapConfigItemDisplayedPipe,
                        TapResourceEnumTranslatePipe,
                        ListEnumValuesPipe,
                        TapServiceCallListPipe,
                    ],
                    exports: [
                        TapRequestErrorToStringPipe,
                        TapConfigItemComponent,
                        TapConfigListComponent,
                        TapResourceEnumTranslatePipe,
                        TapServiceCallListPipe,
                    ],
                    imports: [
                        LibCommonModule,
                        FormsModule,
                        ReactiveFormsModule,
                        FormErrorItemModule,
                        TranslateModule,
                    ],
                }]
        }] });

class TapConfigurationModeService {
    get loading() {
        return this._loadingCounter > 0;
    }
    constructor(tapService, tapInfoCacheService, tapConfigItemStateService) {
        this.tapService = tapService;
        this.tapInfoCacheService = tapInfoCacheService;
        this.tapConfigItemStateService = tapConfigItemStateService;
        this._loadingCounter = 0;
        this.configurationModeChange = this.tapInfoCacheService
            .valueChange(TapInfo.configVersion)
            .pipe(map((v) => {
            return v === CONFIGURATION_MODE_VERSION;
        }), tap((v) => {
            this.editMode = v;
        }), shareReplay(1));
        this.editMode = false;
        this.isConfigurationModeAvailable = this.tapService.connectionStateReplay.pipe(switchMap((event) => {
            if (event.newState === ConnectionState.CONNECTED) {
                return this.tapService.sessionState.pipe(map((sessionState) => {
                    return (sessionState.name === ADMIN_USER.username ||
                        sessionState.groupId === ADMIN_USER.id);
                }));
            }
            else {
                return of(false);
            }
        }));
    }
    _setConfigurationVersion(v) {
        this.tapInfoCacheService.setKeyValue({ key: TapInfo.configVersion }, v);
    }
    enableConfigurationMode() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                this._loadingCounter++;
                const tap = this.tapService.tap;
                const [getVersionCall, putVersionCall] = yield tap.service.interface.executeMultipleCalls([
                    tap.service.interface.getConfigVersionCall(),
                    tap.service.interface.putConfigVersionCall(CONFIGURATION_MODE_VERSION),
                ]);
                this._version = yield getVersionCall.body();
                putVersionCall.successful();
                this._setConfigurationVersion(CONFIGURATION_MODE_VERSION);
            }
            finally {
                this._loadingCounter--;
            }
        });
    }
    applyConfigurationMode() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                this._loadingCounter++;
                const tap = this.tapService.tap;
                yield this.tapConfigItemStateService.savePendingChanges();
                const newVersionChange = this.tapConfigItemStateService
                    .getPendingChangesSnapshot()
                    .find(({ key }) => {
                    return key.key === TapInfo.configVersion;
                });
                let newVersion;
                if (newVersionChange) {
                    newVersion = newVersionChange.value;
                }
                else {
                    newVersion = this._version || '1.0.0';
                }
                if (newVersion === CONFIGURATION_MODE_VERSION ||
                    newVersion === FACTORY_RESET_MODE_VERSION) {
                    newVersion = '1.0.0';
                }
                const [applyConfig, reloadConfig] = yield tap.service.interface.executeMultipleCalls([
                    tap.service.interface.putConfigVersionCall(newVersion),
                    tap.service.interface.reloadConfigCall(),
                ]);
                applyConfig.successful();
                reloadConfig.successful();
                this.tapConfigItemStateService.clearPendingChanges();
                this._setConfigurationVersion(newVersion);
            }
            finally {
                this._loadingCounter--;
            }
        });
    }
    cancelConfigurationMode() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                this._loadingCounter++;
                const tap = this.tapService.tap;
                const [reloadConfig, getConfigVersion] = yield tap.service.interface.executeMultipleCalls([
                    tap.service.interface.reloadConfigCall(),
                    tap.service.interface.getConfigVersionCall(),
                ]);
                reloadConfig.successful();
                this._setConfigurationVersion(getConfigVersion.body());
                this.tapConfigItemStateService.clearPendingChanges();
            }
            finally {
                this._loadingCounter--;
            }
        });
    }
}
/** @nocollapse */ TapConfigurationModeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigurationModeService, deps: [{ token: i1.CurrentDeviceService }, { token: i1.TapInfoCacheService }, { token: TapConfigItemStateService }], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ TapConfigurationModeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigurationModeService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigurationModeService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }], ctorParameters: function () { return [{ type: i1.CurrentDeviceService }, { type: i1.TapInfoCacheService }, { type: TapConfigItemStateService }]; } });

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

export { TapConfigItemComponent, TapConfigItemStateService, TapConfigListComponent, TapConfigModule, TapConfigurationModeService, TapRequestErrorToStringPipe, TapResourceEnumTranslatePipe, TapServiceCallListPipe, defaultInfoResolverConfig, fromXml, isJsonString, isTapConfigured, parseTapConfiguratorConfig };
//# sourceMappingURL=iotize-ionic-config.mjs.map
