/*
 * SPDX-FileCopyrightText: Bosch Rexroth AG
 *
 * SPDX-License-Identifier: MIT
 */

//API
import { Remote } from '../lib/remote';
import DatalayerSystem from '../lib/datalayersystem';
import IVariant from '../lib/variant';
import IProviderNodeResult from '../lib/providernoderesult';

import VariantTypes from '../lib/varianttypes';
import Result from '../lib/result';
import ProviderNodeCallbacks from '../lib/providernodecallbacks';

//Flatbuffers
import * as flatbuffers from 'flatbuffers';
import { Metadata } from 'ctrlx-datalayer-flatbuffers/dist/comm/datalayer/metadata';
import { AllowedOperations } from 'ctrlx-datalayer-flatbuffers/dist/comm/datalayer/allowed-operations';
import { NodeClass } from 'ctrlx-datalayer-flatbuffers/dist/comm/datalayer/node-class';

async function createProvider() {

    let value = 0;

    //onCreate callback function
    const onCreate = (address: string, args: IVariant, result: IProviderNodeResult) => {
        console.log('onCreate', address, args);
        result.setResult(Result.UNSUPPORTED, null);
    };

    //onRemove callback function
    const onRemove = (address: string, result: IProviderNodeResult) => {
        console.log('onRemove', address);
        result.setResult(Result.UNSUPPORTED, null);
    };

    //onBrowse callback function
    const onBrowse = (address: string, result: IProviderNodeResult) => {
        console.log('onBrowse', address);
        result.setResult(Result.UNSUPPORTED, null);
    };

    //onMetadata callback function
    const onMetadata = (address: string, result: IProviderNodeResult) => {
        console.log('onMetadata', address);

        //Build metadata
        const metaDataBuilder = new flatbuffers.Builder(DatalayerSystem.defaultFlatbuffersInitialSize);

        //Setup allowed operations
        const operationsOffset = AllowedOperations.createAllowedOperations(
            metaDataBuilder, true, true, false, false, true); //Required

        const descriptionOffset = metaDataBuilder.createString('my description'); //Required
        const descriptionUrlOffset = metaDataBuilder.createString('my descriptionUrl'); //Required
        const displayNameOffset = metaDataBuilder.createString('my displayName');
        const unitOffset = metaDataBuilder.createString('my unit');

        //Setup metadata
        Metadata.startMetadata(metaDataBuilder);
        Metadata.addDescription(metaDataBuilder, descriptionOffset);
        Metadata.addDescriptionUrl(metaDataBuilder, descriptionUrlOffset);
        Metadata.addDisplayName(metaDataBuilder, displayNameOffset)
        Metadata.addUnit(metaDataBuilder, unitOffset);
        Metadata.addNodeClass(metaDataBuilder, NodeClass.Variable);
        Metadata.addOperations(metaDataBuilder, operationsOffset);

        const offset = Metadata.endMetadata(metaDataBuilder);
        Metadata.finishMetadataBuffer(metaDataBuilder, offset);

        //Respond the callback
        result.setResult(Result.OK, metaDataBuilder.asUint8Array(), VariantTypes.flatbuffers);
    };

    //onRead callback function
    const onRead = (address: string, args: IVariant, result: IProviderNodeResult) => {
        console.log('onRead', address, args);
        result.setResult(Result.OK, value);
    };

    //onWrite callback function
    const onWrite = (address: string, args: IVariant, result: IProviderNodeResult) => {
        console.log('onWrite', address, args);
        value = args.value;
        result.setResult(Result.OK, value);
    };

    //Create DatalayerSystem and start
    const system = new DatalayerSystem('');
    await system.start(false);

    // Build remote
    const cred = {
        user: 'boschrexroth',
        password: 'boschrexroth',
        ip: '192.168.1.1'
    };
    let remote = Remote.build(cred);

    //Create a Provider
    const provider = await system.createProvider(remote);
    await provider.start();

    //Create callbacks
    const providerNodeCallbacks = new ProviderNodeCallbacks()
        .setOnCreate(onCreate)
        .setOnRemove(onRemove)
        .setOnBrowse(onBrowse)
        .setOnMetadata(onMetadata)
        .setOnRead(onRead)
        .setOnWrite(onWrite)

    //Register the node we want to provide
    await provider.registerNode('samples/nodejs/test', providerNodeCallbacks);

    //We change our value randomly
    let intervalHandle = setInterval(async () => {
        value = Math.random() * 100;
    }, 500);

    //Keep the provider alive for 1 min.
    setTimeout(async () => {
        clearInterval(intervalHandle);
        await system.stop();
    }, 60000);
}

//provide
createProvider();
