"use strict";
/*
 * Copyright 2014-2015 Fabian Tollenaar <fabian@starting-point.nl>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.pipedProviders = pipedProviders;
const lodash_1 = __importDefault(require("lodash"));
const stream_1 = require("stream");
const debug_1 = require("./debug");
class PipedProvider {
}
function pipedProviders(app) {
    function createPipedProvider(providerConfig) {
        const { propertyValues, ...sanitizedApp } = app;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const emitPropertyValue = (name, value) => propertyValues.emitPropertyValue({
            timestamp: Date.now(),
            setter: `provider:${providerConfig.id}`,
            name,
            value
        });
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const onPropertyValues = (name, cb) => propertyValues.onPropertyValues(name, cb);
        const boundEventMethods = app.wrappedEmitter.bindMethodsById(`connection:${providerConfig.id}`);
        const appFacade = {
            emitPropertyValue,
            onPropertyValues,
            ...sanitizedApp,
            ...boundEventMethods,
            toJSON: () => 'appFacade'
        };
        const result = {
            id: providerConfig.id,
            pipeElements: providerConfig.pipeElements.reduce((res, config) => {
                if (typeof config.enabled === 'undefined' || config.enabled) {
                    res.push(createPipeElement({
                        ...config,
                        options: {
                            providerId: providerConfig.id,
                            app: appFacade,
                            ...config.options,
                            emitPropertyValue,
                            onPropertyValues
                        }
                    }));
                }
                return res;
            }, [])
        };
        for (let i = result.pipeElements.length - 2; i >= 0; i--) {
            result.pipeElements[i].pipe(result.pipeElements[i + 1]);
        }
        const deltaSink = new stream_1.Writable({
            objectMode: true,
            write(msg, _encoding, done) {
                app.handleMessage(providerConfig.id, msg);
                done();
            }
        });
        result.pipeElements[result.pipeElements.length - 1].pipe(deltaSink);
        app.emit('pipedProvidersStarted', providerConfig);
        return result;
    }
    function createPipeElement(elementConfig) {
        if (elementConfig.optionMappings) {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            elementConfig.optionMappings.forEach(function (mapping) {
                if (lodash_1.default.get(app, mapping.fromAppProperty)) {
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    ;
                    elementConfig.options[mapping.toOption] = lodash_1.default.get(app, mapping.fromAppProperty);
                }
            });
        }
        const efectiveElementType = elementConfig.type.startsWith('providers/')
            ? elementConfig.type.replace('providers/', '@signalk/streams/')
            : elementConfig.type;
        // eslint-disable-next-line @typescript-eslint/no-require-imports
        const mod = require(efectiveElementType);
        const Ctor = mod.default ?? mod;
        return new Ctor({
            ...elementConfig.options,
            createDebug: debug_1.createDebug
        });
    }
    function startProviders() {
        if (app.config.settings.pipedProviders) {
            const piped = app.config.settings.pipedProviders.reduce((result, config) => {
                try {
                    if (typeof config.enabled === 'undefined' || config.enabled) {
                        result.push(createPipedProvider(config));
                    }
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                }
                catch (e) {
                    app.setProviderError(config.id, e.message);
                    console.error(e);
                }
                return result;
            }, []);
            return piped.filter(function (n) {
                return n !== null && n !== undefined;
            });
        }
        else {
            console.error('No pipedProviders in the settings file');
            return [];
        }
    }
    function stopProvider(id) {
        const idx = app.providers.findIndex((p) => p.id === id);
        if (idx !== -1) {
            app.providers[idx].pipeElements[0].end();
            app.providers.splice(idx, 1);
        }
        app.wrappedEmitter.removeAllListenersById(`connection:${id}`);
    }
    function restartProvider(id) {
        stopProvider(id);
        const providerConfig = app.config.settings.pipedProviders?.find((p) => p.id === id);
        if (providerConfig &&
            (typeof providerConfig.enabled === 'undefined' || providerConfig.enabled)) {
            try {
                app.providers.push(createPipedProvider(providerConfig));
            }
            catch (e) {
                const message = e instanceof Error ? e.message : String(e);
                app.setProviderError(id, message);
                console.error(e);
            }
        }
    }
    return {
        start: startProviders,
        createPipedProvider,
        stopProvider,
        restartProvider
    };
}
//# sourceMappingURL=pipedproviders.js.map