"use strict";
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PricingStream = void 0;
const logger_1 = require("../../../logger");
const state_manager_1 = require("../../../state/state-manager");
const state_manager_interface_1 = require("../../../state/state-manager.interface");
const validate_required_1 = require("../../../util/validate-required");
const pricing_stream_error_1 = require("./pricing-stream-error");
const pricing_stream_instrument_1 = require("./pricing-stream-instrument");
const pricing_stream_instrument_interfaces_1 = require("./pricing-stream-instrument.interfaces");
const pricing_stream_interfaces_1 = require("./pricing-stream.interfaces");
const STREAMING_PRICES_REQUEST_PARAMS = 'Pricing.Params';
/** @internal */
class PricingStream extends state_manager_1.AbstractStateManager {
    constructor(session, parameters, api) {
        super();
        this.session = session;
        this.parameters = parameters;
        this.api = api;
        this.pricingStreamEmitter = this;
        this.instrumentStreams = new Map();
        this.nameToResolveCallback = new Map();
        this.openSingleStream = (data, stream) => {
            const resolveHandler = this.nameToResolveCallback.get(stream.name);
            this.nameToResolveCallback.delete(stream.name);
            resolveHandler();
            this.log.debug(`Streaming price for [${stream.name}] has been opened`);
        };
        this.onSingleStreamRefresh = (refresh, stream) => {
            this.pricingStreamEmitter.emit(pricing_stream_interfaces_1.StreamEvent.Refresh, refresh, stream.name, this);
        };
        this.onSingleStreamUpdate = (update, stream) => {
            this.pricingStreamEmitter.emit(pricing_stream_interfaces_1.StreamEvent.Update, update, stream.name, this);
        };
        this.onSingleStreamStatus = (status, stream) => {
            this.pricingStreamEmitter.emit(pricing_stream_interfaces_1.StreamEvent.Status, status, stream.name, this);
        };
        this.onSingleStreamError = (error, stream) => {
            this.pricingStreamEmitter.emit(pricing_stream_interfaces_1.StreamEvent.Error, new pricing_stream_error_1.StreamError(error.message, stream.name), this);
        };
        this.onSingleStreamStateChanged = () => {
            if (this.checkAllPricingStreamClosed()) {
                this.close();
            }
        };
        (0, validate_required_1.validateRequired)({ session, universe: parameters.universe }, ['session', 'universe'], STREAMING_PRICES_REQUEST_PARAMS);
        this.streamOptions = this.getDefaultStreamOptions(parameters, api);
        this.log = logger_1.logger.getLogger('pricing:stream');
    }
    get definition() {
        return this.parameters;
    }
    open(params) {
        if ((params === null || params === void 0 ? void 0 : params.withUpdates) !== undefined) {
            this.streamOptions.streaming = params.withUpdates;
        }
        return super.open();
    }
    async initialize() {
        // to make it possible throw an error if someone tries to open the pricing.stream with not opened session
        await this.session.getOMMStreamConnection(this.api);
        const instruments = Array.from(new Set(this.streamOptions.universe));
        await Promise.all(instruments.map(name => this.openItemStream(name).catch(() => Promise.resolve(void 0))));
        this.pricingStreamEmitter.emit(pricing_stream_interfaces_1.StreamEvent.Complete, this);
        if (this.checkAllPricingStreamClosed() || !this.instrumentStreams.size) {
            this.setState(state_manager_interface_1.State.Closed);
        }
    }
    async cleanUp() {
        await Promise.all([...this.instrumentStreams.values()].map(pricingStream => pricingStream.close()));
    }
    getFieldValue(instrument, field) {
        var _a;
        return (_a = this.getInstrument(instrument)) === null || _a === void 0 ? void 0 : _a.getFieldValue(field);
    }
    getFields(instrument, fields) {
        var _a;
        return (_a = this.getInstrument(instrument)) === null || _a === void 0 ? void 0 : _a.getFields(fields);
    }
    getItemStatus(instrument) {
        var _a;
        return (_a = this.getInstrument(instrument)) === null || _a === void 0 ? void 0 : _a.itemStatus;
    }
    onRefresh(cb) {
        this.pricingStreamEmitter.on(pricing_stream_interfaces_1.StreamEvent.Refresh, cb);
        return this;
    }
    onUpdate(cb) {
        this.pricingStreamEmitter.on(pricing_stream_interfaces_1.StreamEvent.Update, cb);
        return this;
    }
    onStatus(cb) {
        this.pricingStreamEmitter.on(pricing_stream_interfaces_1.StreamEvent.Status, cb);
        return this;
    }
    onComplete(cb) {
        this.pricingStreamEmitter.on(pricing_stream_interfaces_1.StreamEvent.Complete, cb);
        return this;
    }
    onError(cb) {
        this.pricingStreamEmitter.on(pricing_stream_interfaces_1.StreamEvent.Error, cb);
        return this;
    }
    openItemStream(name) {
        return new Promise((resolve, reject) => {
            const _a = this.streamOptions, { universe } = _a, rest = __rest(_a, ["universe"]);
            const instrumentParams = Object.assign({ name }, rest);
            const pricingInstrumentStream = new pricing_stream_instrument_1.PricingInstrumentStreamProvider(this.session, instrumentParams);
            this.addPricingInstrumentListeners(pricingInstrumentStream);
            this.nameToResolveCallback.set(name, () => resolve(void 0));
            this.instrumentStreams.set(name, pricingInstrumentStream);
            pricingInstrumentStream.open().catch(e => reject(e));
        });
    }
    addPricingInstrumentListeners(pricingInstrumentStream) {
        pricingInstrumentStream.once(pricing_stream_instrument_interfaces_1.PricingInstrumentEvent.Refresh, this.openSingleStream);
        pricingInstrumentStream.on(pricing_stream_instrument_interfaces_1.PricingInstrumentEvent.Refresh, this.onSingleStreamRefresh);
        pricingInstrumentStream.on(pricing_stream_instrument_interfaces_1.PricingInstrumentEvent.Update, this.onSingleStreamUpdate);
        pricingInstrumentStream.on(pricing_stream_instrument_interfaces_1.PricingInstrumentEvent.Status, this.onSingleStreamStatus);
        pricingInstrumentStream.on(pricing_stream_instrument_interfaces_1.PricingInstrumentEvent.Error, this.onSingleStreamError);
        pricingInstrumentStream.on(pricing_stream_instrument_interfaces_1.PricingInstrumentEvent.StateChanged, this.onSingleStreamStateChanged);
    }
    checkAllPricingStreamClosed() {
        return (!!this.instrumentStreams.size &&
            [...this.instrumentStreams.values()].every(pricingInstrumentStream => pricingInstrumentStream.state === state_manager_interface_1.State.Closed));
    }
    getInstrument(name) {
        return this.instrumentStreams.get(name);
    }
    getDefaultStreamOptions(parameters, api) {
        return Object.assign(Object.assign({}, parameters), { universe: [].concat(parameters.universe), streaming: true, api, domain: pricing_stream_interfaces_1.MARKET_PRICE_DOMAIN });
    }
}
exports.PricingStream = PricingStream;
//# sourceMappingURL=data:application/json;base64, 