import { bufferToHexString, hexStringToBuffer } from '@iotize/common/byte-converter';
import { KaitaiStreamWriter } from '@iotize/common/byte-stream';
import { DotAccessor } from '@iotize/common/data-accessor';
import { HostProtocol, SpecialFeature } from '@iotize/tap';
import { ADMIN_USER, ANONYMOUS_USER, isSpecialUser } from '@iotize/tap/configurator';
import { reversedTargetSerialModbusConfiguration, SecurityOptionsConverter, SerialSettings, TapnpassProtocolConfigurationConverter, VariableType, } from '@iotize/tap/service/all';
import { converters } from '@iotize/tap/service/core';
import { parse } from 'fast-xml-parser';
import { IoTizeStudioError } from '../errors';
import { toEnumType } from '../util';
import { LowPowerOptimizationLevelMapping, NetworkModeMapping, NFC_CONNECTION_PRIORITY_MAPPING, NFCParingModeMapping, S3P_CONFIG_MODE_MAPPING, TargetProtocolMapping, WIFI_KEY_VISIBILITY_MAPPING, WIFI_PROTOCOL_MAPPING, WIFI_SSID_VISIBILITY_MAPPING, } from './mapping';
import { convertToVariableType, fromMapping, isTruthy } from './utility';
export function convertIoTizeStudioConfigToTapConfig(fileContent) {
    // console.log('File content', fileContent);
    const xmlConfig = parse(fileContent, {
        attributeNamePrefix: '',
        ignoreAttributes: false
    });
    const config = new IoTizeStudioToTapConfigConverter().convert(new DotAccessor(xmlConfig));
    return config;
}
function isHexString(input) {
    if (typeof input !== 'string') {
        return false;
    }
    return input.match(/^(0x)?([a-fA-F0-9])*$/);
}
export function decodeInitialVariableValue(value) {
    const values = value.split(';')
        .reduce((prev, v) => {
        if (v.length === 0) {
            return prev;
        }
        if (v.startsWith('0x')) {
            prev.push(v);
        }
        else {
            prev.push(parseFloat(v));
        }
        return prev;
    }, []);
    return values.length > 0 ?
        (values.length === 1 ? values[0] : values) : undefined;
}
/**
 * Convert an IoTize studio configuration file to TapConfiguratorConfig
 *
 * TODO it's a partial implementation, some keys need to be implemented.
 * Not exaustive list of not supported keys:
 *  - JVM code
 *  - Lora config
 *
 */
export class IoTizeStudioToTapConfigConverter {
    constructor(options = {
        strict: false
    }, host) {
        this.options = options;
        this.host = host;
        /**
         * Errors reported during convertion when strict mode is disabled
         */
        this.warnings = [];
        this.modbusSerialConfigConverter = new TapnpassProtocolConfigurationConverter();
    }
    convert(root) {
        const config = root.get('IOTizeConfiguration');
        const appConfigNode = config.get('IOTizeApp');
        const wifiConfigNode = appConfigNode.get('WIFI_Info', undefined);
        const bundles = config.list('IOTizeBundle', []);
        const profiles = config.list('IOTizeProfile', []);
        const versionString = config.value('Version', 'string', '1.0.0');
        const result = {
            version: versionString,
            application: this.readApplicationConfig(appConfigNode),
            data: {
                bundles: this.readBundlesConfig(bundles),
                profiles: this.readProfilesConfig(profiles)
            },
            cloud: this.readCloudConfig(appConfigNode),
            jvm: this.readJvmConfig(config),
            wireless: {
                options: this.readWirelessOptionsConfig(appConfigNode),
                protocols: {
                    wifi: this.readWifiConfig(wifiConfigNode),
                    mqtt: this.readMqttConfig(wifiConfigNode),
                    ble: this.readBleConfig(appConfigNode),
                    lora: this.readLoraConfig(appConfigNode),
                    nfc: this.readNfcConfig(appConfigNode)
                }
            },
            tap: this.readTapConfig(appConfigNode),
            target: this.readTargetConfig(appConfigNode),
        };
        if (this.warnings.length > 0) {
        }
        return result;
    }
    reportError(error, message = error.message) {
        if (this.options.strict) {
            throw error;
        }
        this.warnings.push({
            error,
            message
        });
    }
    readMqttConfig(appConfig) {
        var _a, _b, _c, _d, _e, _f, _g;
        if (!appConfig) {
            return undefined;
        }
        return {
            brokerHostname: (_a = appConfig.get('CloudHostName', undefined)) === null || _a === void 0 ? void 0 : _a.value('Name', 'string', undefined),
            brokerPort: (_b = appConfig.get('CloudServiceName', undefined)) === null || _b === void 0 ? void 0 : _b.value('Name', 'string', undefined),
            password: (_c = appConfig.get('CloudMQTT_UID', undefined)) === null || _c === void 0 ? void 0 : _c.value('Name', 'string', undefined),
            netKey: (_d = appConfig.get('GUI_DevNetkey', undefined)) === null || _d === void 0 ? void 0 : _d.value('Name', 'string', undefined),
            clientId: (_e = appConfig.get('GUI_DevMQTT_ClientID', undefined)) === null || _e === void 0 ? void 0 : _e.value('Name', 'string', undefined),
            brokerCertificate: this.readFileContentAsHexString((_f = appConfig.get('AWSRootCertificate', undefined)) === null || _f === void 0 ? void 0 : _f.value('Name', 'string', undefined)),
            relayNetKey: undefined,
            topicPrefix: undefined,
            username: (_g = appConfig.get('CloudMQTT_USERNAME', undefined)) === null || _g === void 0 ? void 0 : _g.value('Name', 'string', undefined)
        };
    }
    readLoraConfig(appConfigNode) {
        return {
            config: undefined,
            ids: undefined
        };
    }
    readBleConfig(appConfigNode) {
        return {
            pairing: appConfigNode.value('BLEPairingRequest', 'boolean', undefined)
        };
    }
    readNfcConfig(appConfigNode) {
        return {
            autoLogProfileId: appConfigNode.value('NFCLogin', 'number', undefined),
            connectionPriority: fromMapping(appConfigNode, 'NFCInterruptionLock', NFC_CONNECTION_PRIORITY_MAPPING, undefined),
            pairingMode: fromMapping(appConfigNode, 'NFCPairingMandatory', NFCParingModeMapping, undefined)
        };
    }
    readWifiConfig(wifiConfigNode) {
        if (!wifiConfigNode) {
            return undefined;
        }
        const mode = fromMapping(wifiConfigNode, 'Network', NetworkModeMapping, 'P2P');
        const isAP = mode === 'PEER_TO_PEER';
        return {
            mode,
            ssid: wifiConfigNode.value(isAP ? 'Module_AP_SSID' : 'ModuleSSID', 'string', undefined),
            key: wifiConfigNode.value(isAP ? 'Module_AP_WEPKey' : 'ModuleWEPKey', 'string', undefined),
            mask: wifiConfigNode.value('ModuleIPMask', 'string', undefined),
            ipGateway: wifiConfigNode.value('ModuleIPGateway', 'string', undefined),
            ip: wifiConfigNode.value('ModuleIPAddress', 'string', undefined),
            keyVisibility: fromMapping(wifiConfigNode, 'Wifi_WEPKey_Hidden', WIFI_KEY_VISIBILITY_MAPPING, undefined),
            protocol: fromMapping(wifiConfigNode, 'Wifi_Protocol', WIFI_PROTOCOL_MAPPING, undefined),
            region: wifiConfigNode.value('region', 'string', undefined),
            ssidVisibility: fromMapping(wifiConfigNode, 'Wifi_SSID_Hidden', WIFI_SSID_VISIBILITY_MAPPING, undefined),
            txPower: wifiConfigNode.value('Wifi_TxLevel', 'number', undefined)
        };
    }
    toAuthorizedHostProtocols(value) {
        if (!value || value === 'ALL' || value === 'FFFF') {
            return undefined;
        }
        if (isHexString(value)) {
            const encodedValue = hexStringToBuffer(value);
            return converters.hostProtocolArray
                .decode(encodedValue)
                .map(p => {
                return HostProtocol[p];
            });
        }
        else {
            return value.split(',')
                .reduce((prev, value) => {
                value = value.trim();
                try {
                    // TODO check it's a read HostProtocolConfig...
                    prev.push(value); //stringToEnum<HostProtocolConfig>(HostProtocolConfig, value));
                }
                catch (err) {
                    this.reportError(err);
                }
                return prev;
            }, []);
        }
    }
    readWirelessOptionsConfig(appConfigNode) {
        let availableHostProtocols = undefined;
        const hostProtocolString = appConfigNode.value('HostProtocol', 'string', undefined);
        try {
            availableHostProtocols = this.toAuthorizedHostProtocols(hostProtocolString);
        }
        catch (err) {
            this.reportError(err, `Cannot convert HostProtocol value "${hostProtocolString}"`);
        }
        return {
            inactivityTimeout: appConfigNode.value('LowPowerHostTimeout', 'number', 0),
            authorizedProtocols: availableHostProtocols && availableHostProtocols.length > 0 ? availableHostProtocols : undefined,
        };
    }
    readJvmConfig(config) {
        const appConfigNode = config.get('IOTizeApp');
        const envNode = config.get('GUI_Environment', undefined);
        const bcbFile = appConfigNode.value('JVM_Custom_Code', 'string', undefined);
        const useJvm = envNode === null || envNode === void 0 ? void 0 : envNode.value('UseInternalJVM', 'boolean', false);
        if (!useJvm) {
            return undefined;
        }
        return {
            code: bcbFile ? this.readFileContentAsHexString(bcbFile) : undefined,
        };
    }
    readFileContentAsHexString(path) {
        if (!path) {
            return undefined;
        }
        if (!this.host) {
            this.reportError(new Error(`External file reference "${path}" cannot be resolved`));
        }
        if (this.host) {
            try {
                const fileContent = this.host.getFileContent(path);
                return '0x' + bufferToHexString(fileContent);
            }
            catch (err) {
                this.reportError(err);
            }
        }
        return undefined;
    }
    readCloudConfig(appConfigNode) {
        const cloudService = appConfigNode.get('CloudServices', undefined);
        // if (cloudService?.has('CloudMQTT_UID')) {
        //     let url = '';
        //     const cloudHostName = cloudService.get('CloudHostName', undefined);
        //     const cloudServiceName = cloudService.get('CloudServiceName', undefined);
        //     if (cloudHostName) {
        //         url = `mqtt://${cloudHostName.value('Name', 'string', '')}:${cloudServiceName?.value('Name', 'string', '') || ''}`;
        //     }
        //     // cloud = {
        //     //     // password: cloudService
        //     //     //     .get('CloudMQTT_UID', undefined)
        //     //     //     ?.value('Name', 'string', '') || '',
        //     //     uploadPeriod: ,
        //     //     url
        //     // };
        // }
        const wifiNode = appConfigNode.get('WIFI_Info', undefined);
        return {
            dataLog: {
                mqttPublishTopic: wifiNode === null || wifiNode === void 0 ? void 0 : wifiNode.value('Cloud_Publish_Topic', 'string', undefined),
                mqttSubscribeTopic: wifiNode === null || wifiNode === void 0 ? void 0 : wifiNode.value('Cloud_Subscribe_Topic', 'string', undefined),
                uploadPeriod: cloudService === null || cloudService === void 0 ? void 0 : cloudService.value('CloudMqttPeriod', 'number', 0),
            }
            // platform: '' // TODO
        };
    }
    readApplicationConfig(appConfigNode) {
        const appPath = appConfigNode.has('GUI_Path')
            ? appConfigNode.value('GUI_Path', 'string', '')
            : appConfigNode.value('Path', 'string', '');
        // const appPathInfo = this.appPathConverter.decode(appPath);
        return {
            name: appConfigNode.value('Name', 'string', 'Tap'),
            universalLink: appConfigNode.value('WebLink', 'string', ''),
            uri: appPath
        };
    }
    readTapConfig(appConfigNode) {
        var _a, _b;
        const lockSettingsEncoded = appConfigNode.value('InterfaceLock', 'number', 0);
        const lockOptions = new SecurityOptionsConverter()
            .decode(Uint8Array.from([0, lockSettingsEncoded])); // TODO pad instead
        return {
            security: lockOptions,
            powerOptimization: fromMapping(appConfigNode, 'LowPowerLevel', LowPowerOptimizationLevelMapping, undefined),
            scram: {
                hashIteration: appConfigNode.value('Scram_Hash_It', 'number', 5000)
            },
            certificate: {
                publicKey: this.readFileContentAsHexString((_a = appConfigNode.get('DeviceCertificate', undefined)) === null || _a === void 0 ? void 0 : _a.value('Name', 'string', undefined)),
                privateKey: this.readFileContentAsHexString((_b = appConfigNode.get('DevicePrivateKey', undefined)) === null || _b === void 0 ? void 0 : _b.value('Name', 'string', undefined))
            }
        };
    }
    readTargetConfig(appConfig) {
        const firmwareVersion = appConfig.value('Firmware', 'string', undefined);
        if (appConfig.value('GUI_TargetType', 'string', '0') === '1') {
            return {
                type: 'TAPNPASS',
                protocol: {
                    config: this.readTapnpassTargetProtocolConfig(appConfig)
                },
                firmwareVersion
            };
        }
        else {
            const protocol = this.readMCUTargetProtocol(appConfig);
            if (!protocol) {
                return undefined;
            }
            return {
                type: 'MCU',
                protocol,
                firmwareVersion
            };
        }
        // if (appConfig.has('USB_Aliases')) {
        //   data.type = "TAPNPASS";
        //   (data as TapNPassTargetConfig).usb = this._convertUsbData(appConfig);
        // }
    }
    readTargetProtocol(appConfig) {
        // const targetProtocolString = appConfig.value('TargetProtocol', 'string', 'SWD');
        return fromMapping(appConfig, 'TargetProtocol', TargetProtocolMapping, 'NONE');
    }
    readTapnpassTargetProtocol(appConfig) {
        const targetProtocol = this.readTargetProtocol(appConfig);
        switch (targetProtocol) {
            case 'SERIAL':
                return {
                    type: 'SERIAL',
                    config: this.readTapnpassTargetProtocolConfig(appConfig)
                };
            case 'MODBUS':
                return {
                    type: 'MODBUS',
                    config: this.readTapnpassTargetProtocolConfig(appConfig)
                };
            default:
                throw new Error(`Illegal target protocol "${targetProtocol}" for TapNPass target type.`);
        }
    }
    readTapnpassTargetProtocolConfig(appConfig) {
        const targetProtocolConfDataLen = appConfig.value('TargetProtocolConfDataLen', 'number', 0);
        if (targetProtocolConfDataLen === 0) {
            return {
                modbus: {
                    offsetFirstRegister: false,
                    slave: 0
                },
                serial: {
                    baudRate: 115200,
                    bitParity: "EVEN",
                    dataBits: "_8",
                    handshakeDelimiter: "NONE",
                    hardwareFlowControl: "NONE",
                    identification: false,
                    ledStatus: true,
                    physicalPort: "AUTO",
                    stopBits: "ONE",
                    timeout: 255
                },
                usb: {
                    aliases: []
                }
            };
        }
        let protocolData = hexStringToBuffer(appConfig.value('TargetProtocolConfData', 'string'));
        if (protocolData.length < 8) {
            throw IoTizeStudioError.invalidKeyValue('TargetProtocolConfData', 'Protocol configuration data should be at least 8 bytes long');
        }
        const ctr1 = protocolData.slice(0, 4);
        const ctr2 = protocolData.slice(4, 8);
        const remaining = protocolData.slice(8);
        //  KaitaiStreamWriter.mergeArrays(ctr2, ctr1).reverse(),
        protocolData = KaitaiStreamWriter.mergeArrays(ctr1.reverse(), ctr2.reverse(), remaining);
        const protocolConf = reversedTargetSerialModbusConfiguration.decode(protocolData);
        const serial = protocolConf.serial;
        // TODO usb settings
        return {
            modbus: protocolConf.modbus,
            serial: {
                baudRate: serial.baudRate,
                bitParity: this.toEnumKey(serial.bitParity, SerialSettings.BitParity),
                dataBits: this.toEnumKey(serial.dataBits, SerialSettings.DataBits),
                handshakeDelimiter: this.toEnumKey(serial.handshakeDelimiter, SerialSettings.HandshakeDelimiter),
                hardwareFlowControl: this.toEnumKey(serial.hardwareFlowControl, SerialSettings.HardwareFlowControl),
                physicalPort: this.toEnumKey(serial.physicalPort, SerialSettings.PhysicalPort),
                stopBits: this.toEnumKey(serial.stopBits, SerialSettings.StopBits),
                timeout: serial.timeout,
                identification: false,
                ledStatus: false
            },
            usb: {
                aliases: [
                // TODO 
                ]
            }
        };
    }
    readMCUTargetProtocol(appConfig) {
        const targetProtocol = this.readTargetProtocol(appConfig);
        switch (targetProtocol) {
            case 'SWD':
                return {
                    type: targetProtocol
                };
            case 'CUSTOM':
                return {
                    type: 'CUSTOM'
                    // config: '0xTODO'
                };
            case 'MODBUS':
                return {
                    type: 'MODBUS',
                    config: this.readModbusProtocolConfig(appConfig)
                };
            case 'S3P':
                return {
                    type: 'S3P',
                    config: this.readS3PProtocolConfig(appConfig)
                };
            case 'SERIAL':
                return {
                    type: 'SERIAL',
                    config: this.readSerialProtocolConfig(appConfig)
                };
            case 'NONE':
                return undefined;
            case 'DIRECT_IO':
                return {
                    type: 'DIRECT_IO'
                };
            case 'JTAG':
            default:
                throw new Error(`Target protocol convertion from "${targetProtocol}" is not supported yet.`);
        }
    }
    readSerialProtocolConfig(appConfig) {
        const config = this.readModbusProtocolConfig(appConfig);
        if (!config) {
            return undefined;
        }
        return config === null || config === void 0 ? void 0 : config.serial;
    }
    readS3PProtocolConfig(appConfig) {
        return {
            mode: fromMapping(appConfig, 'S3Pmode', S3P_CONFIG_MODE_MAPPING) || 'EMULATION',
            delay: appConfig.value('S3PDelay', 'number', 1)
        };
    }
    readModbusProtocolConfig(appConfig) {
        const config = this.readTapnpassTargetProtocolConfig(appConfig);
        const partialSerial = config.serial;
        delete partialSerial.identification;
        delete partialSerial.physicalPort;
        delete partialSerial.hardwareFlowControl;
        delete partialSerial.ledStatus;
        return {
            modbus: config.modbus,
            serial: config.serial
        };
    }
    toEnumKey(value, mapping
    // , defaultValue: (keyof MappingType)
    ) {
        // if (value === undefined) {
        //     return defaultValue;
        // }
        if (!(value in mapping)) {
            this.reportError(new Error(`Cannot find corresponding key for value "${value}". Available keys: ${Object.keys(mapping).join(', ')}`));
        }
        return mapping[value];
    }
    // _convertUsbData(appConfig: IAccessor): UsbConfig {
    //   let aliases: UsbAlias[] = [];
    //   let usbAliasesAcccessor = appConfig.get('USB_Aliases');
    //   for (let aliasNum = 0; ; aliasNum++) {
    //     let aliasName = `Alias${aliasNum}`;
    //     if (!usbAliasesAcccessor.has(aliasName)) {
    //       break;
    //     }
    //     let usbAliasRawData = hexStringToBuffer(usbAliasesAcccessor.value(aliasName));
    //     aliases.push(this._convertUsbAlias(usbAliasRawData));
    //   }
    //   return {
    //     aliases: aliases
    //   };
    // }
    // private _convertUsbAlias(data: Uint8Array): UsbAlias {
    //   return this.usbAliasConverter.decode(data);
    // }
    readProfilesConfig(profiles) {
        const results = [];
        for (let i = 0; i < profiles.length; i++) {
            const xmlProfile = profiles[i];
            const name = xmlProfile.value('Name');
            let profile;
            if (name === ANONYMOUS_USER.username) {
                continue;
            }
            else if (isSpecialUser(name)) {
                const specialConfig = {
                    username: xmlProfile.value('Name', 'string'),
                    lifeTime: xmlProfile.value('LifeTime', 'number', 0),
                    key: this.readUserKey(xmlProfile)
                };
                profile = specialConfig;
            }
            else {
                const userConfig = {
                    username: xmlProfile.value('Name', 'string', ''),
                    id: xmlProfile.value('Id', 'number', 0),
                    lifeTime: xmlProfile.value('LifeTime', 'number', 0),
                    key: this.readUserKey(xmlProfile)
                };
                profile = userConfig;
            }
            const subProfilesConfig = xmlProfile.list('IOTizeUser', []);
            if (subProfilesConfig.length > 0) {
                const subProfiles = this.readUserProfile(subProfilesConfig);
                profile.users = subProfiles;
            }
            results.push(profile);
        }
        return results;
    }
    readUserKey(xmlProfile) {
        const scramPwd = xmlProfile.value('Scram_Pwd', 'string', undefined);
        if (scramPwd) {
            // let userSalt = xmlProfile.value('Scram_User_Salt', 'number');
            // specialConfig.salt = userSalt;
            return `0x${scramPwd}`;
        }
        else {
            const key = xmlProfile.value('Pwd', 'string', undefined);
            if (key) {
                return `0x${key}`;
            }
        }
        return undefined;
    }
    readUserProfile(subProfilesConfig) {
        const users = [];
        for (let i = 0; i < subProfilesConfig.length; i++) {
            const xmlUserConfig = subProfilesConfig[i];
            const user = {
                username: xmlUserConfig.value('Name', 'string', ''),
                id: xmlUserConfig.value('Id', 'number', 0),
                key: this.readUserKey(xmlUserConfig),
                lifeTime: 0 // There is no lifetime for users (only profile)
            };
            users.push(user);
        }
        return users;
    }
    readBundlesConfig(xmlBundles) {
        const result = [];
        for (let i = 0; i < xmlBundles.length; i++) {
            const xmlBundle = xmlBundles[i];
            let aclsXml = [];
            const aclContainer = xmlBundle.get('IOTizeAccessControl', undefined);
            if (aclContainer) {
                aclsXml = aclContainer.list('IOTizeACL', []);
            }
            const acls = {};
            for (let j = 0; j < aclsXml.length; j++) {
                const aclXml = aclsXml[j];
                const profileName = aclXml.value('ProfileName');
                if (profileName === ADMIN_USER.username) {
                    continue;
                }
                const rights = aclXml.value('Rights');
                acls[profileName] = {
                    read: rights.includes('read'),
                    write: rights.includes('write')
                };
            }
            const bundleConfig = {
                name: xmlBundle.value('GUI_Name'),
                id: parseInt(xmlBundle.value('Id')),
                variables: this.readVariablesConfig(xmlBundle.list('IOTizeVariable', [])),
                acls,
                dataLog: {
                    period: xmlBundle.value('DataLogPeriod', 'number', 0)
                },
                features: this.readSpecialFeatures(xmlBundle.list('Feature', []))
            };
            result.push(bundleConfig);
        }
        return result;
    }
    readSpecialFeatures(featuresXml) {
        if (featuresXml.length > 0) {
            const result = [];
            for (let i = 0; i < featuresXml.length; i++) {
                const featureId = featuresXml[i].value('FeatureResId', 'number');
                if (featureId in SpecialFeature) {
                    const value = SpecialFeature[featureId]; // TODO check
                    result.push(value);
                }
                else {
                    throw new Error(`Unexpected feature id: ${featureId}`);
                }
            }
            return result;
        }
        else {
            return undefined;
        }
    }
    readVariablesConfig(variables) {
        const result = [];
        for (let i = 0; i < variables.length; i++) {
            const xmlVariable = variables[i];
            const id = xmlVariable.value('Id', 'number');
            const length = xmlVariable.value('Quantity', 'number', 1);
            const dataType = toEnumType(convertToVariableType(xmlVariable), VariableType.Data);
            const name = xmlVariable.value('GUI_Name', 'string', '');
            const unit = xmlVariable.value('GUI_DispUnit', 'string', '') || undefined;
            let meta;
            if (name || unit) {
                meta = {
                    name,
                    unit
                };
            }
            const isInTapStatic = isTruthy(xmlVariable.value('IsInTap', 'string', '0'));
            const IsInTapVolatil = isTruthy(xmlVariable.value('IsInTapVolatil', 'string', '0'));
            if (IsInTapVolatil || isInTapStatic) {
                const initialValueString = xmlVariable.value('InTap_InitialValueString', 'string', '');
                const initialValue = decodeInitialVariableValue(initialValueString);
                const inTapVariable = {
                    domain: IsInTapVolatil ? 'IN_TAP_VOLATIL' : 'IN_TAP_STATIC',
                    id,
                    length,
                    dataType,
                    meta,
                    value: initialValue
                };
                result.push(inTapVariable);
            }
            else {
                // if (isModbusTargetConfig){
                //     const modbusVariableConfig: ModbusVariableConfig = {
                //         domain: 'TARGET',
                //         modbusAddress: {
                //         },
                //         id,
                //         length,
                //         dataType,
                //         name,
                //         unit
                //     };
                //     result.push(variableConfig);
                // }
                // else {
                const variableConfig = {
                    domain: 'TARGET',
                    address: '0x' + xmlVariable.value('Address', 'number').toString(16),
                    id,
                    length,
                    dataType,
                    meta
                };
                result.push(variableConfig);
                // }
            }
        }
        return result;
    }
}
//# sourceMappingURL=data:application/json;base64, 