"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var default_variable_monitor_1 = require("./monitor/default-variable-monitor");
var response_error_1 = require("../../client/api/response/response-error");
var TlvBundleConverter_1 = require("../extra-converter/TlvBundleConverter");
var variable_1 = require("./variable");
// import { BundleVariableMonitor } from "./monitor/bundle-variable-monitor";
// import { TLVConverter } from '../../client/impl/converter/tlv-converter';
var logger_1 = require("../../logger");
var logger = logger_1.default('Bundle');
var UnknownVariableError = /** @class */ (function (_super) {
    __extends(UnknownVariableError, _super);
    function UnknownVariableError(variableName) {
        var _this = _super.call(this, "Unknown variable '" + variableName + "'") || this;
        _this.variableName = variableName;
        _this.code = 'UnknownVariable';
        return _this;
    }
    return UnknownVariableError;
}(Error));
exports.UnknownVariableError = UnknownVariableError;
var ReadBundleError = /** @class */ (function (_super) {
    __extends(ReadBundleError, _super);
    function ReadBundleError(bundle, response) {
        var _this = _super.call(this, "Cannot read bundle " + bundle.config.name + ". " + new response_error_1.ResponseError(response)) || this;
        _this.code = 'ReadBundleError';
        return _this;
    }
    ReadBundleError.fromResponse = function (bundle, response) {
        return new ReadBundleError(bundle, response);
    };
    return ReadBundleError;
}(Error));
exports.ReadBundleError = ReadBundleError;
function parseIntSafe(value) {
    try {
        return parseInt(value);
    }
    catch (err) {
        return NaN;
    }
}
var Bundle = /** @class */ (function () {
    // public variables: VariableInteraction<any>[] = []
    function Bundle(config, bundleService, converter) {
        this.config = config;
        this.bundleService = bundleService;
        this.converter = converter;
    }
    Object.defineProperty(Bundle.prototype, "variables", {
        get: function () {
            return this.config.variables;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Bundle.prototype, "identifier", {
        get: function () {
            return this.config.name;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Bundle.prototype, "bundleId", {
        get: function () {
            return this.config.id;
        },
        enumerable: true,
        configurable: true
    });
    Bundle.createFromConfig = function (config, bundleService, variableService) {
        var newConfig = {
            id: config.id,
            name: config.name,
            variables: []
        };
        var bundle = new Bundle(newConfig, bundleService, new TlvBundleConverter_1.TlvBundleConverter(config.variables));
        var variableInteractions = variable_1.VariableConfig.createAllFromConfig(config.variables, variableService, variable_1.defaultVariableMonitorFactory);
        bundle.config.variables = variableInteractions;
        return bundle;
    };
    // extractVariableMonitor(name: string): VariableMonitor<any> {
    //     let stream = this.monitor().values().pipe(
    //         filter((v => name in v)),
    //         map((v: any) => {
    //             return v[name];
    //         })
    //     );
    //     return ObservableMonitor.fromObservable(stream);
    // }
    /**
     * @deprecated
     */
    // public static createFromVariableManager<T>(
    //     identifier: string,
    //     bundleId: number,
    //     bundleService: BundleValueService, // TODO less restrictive
    //     manager?: VariableManager) {
    //     let mapping = manager ? manager.variableConfig : [];
    //     return new Bundle<T>({
    //         id: bundleId,
    //         name: identifier,
    //         variables: mapping
    //     }, bundleService)
    // }
    /**
     * Get variable by id
     *
     * @param id
     */
    Bundle.prototype.variable = function (id) {
        var variable = this.config.variables.find(function (v) { return v.identifier() == id; });
        if (!variable) {
            // let availableVariables = this.config.variables.map(v => v.identifier()).join(', ');
            throw new UnknownVariableError(id); // TODO errors
        }
        return variable;
    };
    Bundle.prototype.read = function () {
        var _this = this;
        return this
            .bundleService
            .getValues(this.bundleId)
            .then(function (response) {
            if (!response.isSuccess()) {
                throw ReadBundleError.fromResponse(_this, response);
            }
            var rawBody = response.rawBody();
            var values = _this.converter.decode(rawBody);
            var _loop_1 = function (variableNameOrId) {
                var variableConfig = _this.config.variables.find(function (v) {
                    if (v instanceof variable_1.VariableConfig) {
                        return v.config.id === parseIntSafe(variableNameOrId) || v.config.name === variableNameOrId;
                    }
                    return false;
                });
                if (variableConfig) {
                    var name_1 = variableConfig.config.name || variableConfig.config.id;
                    // This step is already done by TLVBundleConverter... Maybe it can be removed
                    if (!(variableNameOrId in values)) {
                        var value = values[variableNameOrId];
                        delete values[variableNameOrId];
                        values[name_1] = variableConfig.converter ? variableConfig.converter.decode(value) : value;
                    }
                    logger.debug("Variable with id \"" + variableNameOrId + "\" (name=" + name_1 + ", converter=" + (variableConfig.converter ? 'yes' : 'no') + ") found!");
                    variableConfig.monitor().notifyNewValue(values[name_1]);
                }
                else {
                    // TODO warn ?
                    logger.debug("Variable with id \"" + variableNameOrId + "\" (name=\"" + name + "\") is not registered");
                }
            };
            for (var variableNameOrId in values) {
                _loop_1(variableNameOrId);
            }
            logger.debug("Values: ", values);
            return values;
        });
    };
    Bundle.prototype.monitor = function () {
        var _this = this;
        if (!this._monitor) {
            this._monitor = new default_variable_monitor_1.DefaultVariableMonitor({
                update: function (count) {
                    logger.debug("Request monitor update on " + _this.identifier);
                    return _this.read();
                }
            });
        }
        return this._monitor;
    };
    return Bundle;
}());
exports.Bundle = Bundle;
