import deviceClient from '@iotize/device-client.js';
import impl from '@iotize/device-client.js/client/impl';
import rxjs from 'rxjs';
import operators from 'rxjs/operators';
import common from '@iotize/common';

var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

function commonjsRequire () {
	throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
}

function unwrapExports (x) {
	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}

function createCommonjsModule(fn, module) {
	return module = { exports: {} }, fn(module, module.exports), module.exports;
}

function getCjsExportFromNamespace (n) {
	return n && n['default'] || n;
}

var debug = createCommonjsModule(function (module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

const prefix = '@iotize:device-client.js:datalog';
exports.debug = common.createDebugger(prefix);

});

var debug$1 = unwrapExports(debug);
var debug_1 = debug.debug;

var dataLogger = createCommonjsModule(function (module, exports) {
"use strict";
var __awaiter = (commonjsGlobal && commonjsGlobal.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });





const TAG = 'DataLogger';
/**
 * Experimental data logger class
 *
 * @experimental
 */
class DataLogger {
    constructor(tap, converter = new DataLogPacketConverter(), options) {
        this.tap = tap;
        this.converter = converter;
        this.options = options;
        this.source = rxjs.interval(this.options.period);
    }
    static fromTap(tap, options) {
        let converter = DataLogPacketConverter.createFromManager(tap.bundles, tap.variables);
        return new DataLogger(tap, converter, options);
    }
    dequeue() {
        return __awaiter(this, void 0, void 0, function* () {
            let singlePacketResponse = yield this.tap.service.datalog.dequeueOnePacket();
            singlePacketResponse.successful();
            let singlePacket = singlePacketResponse.body();
            try {
                return this.converter.decode({
                    raw: singlePacketResponse.rawBody(),
                    singlePacket: singlePacket
                });
            }
            catch (err) {
                throw new DataLogger.CannotDecodePacketError(singlePacket, err);
            }
        });
    }
    getPacketCount() {
        return __awaiter(this, void 0, void 0, function* () {
            return (yield this.tap.service.datalog.getPacketCount()).body();
        });
    }
    download() {
        return this.source.pipe(operators.flatMap(() => rxjs.from(this.dequeue()))).pipe(operators.map((datalogPacket, index) => {
            try {
                return {
                    type: 'progress',
                    payload: {
                        index: index,
                        limit: undefined,
                        current: datalogPacket
                    }
                };
            }
            catch (err) {
                return {
                    type: 'error',
                    error: err
                };
            }
        }), operators.share());
    }
}
exports.DataLogger = DataLogger;
(function (DataLogger) {
    class CannotDecodePacketError extends Error {
        constructor(singlePacket, cause) {
            super(`Cannot parse data log packet. Error: ${cause.message}`);
            this.singlePacket = singlePacket;
            this.cause = cause;
        }
    }
    DataLogger.CannotDecodePacketError = CannotDecodePacketError;
})(DataLogger = exports.DataLogger || (exports.DataLogger = {}));
/**
 *
 * @experimental
 */
class RawPacketConverter {
    constructor(tlvConverter = new impl.TLVConverter(), bundleConverter = new deviceClient.TlvBundleConverter(), singlePacketConverter = new deviceClient.SinglePacketConverter()) {
        this.tlvConverter = tlvConverter;
        this.bundleConverter = bundleConverter;
        this.singlePacketConverter = singlePacketConverter;
    }
    encode(data) {
        throw new Error('Method not implemented.');
    }
    decode(data) {
        let tlvTree = this.tlvConverter.decode(data);
        let bundleId = tlvTree.header.id;
        // console.log(tlvTree);
        let variables = tlvTree.children
            ? this.bundleConverter.decode(tlvTree)
            : {};
        return {
            _raw: data,
            bundle: {
                id: bundleId
            },
            rawVariables: variables
        };
    }
}
exports.RawPacketConverter = RawPacketConverter;
/**
 *
 * @experimental
 */
class DataLogPacketConverter {
    constructor(meta, rawPacketConverter = new RawPacketConverter()) {
        this.meta = meta;
        this.rawPacketConverter = rawPacketConverter;
    }
    static createFromManager(bundleManager, variableManager) {
        let meta = [];
        let variableConfig = variableManager.variableConfig;
        for (let bundleId in bundleManager.bundles) {
            let bundle = bundleManager.get(bundleId);
            meta.push({
                id: bundle.bundleId,
                name: bundle.identifier,
                variables: variableConfig
            });
        }
        // debug(TAG, 'Created with meta', meta );
        return new DataLogPacketConverter(meta);
    }
    static createFromMeta(meta, rawPacketConverter = new RawPacketConverter()) {
        return new DataLogPacketConverter(meta, rawPacketConverter);
    }
    encode(type) {
        throw new Error('Method not implemented.');
    }
    decode(data) {
        let singlePacket = data.singlePacket;
        let dataLogPacket = this.rawPacketConverter.decode(singlePacket.payload.data);
        let timeOffset = Date.now() - singlePacket.sendTime * 1000;
        dataLogPacket.bundle.logTime = new Date(singlePacket.payload.logTime * 1000 + timeOffset);
        let packet = populateDataLogPacket(dataLogPacket, this.meta || []);
        return {
            packet: packet,
            rawSinglePacket: data.raw,
            singlePacket: singlePacket
        };
    }
}
exports.DataLogPacketConverter = DataLogPacketConverter;
/**
 *
 * @experimental
 */
function populateDataLogPacket(rawDataLogPacket, meta) {
    // console.log('decodeDataLogPacket', meta)
    let result = rawDataLogPacket;
    result.variables = {};
    let bundleMeta = meta.find(item => item.id == rawDataLogPacket.bundle.id);
    if (bundleMeta) {
        let variableMeta = bundleMeta.variables;
        result.bundle.name = bundleMeta.name;
        let id;
        for (id in rawDataLogPacket.rawVariables) {
            let data = rawDataLogPacket.rawVariables[id];
            const variableConfig = variableMeta.find(v => v.id == parseInt(id));
            if (variableConfig) {
                let key = variableConfig.name || variableConfig.id.toString();
                debug.debug(TAG, 'Converting key', id, key, data, variableConfig);
                result.variables[key] = variableConfig.converter
                    ? variableConfig.converter.decode(data)
                    : data; // Converts Buffer to a value according to variableConfig
            }
            else {
                debug.debug(TAG, 'No converter available', id, data, variableConfig);
                result.variables[id] = data;
            }
        }
    }
    else {
        debug.debug(TAG, `NO BUNDLE META FOR VARIABLE ID "${rawDataLogPacket.bundle.id}". Available:`, meta.map(item => item.id).join(','));
    }
    if (Object.keys(result.variables).length === 0) {
        result.variables = result.rawVariables;
    }
    return result;
}
exports.populateDataLogPacket = populateDataLogPacket;

});

var dataLogger$1 = unwrapExports(dataLogger);
var dataLogger_1 = dataLogger.DataLogger;
var dataLogger_2 = dataLogger.RawPacketConverter;
var dataLogger_3 = dataLogger.DataLogPacketConverter;
var dataLogger_4 = dataLogger.populateDataLogPacket;

var tapExtension = createCommonjsModule(function (module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });


Object.defineProperty(deviceClient.IoTizeDevice.prototype, 'datalogger', {
    get() {
        if (!this._datalogger) {
            this._datalogger = dataLogger.DataLogger.fromTap(this, {
                period: 100 // TODO remove..
            });
        }
        return this._datalogger;
    },
    enumerable: false,
    configurable: true
});
deviceClient.IoTizeDevice.prototype.hasDatalogger = function () {
    return Boolean(this._datalogger);
};

});

var tapExtension$1 = unwrapExports(tapExtension);

var public_api = createCommonjsModule(function (module, exports) {
"use strict";
function __export(m) {
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(dataLogger);


});

var public_api$1 = unwrapExports(public_api);

var iotizeDeviceClient_jsDatalog = createCommonjsModule(function (module, exports) {
"use strict";
/**
 * Generated bundle index. Do not edit.
 */
function __export(m) {
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(public_api);

});

var iotizeDeviceClient_jsDatalog$1 = unwrapExports(iotizeDeviceClient_jsDatalog);

export default iotizeDeviceClient_jsDatalog$1;
//# sourceMappingURL=iotize-device-client.js-datalog.js.map
