import { LasalRuntimeSigElement, SigPolymer } from '../../sigmatek/sig-element/sig-element.js';
import { DA_DataManager } from '../sig-control-da-datamanager/sig-control-da-datamanager.js';

import "../sig-control-listview-ag/sig-control-listview-ag.js";
import "../sig-control-listview-ag/sig-control-listview-ag-css.js";
import "../sig-control-titlebar/sig-control-titlebar.js";
import "../sig-control-titlebar/sig-control-titlebar-css.js";

export class LasalRuntimeSigControlDACursordata extends LasalRuntimeSigElement {

    /***************************************************************************************************************************
     * Defines the custom tag name. Must match the dom module id
     ***************************************************************************************************************************/
    static get is() {
        return 'sig-control-da-cursordata';
    }

    /***************************************************************************************************************************
     * When the element is loaded, importMeta() assigns reference to the path from 
     * which an element was imported to its importPath property. 
     * Relative URLs in styles are automatically re-written to be relative to the importPath property. 
     * You can use [[importPath]] in your component to load url resources
     ***************************************************************************************************************************/
    static get importMeta() { return import.meta; }

    /***************************************************************************************************************************
     * Return the component style and template as a template literal
     ***************************************************************************************************************************/
    static get template() {
        return SigPolymer.html`

        <style include="sig-element-css sig-control-listview-ag-css sig-control-titlebar-css">
            :host {
                /* Basic styling of the component */
                color: var(--theme-sig-element-color, inherit);
                background-color: var(--theme-sig-control-da-cursordata-background-color, transparent);

                border-width: var(--theme-sig-control-da-cursordata-border-width, inherit);
                border-color: var(--theme-sig-control-da-cursordata-border-color, inherit);
                border-style: var(--theme-sig-control-da-cursordata-border-style, none);
                border-radius: var(--theme-sig-control-da-cursordata-border-radius, 0);

                /* Basic box model settings */
                display: block;
                position: absolute;
            }

            :host * {
                /* Reset margin and padding for child elements and turn off text selection */
                @apply --notextselect;
                margin: 0;
                padding: 0;
            }

            .clearfix:after {
                /* Import the global clearfix css mixin */
                @apply --clearfix;
            }

            .sig-control-cursordata {
                /* This div should be relative for use in designer */
                position: relative;
                width: 100%;
                height: 100%;
                /* inherit text-decoration through all levels to support underlined fonts */
                text-decoration: inherit;
            }

            #grid {
                position:unset;
                top:0;
                left:0;
                height:100%;
                width:100%;
            }

            .container {
                display: flex;
                flex-direction: column;
                height: 100%;
                min-height: 100%;
                overflow:hidden;
            }

            .fillheight {
                flex: 1;
            }

            :host sig-control-titlebar {
                position: unset;
                width:100%;
                height: var(--theme-sig-element-height, 26px); 
            }

            :host([hidetitle]) #titlebar {
                display: none !important;
            }  
        </style>
        <div class="sig-control-cursordata clearfix">
            <div class="container">
                <div>
                    <sig-control-titlebar id="titlebar" value=[[titletext]]></sig-control-titlebar>
                </div>
                <div class="fillheight">        
                    <sig-control-listview-ag id="grid"></sig-control-listview-ag>
                </div>
            </div>
        </div>
        `;
    }

    static get properties() {
        return {
            hidetitle: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            widthchannelname: {
                type: String,
                value: '100px',
            },
            widthunit: {
                type: String,
                value: '50px'
            },
            widthvertical1: {
                type: String,
                value: '100px'
            },
            widthvertical2: {
                type: String,
                value: '100px'
            },
            widthdeltavertical: {
                type: String,
                value: '100px'
            },
            widthhorizontal1: {
                type: String,
                value: '100px'
            },
            widthhorizontal2: {
                type: String,
                value: '100px'
            },
            widthdeltahorizontal: {
                type: String,
                value: '100px'
            },
            widthmin: {
                type: String,
                value: '50px'
            },
            widthmax: {
                type: String,
                value: '50px'
            },
            widthdeltaminmax: {
                type: String,
                value: '100px'
            },
            rowheight: {
                type: String,
                value: '30px'
            },
            timetext: {
                type: String,
                value: '',
                observer: 'updateTimeText'
            }
        };
    }

    /***************************************************************************************************************************
     * Called when the element has been created,
     * but before property values are set and local DOM is initialized.
     ***************************************************************************************************************************/
    constructor() {
        super();
        //only do if not in designmode
        if (!this.isdesignmode) {
            //  Create shortcuts to the common apis makes the code more readable
            if (window.sigApi) {
                this.propApi = window.sigApi.properties;
                this.vmApi = window.sigApi.vm;
                this.dpApi = window.sigApi.datapointManager;
                this.constApi = window.sigApi.SIG_CONST;
                this.evtMediaApi = window.sigApi.eventMediator;
                this.evtApi = window.sigApi.events;
                this.unitApi = window.sigApi.unitManager;
            } else {
                this._log('constructor(): API not ready!', 'ERROR');
            }

            //register for incoming events
            this._registerEvents();

            //add header texts as required property
            this.sigAddRequiredProperty('graphinstanceid');
            this.sigAddRequiredProperty('rowheight');
            this.sigAddRequiredProperty('widthchannelname');
            this.sigAddRequiredProperty('widthunit');
            this.sigAddRequiredProperty('widthvertical1');
            this.sigAddRequiredProperty('widthvertical2');
            this.sigAddRequiredProperty('widthdeltavertical');
            this.sigAddRequiredProperty('widthhorizontal1');
            this.sigAddRequiredProperty('widthhorizontal2');
            this.sigAddRequiredProperty('widthdeltahorizontal');
            this.sigAddRequiredProperty('widthmin');
            this.sigAddRequiredProperty('widthmax');
            this.sigAddRequiredProperty('widthdeltaminmax');
            this.sigAddRequiredProperty('activeonly');
            this.sigAddRequiredProperty('timetext');

            //request instance of datamanager
            this.DA_DataManager = DA_DataManager.requestInstance();
        }
    }

    /**
     * register for incoming events
     */
    _registerEvents() {
        //*******************************************************************************************************
        //** cursor data changed so update values in list
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_UPDATE_CURSOR_VALUES', (e) => {
            //only neccessary to update cursor values if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if ment for us
                    if (e.detail.graphInstID === this.graphinstanceid) {
                        //get data
                        this.cursorInfos = e.detail.cursorInfos;
                        //update row data
                        this.updateCursor();
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** unit of channel changed so check if we need to update list
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_UNIT_CHANGED', (e) => {
            //only neccessary to update unit if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if datamanager was initialized
                    if (this.DA_DataManager !== undefined) {
                        //get visuchannels
                        const visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
                        if ((visuChls !== undefined) && (visuChls.size > 0)) {
                            for (let [visuChlID, channel] of visuChls) {
                                //check if channel is displayed in list and if unit column is shown
                                if (((channel.channelActive.value === 1) || (this.activeonly !== true)) && (parseInt(this.widthunit) > 0)) {
                                    if (channel.chlReference !== undefined) {
                                        //check if it is about this channel
                                        if ((channel.chlReference.stationNumber === e.detail.stationNumber) && (channel.chlReference.chlID === e.detail.chlID)) {
                                            //update unit
                                            this.updateUnit(e.detail.stationNumber, e.detail.chlID, visuChlID);
                                        }
                                    }
                                    else {
                                        this._log('_registerEvents(): invalid channel reference (unit change)', 'ERROR');
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** new channel logged in so update configuration
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_NEW_CHANNEL_LOGGED_IN', (e) => {
            //only neccessary to update row data if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if channel is active and ment for graph instance id
                    if (((e.detail.channelActive === 1) || (this.activeonly !== true)) && (this.graphinstanceid === e.detail.instID)) {
                        //update config
                        this.updateConfig();
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** update color of row
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_SELECTED_COLOR_CHANGED', (e) => {
            //only neccessary to update row if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if datamanager was initialized
                    if (this.DA_DataManager !== undefined) {
                        //get visuchannels
                        const visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
                        if ((visuChls !== undefined) && (visuChls.size > 0)) {
                            //get channel
                            const channel = visuChls.get(e.detail.chlID);
                            if (channel !== undefined) {
                                //check if channel is active and ment for graph instance id
                                if (((channel.channelActive.value === 1) || (this.activeonly !== true)) && (this.graphinstanceid === e.detail.instID)) {
                                    //flash row to restyle it
                                    this.updateRow(e.detail.chlID);
                                }
                            }
                        }
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** channel active changed
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_CHANNEL_ACTIVE_CHANGED', (e) => {
            //only neccessary to add or delete row if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if ment for graph
                    if (e.detail.instID === this.graphinstanceid) {
                        //check if only active channels are displayed
                        if (this.activeonly === true) {
                            //set new row data
                            this.updateConfig();
                        }
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** channel name changed
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_CHANNEL_NAME_CHANGED', (e) => {
            //only neccessary to add or delete row if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if datamanager was initialized
                    if (this.DA_DataManager !== undefined) {
                        //get visuchannels
                        const visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
                        if ((visuChls !== undefined) && (visuChls.size > 0)) {
                            for (let [visuChlID, channel] of visuChls) {
                                //check if channel is displayed in list and if unit column is shown
                                if (((channel.channelActive.value === 1) || (this.activeonly !== true)) && (parseInt(this.widthunit) > 0)) {
                                    if (channel.chlReference !== undefined) {
                                        //check if it is about this channel
                                        if ((channel.chlReference.stationNumber === e.detail.stationNumber) && (channel.chlReference.chlID === e.detail.chlID)) {
                                            //update unit
                                            this.updateChannelName(e.detail.stationNumber, e.detail.chlID, visuChlID);
                                        }
                                    }
                                    else {
                                        this._log('_registerEvents(): invalid channel reference (unit change)', 'ERROR');
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** buffer data have changed -> update min and max values
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_CHANNEL_BUFFER_CHANGED', (e) => {
            //only neccessary to update unit if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if datamanager was initialized
                    if (this.DA_DataManager !== undefined) {
                        //get visuchannels
                        const visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
                        if ((visuChls !== undefined) && (visuChls.size > 0)) {
                            for (let [visuChlID, channel] of visuChls) {
                                //check if channel is active and ment for graph instance id
                                if ((channel.channelActive.value === 1) || (this.activeonly !== true)) {
                                    //check if the visu channel has reference to real channel
                                    if (channel.chlReference !== undefined) {
                                        //check if it is about this channel
                                        if ((channel.chlReference.stationNumber === e.detail.stationNumber) && (channel.chlReference.chlID === e.detail.chlID)) {
                                            //throttle event otherwise this will happen far too often
                                            if (this.minMaxTimer === undefined) {
                                                this.minMaxTimer = new Map();
                                            }
                                            //check for timer of channel
                                            const timerChannel = this.minMaxTimer.get(visuChlID);
                                            if (timerChannel === undefined) {
                                                this.minMaxTimer.set(visuChlID, this.sigSetTimeout(() => {
                                                    this.updateMinMax(e.detail.stationNumber, e.detail.chlID, visuChlID);
                                                    this.minMaxTimer.delete(visuChlID);
                                                }, 500));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** channel reference changed -> therefore also name changed
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_CHANNEL_REFERENCE_CHANGED', (e) => {
            //only neccessary to update row if grid already configured
            if ((this.$.grid) && (this.gridConfig)) {
                if (e.detail !== undefined) {
                    //check if datamanager was initialized
                    if (this.DA_DataManager !== undefined) {
                        //get visuchannels
                        const visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
                        if ((visuChls !== undefined) && (visuChls.size > 0)) {
                            //get channel
                            const channel = visuChls.get(e.detail.visuChlID);
                            if (channel !== undefined) {
                                //check if channel is active and ment for graph instance id
                                if (((channel.channelActive.value === 1) || (this.activeonly !== true)) && (this.graphinstanceid === e.detail.graphInstID)) {
                                    //update rowdata
                                    this.updateRowData(channel, e.detail.visuChlID);    
                                }
                            }
                        }
                    }
                }
            }
        }, 'jsEvent', window);

        //*******************************************************************************************************
        //** check for change of source -> limits have to be formatted new
        //*******************************************************************************************************
        this.sigAddEventListener('_DA_SERVER_CHANGED', (e) => {
            if (e.detail !== undefined) {
                //check if init
                if ((this.$.grid) && (this.gridConfig)) {
                    //check if datamanager was initialized
                    if (this.DA_DataManager !== undefined) {
                        //get visuchannels
                        const visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
                        if ((visuChls !== undefined) && (visuChls.size > 0)) {
                            for (let [visuChlID, channel] of visuChls) {
                                if (channel.chlReference !== undefined) {
                                    //check if it is about this channel
                                    if ((channel.chlReference.stationNumber === e.detail.stationNumber) && (channel.chlReference.chlID === e.detail.chlID)) {
                                        //check if channel is active
                                        if ((channel.channelActive.value === 1) || (this.activeonly !== true)) {
                                            //update rowdata
                                            this.updateRowData(channel, visuChlID);                                               
                                        }                                  
                                    }
                                }
                                else {
                                    this._log('_registerEvents(): invalid channel reference', 'ERROR');
                                }                                
                            }
                        }
                    }  
                }
            }
        }, 'jsEvent', window); 

        //*******************************************************************************************************
        //** register for language change event
        //*******************************************************************************************************
        if ((this.evtMediaApi !== undefined) && (this.evtApi !== undefined)) {
            this.evtMediaApi.subscribe(this.evtApi.getInternalEvent('LANGUAGE_CHG'), () => {
                //we need a timeout here cause listview is refreshing on it's own and in this case we have a timing problem
                this.sigSetTimeout(() => {
                    //update configuration
                    this.updateConfig();
                }, 100);

            })
        }
        else {
            this._log('_registerEvents(): event apis not ready', 'ERROR');
        }
    }

    /**
     * 
     */
    ready() {
        super.ready();
        this.$.grid.gridReadonly = true;
        //as onRequiredPropertiesReady won't work in designer we use the ready interface to trigger drawing
        if (this.isdesignmode) {
            //init components
            this._init();                
            SigPolymer.afterNextRender(this, () => {
                this._rendered();
            });
        }
    }

    /**
     * render callback
     */
    _rendered() {
        //set info that control was rendered
        this.rendered = true;
        //create style tag to avoid scroll bars
        let style = this.$.grid.shadowRoot.querySelector('#gridstyles');
        let newStyle = false;
        if (style === null) {
            style = document.createElement('style');
            style.id = 'gridstyles';
            newStyle = true;
        }

        // Since the style for the ag grid list is in the shadow DOM of another control, we have to set the styles in that shadow DOM
        style.innerHTML = `  
                .ag-floating-top {
                    overflow-y                          : hidden !important;
                }
        `;

        if (newStyle === true) {
            const container = this.$.grid.shadowRoot.querySelector('#container');
            this.$.grid.shadowRoot.insertBefore(style, container);
        }        
    }

    /**
     * render callback error
     */
    _renderCBError() {
        //error occured -> try again
        this._addRenderCB();
        this._log("_renderCBError(): error render callback", "ERROR");
    }

    /**
     * helper method to do not need to code this multiple times
     */
    _addRenderCB() {
        //check if vm api ready
        if (this.vmApi !== undefined) {
            //if properties are ready add rendercallback
            this.vmApi.addRenderCallback(this, () => {
                this._rendered();
            }, () => {
                this._renderCBError();
            });
        }
        else {
            this._log('_addRenderCB(): vm api not ready', 'ERROR');
        }
    }

    /**
     * gets called if required properties are ready
     */
    sigOnRequiredPropertiesReady() {
        //call base
        super.sigOnRequiredPropertiesReady();
        //init components
        this._init();           
        //request render callback
        this._addRenderCB();
    }

    /**
     * Initializes the component.
     * Do all the one time setup of the component
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlDACursordata
     */
    _init() {
        if (this.$.grid.gridInitDone) this.$.grid.destroy();
        this._getGridConfig().then((gridConfig) => {
            //save grid config
            this.gridConfig = gridConfig;
            for (const property in gridConfig.settings) {
                if (Object.hasOwnProperty.call(gridConfig.settings, property)) {
                    this.$.grid[property] = gridConfig.settings[property];
                }
            }
            this.$.grid.gridOptions = gridConfig.options;
            this.$.grid.init();
        });
    }

    /**
     * method gets called if grid was initialized
     */
    onGridReady() {
        //check if config needs to be updated
        if (this.reInit) {
            this.reInit = false;
            this.updateConfig();
        }
        else {
            //update cursors
            this.updateCursor();
        }
    }

    /**
     * gets called if grid config should be updated
     */
    updateConfig() {
        //check if grid has been initialized already
        if (this.$.grid.gridInitDone) {
            this._init();
        }
        else {
            this.reInit = true;
        }
    }   

    /**
     * Returns all defined configurations.
     * @returns {Object} An settings object for listview-ag.
     * @memberof LasalRuntimeSigControlDACursordata
     */
    async _getGridConfig() {
        let visuChls;
        //check if da manager is available
        if (this.DA_DataManager !== undefined) {
            //get visu channels
            visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
        }
        //generate column data
        try {
            this.columnData = await this._getColumnConfig();
            return {
                settings: {
                    gridRenderMode: 'native',
                    gridRowModelType: 'clientSide',
                    gridRowHeight: parseInt(this.rowheight),
                    gridColDefaultWidth: 100,
                    gridVirtualizationDisabled: false,
                },
                options: {
                    columnDefs: this.columnData,
                    rowData: await this.getRowData(this.columnData, visuChls),
                    pinnedTopRowData: this._getTimeRow(this.columnData),             
                    getRowStyle: (params) => {
                        //only overwrite styles if not in designer
                        if (!this.isdesignmode) {
                            if (visuChls !== undefined) {
                                if (params.data !== undefined) {
                                    return { color: this._getChannelColor(visuChls.get(params.data.visuChlID)) };
                                }
                            }
                        }
                    },
                    asyncTransactionWaitMillis: 300,
                    getRowNodeId: (params) => params.visuChlID !== undefined ? params.visuChlID : -1,
                }
            }
        }
        catch (error) {
            this._log('_getGridConfig(): get grid configuration failed -> ' + error, 'ERROR');
        }
    }

    /**
     * method is used to get the color of the channel
     * @param {*} channel - channel to get the color of
     * @returns 
     */
    _getChannelColor(channel) {
        if (channel !== undefined) {
            //get channel color
            if (channel.selectedColor.value === undefined) {
                //take default color
                return channel.defaultColor;
            }
            else {
                return this._makeColorString(channel.selectedColor.value);
            }
        }
        else {
            this._log('_getChannelColor(): invalid channel');
        }
    }

    /**
     * method is used to convert value of colorpicker to string
     * @param {*} value - value which should be converted
     * @returns 
     */
    _makeColorString(value) {
        let valueString = value.toString(16);
        let colorString = '#' + valueString.padStart(8, '0');;
        return colorString;
    }

    /**
     * @returns {Array} An array of columns
     * @memberof LasalRuntimeSigControlDACursordata
     */
    async _getColumnConfig() {
        //in design mode we make dummy columns
        if (!this.isdesignmode) {
            try {
                return await this.getUserColumnConfig();
            }
            catch (error) {
                this._log('getUserColumnConfig(): get column config failed -> ' + error, 'ERROR');
            }
        }
        else {
            return [
                {
                    headerName: 'Col1',
                    field: 'col1',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthchannelname),
                    hide: (parseInt(this.widthchannelname) === 0)
                },
                {
                    headerName: 'Col2',
                    field: 'col2',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthunit),
                    hide: (parseInt(this.widthunit) === 0)
                },
                {
                    headerName: 'Col3',
                    field: 'col3',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthvertical1),
                    hide: (parseInt(this.widthvertical1) === 0)
                },
                {
                    headerName: 'Col4',
                    field: 'col4',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthvertical2),
                    hide: (parseInt(this.widthvertical2) === 0)
                },
                {
                    headerName: 'Col5',
                    field: 'col5',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthdeltavertical),
                    hide: (parseInt(this.widthdeltavertical) === 0)
                },
                {
                    headerName: 'Col6',
                    field: 'col6',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthhorizontal1),
                    hide: (parseInt(this.widthhorizontal1) === 0)
                },
                {
                    headerName: 'Col7',
                    field: 'col7',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthhorizontal2),
                    hide: (parseInt(this.widthhorizontal2) === 0)
                },
                {
                    headerName: 'Col8',
                    field: 'col8',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthdeltahorizontal),
                    hide: (parseInt(this.widthdeltahorizontal) === 0)
                },
                {
                    headerName: 'Col9',
                    field: 'col9',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthmin),
                    hide: (parseInt(this.widthmin) === 0)
                },
                {
                    headerName: 'Col10',
                    field: 'col10',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthmax),
                    hide: (parseInt(this.widthmax) === 0)
                },
                {
                    headerName: 'Col11',
                    field: 'col11',
                    sortable: false,
                    filter: false,
                    width: parseInt(this.widthdeltaminmax),
                    hide: (parseInt(this.widthdeltaminmax) === 0)
                },
            ]
        }
    }

    /**
     * this method should be overwritten in order to set data for columns
     * @returns {Array} An array of columns
     * @memberof LasalRuntimeSigControlDACursordata
     */
    async getUserColumnConfig() {
        //check if property api is ready
        if (this.propApi !== undefined) {
            try {
                //get branches
                let branches = await this.propApi.getSchemeDataWithProperty(this.id, 'headertexts');
                if (branches !== undefined) {
                    let colConf = [];
                    let column = {
                        headerName: undefined,
                        field: undefined,
                        sortable: false,
                        filter: false,
                        width: undefined,
                        hide: false
                    }
                    //go through branches and set columns
                    for (let i = 0; i < branches.length; i++) {
                        switch (branches[i].compare.value) {
                            //----------------------------------------------------------------------------------------
                            //-- channel name
                            //----------------------------------------------------------------------------------------
                            case 0:
                                column.width = parseInt(this.widthchannelname);
                                column.field = 'channelName';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- unit
                            //----------------------------------------------------------------------------------------
                            case 1:
                                column.width = parseInt(this.widthunit);
                                column.field = 'unit';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- vertical 1
                            //----------------------------------------------------------------------------------------
                            case 2:
                                column.width = parseInt(this.widthvertical1);
                                column.field = 'vertical1';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- vertical 2
                            //----------------------------------------------------------------------------------------
                            case 3:
                                column.width = parseInt(this.widthvertical2);
                                column.field = 'vertical2';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- delta vertical
                            //----------------------------------------------------------------------------------------
                            case 4:
                                column.width = parseInt(this.widthdeltavertical);
                                column.field = 'deltaVertical';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- horizontal 1
                            //----------------------------------------------------------------------------------------
                            case 5:
                                column.width = parseInt(this.widthhorizontal1);
                                column.field = 'horizontal1';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- horizontal 2
                            //----------------------------------------------------------------------------------------
                            case 6:
                                column.width = parseInt(this.widthhorizontal2);
                                column.field = 'horizontal2';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- delta horizontal
                            //----------------------------------------------------------------------------------------
                            case 7:
                                column.width = parseInt(this.widthdeltahorizontal);
                                column.field = 'deltaHorizontal';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- min
                            //----------------------------------------------------------------------------------------
                            case 8:
                                column.width = parseInt(this.widthmin);
                                column.field = 'min';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- max
                            //----------------------------------------------------------------------------------------
                            case 9:
                                column.width = parseInt(this.widthmax);
                                column.field = 'max';
                                break;
                            //----------------------------------------------------------------------------------------
                            //-- delta min/max
                            //----------------------------------------------------------------------------------------
                            case 10:
                                column.width = parseInt(this.widthdeltaminmax);
                                column.field = 'deltaMinMax';
                                break;
                        }
                        if (column.width === 0) {
                            //hide column
                            column.hide = true;
                        }
                        else {
                            column.hide = false;
                        }
                        column.headerName = branches[i].value;
                        //add column
                        colConf.push(Object.assign(new Object(), column));
                    }
                    //return column configuration
                    return colConf;
                }
                else {
                    this._log('getUserColumnConfig(): get scheme branches failed', 'ERROR');
                }
            }
            catch (error) {
                this._log('getUserColumnConfig(): get scheme branches failed -> ' + error, 'ERROR');
            }
        }
        else {
            this._log('getUserColumnConfig(): invalid property api', 'ERROR');
        }
    }

    /**
     * Get row data -> must be overwritten in order to set row data
     * @param {Array} cols Column definitions
     * @param {map} visuChls a map object of all visu channels
     * @memberof LasalRuntimeSigControlDACursordata 
     */
    async getRowData(cols, visuChls) {
        if (!this.isdesignmode) {
            //go through column definition and set data
            if ((cols !== undefined) && (visuChls !== undefined)) {
                //check if datapoint manager api ready
                if (this.dpApi !== undefined) {
                    if (visuChls.size > 0) {
                        let rows = [];
                        let row = {};
                        for (let [visuChlID, channel] of visuChls) {
                            //check if channel should be displayed
                            if ((channel.channelActive.value === 1) || (this.activeonly !== true)) {
                                //reset row
                                row = {};
                                //get single row data
                                row = await this.getSingleRowData(channel, visuChlID, cols, row);
                                if (row !== undefined) {
                                    rows.push(row);
                                }
                            }
                        }
                        return rows;
                    }
                    else {
                        this._log('getRowData(): api not ready', 'ERROR');
                    }
                }
            }
            else {
                //do not set error, cause possible that visu channels are not logged in already -> row data get set at login then
                // this._log('getRowData(): invalid inputs', 'ERROR');
            }
        }
        else {
            //simply return empty row so column lines are displayed
            return [undefined];
        }
    }

    /**
     * method is used to get the channel data used for displaying in row
     * @param {*} channel - visu channel data
     * @param {*} visuChlID - id of the visu channel
     * @param {*} cols - columns defined in list
     * @param {*} row - row object to fill with channel data
     */
    async getSingleRowData(channel, visuChlID, cols, row) {
        if ((channel !== undefined) && (visuChlID !== undefined) && (cols !== undefined) && (row !== undefined)) {
            //get real to be able to get unit text and so on
            if (channel.chlReference !== undefined) {
                //get real channel
                const realChl = this.DA_DataManager.getChannelByID(channel.chlReference.stationNumber, channel.chlReference.chlID);
                if (realChl !== undefined) {
                    //get datapoint of recorded server
                    const dp = this.dpApi.getDatapoint(realChl.srcVarID);
                    if (dp !== null) {
                        const isFloatingPoint = dp.isFloatingPoint();
                        let actCursorValues;
                        //get cursorvalues if available
                        if (this.cursorInfos !== undefined) {
                            actCursorValues = this.cursorInfos.cursorValues.get(visuChlID);
                        }
                        //get min and max value of channel
                        let minValue, maxValue;
                        //get minimum and maximum value and average
                        for (let i = 0; i < realChl.noOfEntries; i++) {
                            //only evaluate if not invalid value
                            if (realChl.buffer[i] !== realChl.invalidValue) {
                                if ((realChl.buffer[i] < minValue) || (minValue === undefined)) {
                                    minValue = realChl.buffer[i];
                                }
                                if ((realChl.buffer[i] > maxValue) || (maxValue === undefined)) {
                                    maxValue = realChl.buffer[i];
                                }                                                    
                            }
                        }
                        //set visu channel id
                        row.visuChlID = visuChlID;
                        let unitInfo;
                        //go through columns and set data
                        for (let i = 0; i < cols.length; i++) {
                            switch (cols[i].field) {
                                //-------------------------------------------------------------
                                //-- channel name
                                //-------------------------------------------------------------
                                case 'channelName':
                                    //get channel name
                                    try {
                                        //get id of channel name datapoint
                                        const result = await this.dpApi.getIdFromLasalId(realChl.chlNameLasalID, channel.chlReference.stationNumber);
                                        if ((result !== undefined) && (result[0] !== undefined)) {
                                            const varID = result[0];
                                            //get data point
                                            const datapoint = this.dpApi.getDatapoint(varID);
                                            if (datapoint !== null) {
                                                let channelName = await datapoint.getValue();
                                                if (channelName === '') {
                                                    //if no channelname configured, we take the var text 1 of the source
                                                    channelName = await this.dpApi.getDatapointText(realChl.srcVarID, 'text1');
                                                }                                                                         
                                                //set channelname
                                                row.channelName = channelName;
                                            }
                                            else {
                                                this._log('getRowData(): get datapoint failed', 'ERROR');
                                            }
                                        }
                                        else {
                                            this._log('getRowData(): get varid failed', 'ERROR');
                                        }
                                    }
                                    catch (error) {
                                        this._log('getRowData(): get channel name lasal id failed -> ' + error, 'ERROR');
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- unit text
                                //-------------------------------------------------------------
                                case 'unit':
                                    //get unit property
                                    unitInfo = dp.getProperties().unit;
                                    if (unitInfo !== undefined) {
                                        row.unit = await this._getUnitText(unitInfo);
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- vertical 1
                                //-------------------------------------------------------------
                                case 'vertical1':
                                    //check if data available
                                    if (actCursorValues !== undefined) {
                                        row.vertical1 = await this._formatValue(actCursorValues.x1, unitInfo, isFloatingPoint);
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- vertical 2
                                //-------------------------------------------------------------
                                case 'vertical2':
                                    //check if data available
                                    if (actCursorValues !== undefined) {
                                        row.vertical1 = await this._formatValue(actCursorValues.x2, unitInfo, isFloatingPoint);
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- delta vertical
                                //-------------------------------------------------------------
                                case 'deltaVertical':
                                    //check if data available
                                    if (actCursorValues !== undefined) {
                                        if ((row.vertical1 !== undefined) && (row.vertical2 !== undefined)) {
                                            row.deltaVertical = parseFloat(row.vertical1 - row.vertical2).toFixed(2);
                                        }
                                        else {
                                            row.deltaVertical = undefined;
                                        }
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- horizontal 1
                                //-------------------------------------------------------------
                                case 'horizonatl1':
                                    //check if data available
                                    if (actCursorValues !== undefined) {
                                        row.horizontal1 = await this._formatValue(actCursorValues.y1, unitInfo, isFloatingPoint);
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- horizontal 2
                                //-------------------------------------------------------------
                                case 'horizontal2':
                                    //check if data available
                                    if (actCursorValues !== undefined) {
                                        row.horizontal2 = await this._formatValue(actCursorValues.y2, unitInfo, isFloatingPoint);
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- delta horizontal
                                //-------------------------------------------------------------
                                case 'deltaHorizontal':
                                    //check if data available
                                    if (actCursorValues !== undefined) {
                                        if ((row.horizontal1 !== undefined) && (row.horizontal2 !== undefined)) {
                                            row.deltaHorizontal = parseFloat(row.horizontal1 - row.horizontal2).toFixed(2);
                                        }
                                        else {
                                            row.deltaHorizontal = undefined;
                                        }
                                    }
                                    break;

                                //-------------------------------------------------------------
                                //-- min
                                //-------------------------------------------------------------
                                case 'min':
                                    row.min = await this._formatValue(minValue, unitInfo, isFloatingPoint);
                                    break;

                                //-------------------------------------------------------------
                                //-- max
                                //-------------------------------------------------------------
                                case 'max':
                                    row.max = await this._formatValue(maxValue, unitInfo, isFloatingPoint);
                                    break;

                                //-------------------------------------------------------------
                                //-- delta min/max
                                //-------------------------------------------------------------
                                case 'deltaMinMax':
                                    if ((row.max !== undefined) && (row.min !== undefined)) {
                                        row.deltaMinMax = parseFloat(row.max - row.min).toFixed(2);
                                    }
                                    else {
                                        row.deltaMinMax = undefined;
                                    }
                                    break;
                            }
                        }
                        //return row
                        return row;
                    }
                    else {
                        this._log('getSingleRowData(): get datapoint failed', 'ERROR');
                    }

                }
                else {
                    this._log('getSingleRowData(): get real channel failed', 'ERROR');
                }
            }
            else {
                this._log('getSingleRowData(): invalid channel reference', 'ERROR');
            }
        }
        else {
            this._log('getSingleRowData(): invalid inputs', 'ERROR');
        }
    }

    /**
     * method is used to get the data for the time row
     * @param {*} cols - column definition
     */
    _getTimeRow(cols) {
        //go through column definition and set data
        if (cols !== undefined) {
            let row = {};
            //go through columns and set data
            for (let i = 0; i < cols.length; i++) {
                switch (cols[i].field) {
                    //-------------------------------------------------------------
                    //-- channel name
                    //-------------------------------------------------------------
                    case 'channelName':
                        //set channel text
                        row.channelName = this.timetext;
                        break;

                    //-------------------------------------------------------------
                    //-- unit text
                    //-------------------------------------------------------------
                    case 'unit':
                        if (this.cursorInfos !== undefined) {
                            row.unit = this._getXAxisUnitText(this.cursorInfos.cursorTimes.unit);
                        }
                        break;

                    //-------------------------------------------------------------
                    //-- vertical 1
                    //-------------------------------------------------------------
                    case 'vertical1':
                        if (this.cursorInfos !== undefined) {
                            //check if data available
                            if (this.cursorInfos.cursorTimes.x1 !== undefined) {
                                row.vertical1 = this._convertTime(this.cursorInfos.cursorTimes.x1 - this.cursorInfos.cursorTimes.latestTime,
                                    this.cursorInfos.cursorTimes.unit).toFixed(2);
                            }
                            else {
                                row.vertical1 = undefined;
                            }
                        }
                        break;

                    //-------------------------------------------------------------
                    //-- vertical 2
                    //-------------------------------------------------------------
                    case 'vertical2':
                        if (this.cursorInfos !== undefined) {
                            //check if data available
                            if (this.cursorInfos.cursorTimes.x2 !== undefined) {
                                row.vertical2 = this._convertTime(this.cursorInfos.cursorTimes.x2 - this.cursorInfos.cursorTimes.latestTime,
                                    this.cursorInfos.cursorTimes.unit).toFixed(2);
                            }
                            else {
                                row.vertical2 = undefined;
                            }
                        }
                        break;

                    //-------------------------------------------------------------
                    //-- delta vertical
                    //-------------------------------------------------------------
                    case 'deltaVertical':
                        if (this.cursorInfos !== undefined) {
                            //check if data available
                            if ((row.vertical1 !== undefined) && (row.vertical2 !== undefined)) {
                                row.deltaVertical = parseFloat(row.vertical1 - row.vertical2).toFixed(2);
                            }
                            else {
                                row.deltaVertical = undefined;
                            }
                        }
                        //finished if reaching this
                        return [row];
                }
            }
        }
    }

    /**
     * method is used to convert a time in microseconds into used format
     * @param {*} time - time to convert
     * @param {*} unit - unit to convert to
     */
    _convertTime(time, unit) {
        if ((time !== undefined) && (unit !== undefined)) {
            //check for unit
            switch (unit) {

                //*****************************************************************************
                //** time is given in µs
                //*****************************************************************************
                case 0:
                    return time;

                //*****************************************************************************
                //** time is given in ms
                //*****************************************************************************
                case 1:
                    return time / 1000;

                //*****************************************************************************
                //** time is given in sec
                //*****************************************************************************
                case 2:
                    return time / 1000000;

                //*****************************************************************************
                //** time is given in min
                //*****************************************************************************
                case 3:
                    return time / 60000000;

                //*****************************************************************************
                //** time is given in hours
                //*****************************************************************************
                case 4:
                    return time / 360000000;

                //*****************************************************************************
                //** time is given in days
                //*****************************************************************************
                case 5:
                    return time / 86400000000;
            }
        }
        else {
            this._log('_convertTime(): invalid time', 'ERROR');
        }
    }

    /**
     * gets the text for the x axis unit
     * @param {*} unit - unit to get text from
     */
    _getXAxisUnitText(unit) {
        if (unit !== undefined) {
            switch (unit) {

                //*****************************************************************************
                //** time is given in µs
                //*****************************************************************************
                case 0:
                    return 'µs';

                //*****************************************************************************
                //** time is given in ms
                //*****************************************************************************
                case 1:
                    return 'ms';

                //*****************************************************************************
                //** time is given in sec
                //*****************************************************************************
                case 2:
                    return 'sec';

                //*****************************************************************************
                //** time is given in min
                //*****************************************************************************
                case 3:
                    return 'min';

                //*****************************************************************************
                //** time is given in hours
                //*****************************************************************************
                case 4:
                    return 'h';

                //*****************************************************************************
                //** time is given in days
                //*****************************************************************************
                case 5:
                    return 'day';
            }
        }
        else {
            this._log('_getXAxisUnitText(): invalid unit', 'ERROR');
        }
    }

    /**
     * row data gets updated if this function is called
     */
    async updateCursor() {
        //check if grid already initialized
        if (this.gridConfig) {
            //check if da manager is available
            if (this.DA_DataManager !== undefined) {
                //check if the grid api is ready
                if ((this.$.grid.gridApi !== undefined) && (this.$.grid.gridApi !== null)) {
                    //check if cursorinfos available
                    if (this.cursorInfos !== undefined) {
                        //get visu channels
                        const visuChls = this.DA_DataManager.getVisuChannels(this.graphinstanceid);
                        if (visuChls !== undefined) {
                            if (this.hidetime !== true) {
                                //get time data for pinned top row
                                let pinnedTopRowData = this.$.grid.gridOptions.pinnedTopRowData[0];
                                //update time values
                                pinnedTopRowData.unit = this._getXAxisUnitText(this.cursorInfos.cursorTimes.unit);
                                //check if data available
                                if (this.cursorInfos.cursorTimes.x1 !== undefined) {
                                    pinnedTopRowData.vertical1 = this._convertTime(this.cursorInfos.cursorTimes.x1 - this.cursorInfos.cursorTimes.latestTime,
                                        this.cursorInfos.cursorTimes.unit).toFixed(2);
                                }
                                else {
                                    pinnedTopRowData.vertical1 = undefined;
                                }
                                //check if data available
                                if (this.cursorInfos.cursorTimes.x2 !== undefined) {
                                    pinnedTopRowData.vertical2 = this._convertTime(this.cursorInfos.cursorTimes.x2 - this.cursorInfos.cursorTimes.latestTime,
                                        this.cursorInfos.cursorTimes.unit).toFixed(2);
                                }
                                else {
                                    pinnedTopRowData.vertical2 = undefined;
                                }
                                //check if data available
                                if ((pinnedTopRowData.vertical1 !== undefined) && (pinnedTopRowData.vertical2 !== undefined)) {
                                    pinnedTopRowData.deltaVertical = parseFloat(pinnedTopRowData.vertical1 - pinnedTopRowData.vertical2).toFixed(2);
                                }
                                else {
                                    pinnedTopRowData.deltaVertical = undefined;
                                }
                                this.$.grid.gridApi.setPinnedTopRowData([pinnedTopRowData]);
                            }
                            let updateItems = [];
                            let rowData;
                            //iterate through nodes
                            for (let i=0;i<this.$.grid.gridOptions.rowData.length;i++) {
                                rowData = this.$.grid.gridOptions.rowData[i];
                                //get visuchannel
                                const channel = visuChls.get(rowData.visuChlID);
                                if (channel !== undefined) {
                                    //get real channel
                                    if (channel.chlReference !== undefined) {
                                        const realChl = this.DA_DataManager.getChannelByID(channel.chlReference.stationNumber, channel.chlReference.chlID);
                                        if (realChl !== undefined) {
                                            //get datapoint
                                            let datapoint = this.dpApi.getDatapoint(realChl.srcVarID);
                                            if (datapoint !== null) {
                                                //now that datapoint is available we can get the unit
                                                const unitInfo = datapoint.getProperties().unit;
                                                //get channel data
                                                const channelData = this.cursorInfos.cursorValues.get(rowData.visuChlID);
                                                if (channelData !== undefined) {
                                                    rowData.vertical1 = await this._formatValue(channelData.x1, unitInfo, datapoint.isFloatingPoint());
                                                    rowData.vertical2 = await this._formatValue(channelData.x2, unitInfo, datapoint.isFloatingPoint());
                                                    if ((rowData.vertical1 !== undefined) && (rowData.vertical2 !== undefined)) {
                                                        rowData.deltaVertical = parseFloat(rowData.vertical1 - rowData.vertical2).toFixed(2);
                                                    }
                                                    else {
                                                        rowData.deltaVertical = undefined;
                                                    }
                                                    rowData.horizontal1 = await this._formatValue(channelData.y1, unitInfo, datapoint.isFloatingPoint());
                                                    rowData.horizontal2 = await this._formatValue(channelData.y2, unitInfo, datapoint.isFloatingPoint());
                                                    if ((rowData.horizontal1 !== undefined) && (rowData.horizontal2 !== undefined)) {
                                                        rowData.deltaHorizontal = parseFloat(rowData.horizontal1 - rowData.horizontal2).toFixed(2);
                                                    }
                                                    else {
                                                        rowData.deltaHorizontal = undefined;
                                                    }
                                                    updateItems.push(rowData);
                                                }
                                            }
                                            else {
                                                this._log('updateCursor(): get datapoint failed', 'ERROR');
                                            }
                                        }
                                    }
                                }                            
                            }
                            //do update
                            this.$.grid.gridApi.applyTransactionAsync({ update: updateItems });
                        }                        
                    }
                }
            }
        }

    }

    /**
     * method is used to format a value by information of unit
     * @param {*} value - value which should be formatted 
     * @param {*} unitInfo - info of unit used to format
     * @param {*} isFloatingPoint - if true value gets evaluated as floating point
     */
    async _formatValue(value, unitInfo, isFloatingPoint) {
        //check for valid value -> as unitinfo is also valid if undefined in case of no unit configured, we don't question that
        if (value !== undefined) {
            //check if value needs to be formatted
            if (unitInfo !== undefined) {
                //check if apis ready for formating values
                if ((this.propApi !== undefined) && (this.constApi !== undefined)) {
                    if (unitInfo.src === this.constApi.PROP_SRC_UNIT) {
                        value = await this.propApi.formatValueWithUnit(unitInfo.value, value, isFloatingPoint, true, 0);
                    }
                    else if (unitInfo.src === this.constApi.PROP_SRC_SCHEME) {
                        const schemeVals = unitInfo.value.split(':');
                        value = await this.propApi.formatValueWithUnitscheme(schemeVals[1], schemeVals[0], value, 0, isFloatingPoint, true, 0, false);
                    }
                    else if (unitInfo.src === this.constApi.PROP_SRC_SWITCH_PROP) {
                        //scheme and unit configured
                        if ((unitInfo.children !== undefined) && (unitInfo.children.length > 0)) {
                            let unit = 0;
                            let unitScheme = 0;
                            for (let i = 0; i < unitInfo.children.length; i++) {
                                //check for unit
                                if (unitInfo.children[i].src === this.constApi.PROP_SRC_UNIT) {
                                    unit = unitInfo.children[i].value;
                                }
                                else if (unitInfo.children[i].src === this.constApi.PROP_SRC_SCHEME) {
                                    unitScheme = unitInfo.children[i].value;
                                }
                            }
                            const schemeVals = unitScheme.split(':');
                            value = await this.propApi.formatValueWithUnitscheme(schemeVals[1], schemeVals[0], value, unit, isFloatingPoint, true, 0, false);
                        }
                        else {
                            this._log('_formatValue(): invalid constellation', 'ERROR');
                        }
                    }
                }
                else {
                    this._log('_formatValue(): api not ready', 'ERROR');
                }
            }
            return parseFloat(value).toFixed(2);
        }
        else {
            //do not set error cause if cursor is not activated we get undefined here
            // this._log('_formatValue(): invalid value', 'ERROR');
        }
    }

    /**
     * method is used to update min and max values of row
     * @param {*} stationNumber - station number of the real channel
     * @param {*} chlID - ID of the real channel
     * @param {*} visuChlID - id of the visuchannel used for identifiyng row
     * @returns 
     */
    async updateMinMax(stationNumber, chlID, visuChlID) {
        //check for valid inputs
        if ((stationNumber !== undefined) && (chlID !== undefined) && (visuChlID !== undefined)) {
            //check if api ready
            if (this.$.grid.gridApi) {
                //check if datapoint api ready
                if (this.dpApi !== undefined) {
                    //get row
                    let rowNode = this.$.grid.gridApi.getRowNode(visuChlID);
                    if (rowNode !== undefined) {
                        //get real channel
                        const realChl = this.DA_DataManager.getChannelByID(stationNumber, chlID);
                        if (realChl !== undefined) {
                            //get unit to format min and max later on
                            //get datapoint
                            let datapoint = this.dpApi.getDatapoint(realChl.srcVarID);
                            if (datapoint !== null) {
                                //now that datapoint is available we can get the unit
                                const unitInfo = datapoint.getProperties().unit;
                                let minValue, maxValue;
                                //get minimum and maximum value and average
                                for (let i = 0; i < realChl.noOfEntries; i++) {
                                    //only evaluate if not invalid value
                                    if (realChl.buffer[i] !== realChl.invalidValue) {
                                        if ((realChl.buffer[i] < minValue) || (minValue === undefined)) {
                                            minValue = realChl.buffer[i];
                                        }
                                        if ((realChl.buffer[i] > maxValue) || (maxValue === undefined)) {
                                            maxValue = realChl.buffer[i];
                                        }
                                    }    
                                }
                                let rowData = rowNode.data;
                                rowData.min = await this._formatValue(minValue, unitInfo, datapoint.isFloatingPoint());
                                rowData.max = await this._formatValue(maxValue, unitInfo, datapoint.isFloatingPoint());
                                if ((rowData.max !== undefined) && (rowData.min !== undefined)) {
                                    rowData.deltaMinMax = parseFloat(rowData.max - rowData.min).toFixed(2);
                                }
                                else {
                                    rowData.deltaMinMax = undefined;
                                }
                                //update
                                this.$.grid.gridApi.applyTransactionAsync({ update: [rowData] });
                                return;
                            }
                            else {
                                this._log('updateMinMax(): failed to get datapoint', 'ERROR');
                            }
                        }
                        else {
                            this._log('updateMinMax(): failed to get real channel', 'ERROR');
                        }

                    }
                    else {
                        this._log('updateMinMax(): row not found', 'ERROR');
                    }
                }
                else {
                    this._log('updateMinMax(): datapoint api not ready', 'ERROR');
                }
            }
        }
        else {
            this._log('updateMinMax(): invalid inputs', 'ERROR');
        }
    }

    /**
     * method is used to update unit of a channel
     * @param {*} stationNumber - station number of the real channel
     * @param {*} chlID - ID of the real channel
     * @param {*} visuChlID - id of the visuchannel used for identifiyng row
     * @returns 
     */
    async updateUnit(stationNumber, chlID, visuChlID) {
        //check for valid inputs
        if ((stationNumber !== undefined) && (chlID !== undefined) && (visuChlID !== undefined)) {
            //check if api ready
            if (this.$.grid.gridApi) {
                //check if datapoint api ready
                if (this.dpApi !== undefined) {
                    //get row data
                    let rowNode = this.$.grid.gridApi.getRowNode(visuChlID);
                    if (rowNode !== undefined) {
                        //get real channel
                        const realChl = this.DA_DataManager.getChannelByID(stationNumber, chlID);
                        if (realChl !== undefined) {
                            //get datapoint
                            const dp = this.dpApi.getDatapoint(realChl.srcVarID);
                            if (dp !== null) {
                                //get unit property
                                const unitInfo = dp.getProperties().unit;
                                if (unitInfo !== undefined) {
                                    let rowData = rowNode.data;
                                    rowData.unit = await this._getUnitText(unitInfo);
                                    //update
                                    this.$.grid.gridApi.applyTransactionAsync({ update: [rowData] });
                                    return;
                                }
                                else {
                                    this._log('updateUnit(): failed to get unit', 'ERROR');
                                }
                            }
                            else {
                                this._log('updateUnit(): failed to get source datapoint', 'ERROR');
                            }
                        }
                        else {
                            this._log('updateUnit(): failed to get real channel', 'ERROR');
                        }
                    }
                    else {
                        this._log('updateUnit(): row not found', 'ERROR');
                    }
                }
                else {
                    this._log('updateUnit(): datapoint api not ready', 'ERROR');
                }
            }
        }
        else {
            this._log('updateUnit(): invalid inputs', 'ERROR');
        }
    }

    /**
     * method is used to update the channel name
     * @param {*} stationNumber - station number of the real channel
     * @param {*} chlID - ID of the real channel
     * @param {*} visuChlID - id of the visuchannel used for identifiyng row
     * @returns 
     */
    async updateChannelName(stationNumber, chlID, visuChlID) {
        //check for valid inputs
        if ((stationNumber !== undefined) && (chlID !== undefined) && (visuChlID !== undefined)) {
            //check if api ready
            if (this.$.grid.gridApi) {
                //check if datapoint api ready
                if (this.dpApi !== undefined) {
                    //get row data
                    let rowNode = this.$.grid.gridApi.getRowNode(visuChlID);
                    if (rowNode !== undefined) {
                        //get real channel
                        const realChl = this.DA_DataManager.getChannelByID(stationNumber, chlID);
                        if (realChl !== undefined) {
                            //get channel name
                            try {
                                //get id of channel name datapoint
                                const result = await this.dpApi.getIdFromLasalId(realChl.chlNameLasalID, stationNumber);
                                if ((result !== undefined) && (result[0] !== undefined)) {
                                    const varID = result[0];
                                    //get data point
                                    const datapoint = this.dpApi.getDatapoint(varID);
                                    if (datapoint !== null) {
                                        let channelName = await datapoint.getValue();
                                        if (channelName === '') {
                                            //if no channelname configured, we take the var text 1 of the source
                                            channelName = await this.dpApi.getDatapointText(realChl.srcVarID, 'text1');
                                        }                                        
                                        let rowData = rowNode.data;
                                        //at least get value which is the name
                                        rowData.channelName = channelName;
                                        //update
                                        this.$.grid.gridApi.applyTransactionAsync({ update: [rowData] });
                                        return;
                                    }
                                    else {
                                        this._log('updateChannelName(): get datapoint failed', 'ERROR');
                                    }
                                }
                                else {
                                    this._log('updateChannelName(): get varid failed', 'ERROR');
                                }
                            }
                            catch (error) {
                                this._log('updateChannelName(): get channel name lasal id failed -> ' + error, 'ERROR');
                            }
                        }
                        else {
                            this._log('updateChannelName(): failed to get real channel', 'ERROR');
                        }
                    }
                    else {
                        this._log('updateChannelName(): row not found', 'ERROR');
                    }
                }
                else {
                    this._log('updateChannelName(): datapoint api not ready', 'ERROR');
                }
            }
        }
        else {
            this._log('updateChannelName(): invalid inputs', 'ERROR');
        }
    }

    /**
     * method is used to flash the given row for updating styles
     * @param {*} visuChlID - id of the visuchannel used for identifiyng row
     * @returns 
     */
    updateRow(visuChlID) {
        //check for valid inputs
        if (visuChlID !== undefined) {
            //check if api ready
            if ((this.$.grid) && (this.gridConfig) && (this.$.grid.gridApi)) {
                //get row data
                let rowNode = this.$.grid.gridApi.getRowNode(visuChlID);
                if (rowNode !== undefined) {
                    let rowData = rowNode.data;
                    //update
                    this.$.grid.gridApi.applyTransactionAsync({ update: [rowData] });
                    return;
                }
                else {
                    this._log('updateRow(): row not found', 'ERROR');
                }
            }
        }
        else {
            this._log('updateRow(): invalid visu channel id', 'ERROR');
        }
    }

    /**
     * method is used to update the rowdata
     * @param {*} visuChlID - id of the visuchannel used for identifiyng row
     * @returns 
     */
    async updateRowData(channel, visuChlID) {
        //check for valid inputs
        if ((channel !== undefined) && (visuChlID !== undefined)) {
            //check if api ready
            if ((this.$.grid) && (this.gridConfig) && (this.$.grid.gridApi)) {
                //get row data
                let rowNode = this.$.grid.gridApi.getRowNode(visuChlID);
                if (rowNode !== undefined) {
                    let rowData = rowNode.data;
                    //fill up channel data
                    rowData = await this.getSingleRowData(channel, visuChlID, this.columnData, rowData);
                    //update
                    this.$.grid.gridApi.applyTransactionAsync({ update: [rowData] });
                    return;
                }
                else {
                    this._log('updateRow(): row not found', 'ERROR');
                }
            }
        }
        else {
            this._log('updateRow(): invalid inputs', 'ERROR');
        }
    }

    /**
     * observer method if time text changes
     */
    updateTimeText() {
        //check if grid already initialized
        if ((this.$.grid) && (this.gridConfig) && (this.$.grid.gridApi)) {
            //get time row
            let rowNode = this.$.grid.gridApi.getRowNode(-1);
            if (rowNode !== undefined) {
                rowNode.data.channelName = this.timetext;
                this.$.grid.gridApi.applyTransactionAsync({ update: [rowNode.data] });
            }
            else {
                this._log('updateTimeText(): row not found', 'ERROR');
            }
        }
    }

     /****************************************************************************************************
      * method is used to get the unit text via a unitproperty
      *
      * @param {*} unitInfo - unit property
      * @return {String} - Unittext
      * @memberof LasalRuntimeSigControlDACursordata
      ****************************************************************************************************/
    async _getUnitText(unitInfo) {
        //check for valid input
        if (unitInfo !== undefined) {
            //check if properties ready to get unit
            if ((this.propApi !== undefined) && (this.unitApi !== undefined) && (this.constApi !== undefined)) {
                let unit;
                if (unitInfo.src === this.constApi.PROP_SRC_UNIT) {
                    unit = this.unitApi.getUnit(unitInfo.value);
                }
                else if (unitInfo.src === this.constApi.PROP_SRC_SCHEME) {
                    try {
                        const schemeVals = unitInfo.value.split(':');
                        unit = await this.propApi.doScheme(schemeVals[1], schemeVals[0], false);                                            
                    }
                    catch (error) {
                        this._log('_getUnitText(): failed to get unit -> ' + error, 'ERROR');
                    }
                }
                else if (unitInfo.src === this.constApi.PROP_SRC_SWITCH_PROP) {
                    //scheme and unit configured
                    if ((unitInfo.children !== undefined) && (unitInfo.children.length > 0)) {
                        let unitScheme;
                        for (let i=0;i<unitInfo.children.length;i++) {
                            //check for unit
                            if (unitInfo.children[i].src === this.constApi.PROP_SRC_UNIT) {
                                unit = this.unitApi.getUnit(unitInfo.children[i].value);
                            }
                            else if (unitInfo.children[i].src === this.constApi.PROP_SRC_SCHEME) {
                                unitScheme = unitInfo.children[i].value;
                            }
                        }
                        if (unitScheme !== undefined) {
                            try {
                                const schemeVals = unitScheme.split(':');
                                const schemeUnit = await this.propApi.doScheme(schemeVals[1], schemeVals[0], false);
                                if (schemeUnit) unit = schemeUnit;                                                     
                            }
                            catch (error) {
                                this._log('_getUnitText(): failed to get unit -> ' + error, 'ERROR');
                            }                                               
                        }                           
                    }
                    else {
                        this._log('_getUnitText(): invalid constellation', 'ERROR');
                    }
                }
                //check if unit was found
                if (unit !== undefined) {
                    //return unit text
                    return unit.getUnitText();
                }
                else {
                    this._log('_getUnitText(): unit not found', 'ERROR');
                }
            }
            else {
                this._log('_getUnitText(): apis not ready', 'ERROR');
            }    
        }
        else {
            this._log('_getUnitText(): invalid input', 'ERROR');
        }
    }

    /***************************************************************************************************************************
     * gets called if control gets disconnected from dom
     ***************************************************************************************************************************/
    disconnectedCallback() {
        super.disconnectedCallback();    
    }

}
customElements.define(LasalRuntimeSigControlDACursordata.is, LasalRuntimeSigControlDACursordata);