//keeps the instance of the datamanager
let dataManagerInstance = undefined;

/**
 * handles the communication and buffers
 */
export class DA_DataManager {

    static requestInstance() {
        if (dataManagerInstance === undefined) {
            if (window.sigApi !== undefined) {
                dataManagerInstance =  new DA_DataManager(window.sigApi);
            } else {
                //check if sig api is ready
                window.addEventListener('SigApiReady', () => {
                    dataManagerInstance = new DA_DataManager(window.sigApi);
                });
            }            
        }
        return dataManagerInstance;
    }

    constructor(api) {
        this.evtApi = undefined;
        this.evtMedApi = undefined;
        this.datapointApi = undefined;
        this.constApi = undefined;
        this._initVars();
        this._initApis(api);
        //register for events
        this._registerEvents(); 
        //login to station
        this._stationLogin();                   
    }

    /**
     * Method is used to init variables and constants
     */
    _initVars() {

        //************************************************************************************************************
        //** user bit mask for manager station
        //************************************************************************************************************
        this.mngStation = 0x2000000000000;

        //************************************************************************************************************
        //** defines for events
        //************************************************************************************************************
        this.majorID = 0x8003;
        Object.freeze(this.majorID);

        this.loginRequest = {
            minorID: 0x01,
            version: 0x01,
            dataOffset: 8
        };
        Object.freeze(this.loginRequest);

        this.loginResponse = {
            minorID: 0x02,
            version: 0x01
        };
        Object.freeze(this.loginResponse);

        this.loginReject = {
            minorID: 0x03,
            version: 0x01
        };
        Object.freeze(this.loginReject);

        this.logoutRequest = {
            minorID: 0x04,
            version: 0x01,
            dataOffset: 8
        }
        Object.freeze(this.logoutRequest); 

        this.dataResponse = {
            minorID: 0x05,
            version: 0x01
        }
        Object.freeze(this.dataResponse);         

        this.reallocRequest = {
            minorID: 0x06,
            version: 0x01
        }
        Object.freeze(this.reallocRequest);

        this.additionalDataResponse = {
            minorID: 0x07,
            version: 0x01
        }
        Object.freeze(this.additionalDataResponse); 

        this.autoset = {
            minorID: 0x08
        }
        Object.freeze(this.autoset); 

        this.newServerRequest = {
            minorID: 0x09,
            version: 0x01,
            dataOffset: 8,
            size: 28
        }
        Object.freeze(this.newServerRequest); 

        this.newServerResponse = {
            minorID: 0x0A,
            version: 0x01
        }
        Object.freeze(this.newServerResponse); 

        this.triggerRaised = {
            minorID: 0x0B,
            version: 0x01
        }
        Object.freeze(this.triggerRaised); 

        this.resetTriggers = {
            minorID: 0x0C,
            version: 0x01
        }
        Object.freeze(this.resetTriggers); 

        this.clearData = {
            minorID: 0x0D,
            version: 0x01
        }
        Object.freeze(this.clearData); 

        this.groupUpdate = {
            minorID: 0x0E,
            version: 0x01
        }
        Object.freeze(this.groupUpdate); 

        this.getPrePostRequest = {
            minorID: 0x0F,
            version: 0x01,
            dataOffset: 8,
            size: 12
        }
        Object.freeze(this.getPrePostRequest);        

        this.getPrePostResponse = {
            minorID: 0x10,
            version: 0x01,
            dataOffset: 8
        }
        Object.freeze(this.getPrePostResponse); 

        this.setPrePost = {
            minorID: 0x11,
            version: 0x01,
            dataOffset: 8,
            size: 24
        }
        Object.freeze(this.setPrePost); 

        this.getThresholdRequest = {
            minorID: 0x12,
            version: 0x01,
            dataOffset: 8,
            size: 16
        }
        Object.freeze(this.getThresholdRequest);   

        this.getThresholdResponse = {
            minorID: 0x13,
            version: 0x01,
            dataOffset: 8
        }
        Object.freeze(this.getThresholdResponse); 

        this.setTriggerThreshold = {
            minorID: 0x14,
            version: 0x01,
            dataOffset: 8,
            size: 17
        }
        Object.freeze(this.setTriggerThreshold); 

        this.invalidValueUpdate = {
            minorID: 0x15,
            version: 0x01
        }
        Object.freeze(this.invalidValueUpdate); 

        this.exportChannelNameRequest = {
            minorID: 0x19,
            version: 0x01,
        };
        Object.freeze(this.exportChannelNameRequest); 

        this.exportChannelNameResponse = {
            minorID: 0x20,
            version: 0x01,
        };
        Object.freeze(this.exportChannelNameResponse); 

        //define size of header
        this.sigHeader = 16;
        Object.freeze(this.sigHeader);           

        //************************************************************************************************************

        //define datatypes
        this.dataTypes = {
            void: 0,
            bool: 1,
            int8: 2,
            int16: 3,
            int32: 4,
            int64: 5,
            uint8: 6,
            uint16: 7,
            uint32: 8,
            uint64: 9,
            float32: 10,
            float64: 11
        }
        Object.freeze(this.dataTypes);

        //define reference datatypes
        this.referenceDataTypes = {
            DINT: 0,
            UDINT: 1,
            REAL: 2
        }
        Object.freeze(this.referenceDataTypes);
        
        this.registerData;

        //array for management stations
        this.managementStations = [];
    }

    /**
     * Method is used to initialize needed apis
     * @param {*} api - api interface
     */  
     _initApis(api) {
        if ((api !== null) && (api !== undefined)) {
            if (api.eventMediator !== undefined) {
                this.evtMedApi = api.eventMediator;
            }
            if (api.events !== undefined) {
                this.evtApi = api.events;
            }
            if (api.properties !== undefined) {
                this.propApi = api.properties;
            }
            if (api.datapointManager !== undefined) {
                this.datapointApi = api.datapointManager;
            }
            if (api.SIG_CONST !== undefined) {
                this.constApi = api.SIG_CONST;
            }
            if (api.accessSequence !== undefined) {
                this.accessApi = api.accessSequence;
            }
            if (api.stationManager !== undefined) {
                this.stationsApi = api.stationManager;
            }            
        }
    }

    /**
     * Register for incoming events
     */      
    _registerEvents() {
        if ((this.evtMedApi !== undefined) && (this.evtApi !== undefined) && (this.accessApi !== undefined) && (this.stationsApi !== undefined) && (this.constApi !== undefined)) {                                         

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for login response
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.loginResponse.minorID, (ma, mi, dv) => {
                //get login response data
                this._getLoginRspData(dv);
                if (this.rejectTimeout !== undefined) {
                    clearTimeout(this.rejectTimeout);
                }
            },1);

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for login reject
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.loginReject.minorID, (ma, mi, dv) => {
                if (this.rejectTimeout === undefined) {
                    //get stationnumber for retry
                    const rejectStation = dv.getUint16(8, true);
                    //login rejected due to station not ready -> try later again
                    this.rejectTimeout = setTimeout(() => {
                        this._sendLoginRequest(rejectStation);
                        this.rejectTimeout = undefined;
                    }, 300);                    
                }
            },1); 

            this.evtMedApi.subscribe(this.evtApi.getInternalEvent('STATION_STATE_CHG'), (ma, mi, station) => {
                //check if managmentstations already exists
                if (this.managementStations !== undefined) {
                    //check if station is a management station and if it is running
                    if ((this.managementStations.includes(station.station)) && (station.status === this.constApi.STAT_STATION_RUNNING)) {
                        this._sendLoginRequest(station.station); 
                    }                    
                }                                                                  
            });             

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for data
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.dataResponse.minorID, (ma, mi, dv) => {
                //handle incoming data
                this._handleData(dv);                
            },1);  
            
            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for realloc request
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.reallocRequest.minorID, (ma, mi, dv) => {
                //realloc buffer
                this._reallocBuffer(dv);                
            },1);            

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for additional data
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.additionalDataResponse.minorID, (ma, mi, dv) => {
                //handle incoming data
                this._handleAdditionalData(dv);                
            },1);  

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for new server info
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.newServerResponse.minorID, (ma, mi, dv) => {
                //set new server
                this._setNewServer(dv);                
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for trigger raised event
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.triggerRaised.minorID, (ma, mi, dv) => {
                //save trigger infos
                this._triggerRaised(dv);
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for reset triggers
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.resetTriggers.minorID, (ma, mi, dv) => {
                //take start info to reset triggers
                this._resetTriggersReceived(dv);
            },1);             

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for clear data
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.clearData.minorID, (ma, mi, dv) => {
                //clear data
                this._clearData(dv);
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for update of group info
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.groupUpdate.minorID, (ma, mi, dv) => {
                //update group of channel
                this._groupUpdate(dv);
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for pre postsample response
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.getPrePostResponse.minorID, (ma, mi, dv) => {
                //fire event with pre and postsamples to update graphs
                this._updatePrePost(dv);
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for threshold response
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.getThresholdResponse.minorID, (ma, mi, dv) => {
                //fire event with threshold to update graphs
                this._updateThreshold(dv);
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for invalid value update
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.invalidValueUpdate.minorID, (ma, mi, dv) => {
                //update invalid values
                this._invalidValueUpdate(dv);
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- subscribe for export channel name requests
            //-----------------------------------------------------------------------------------------------------  
            this.evtMedApi.subscribeWithId(this.majorID, this.exportChannelNameRequest.minorID, (ma, mi, dv) => {
                //update invalid values
                this._exportRequestChannelNames(dv);
            },1); 

            //-----------------------------------------------------------------------------------------------------
            //-- standard events

            //-----------------------------------------------------------------------------------------------------
            //-- register unload event for sending log off
            //-----------------------------------------------------------------------------------------------------             
            window.addEventListener('unload', () => {
                //send unload event
                this._sendLogout();
            });

            //-----------------------------------------------------------------------------------------------------
            //-- register for change of selected channel
            //-----------------------------------------------------------------------------------------------------             
            window.addEventListener('_DA_SELECTED_CHANNEL_CHANGED', async (e) => {
                if (e.detail !== undefined) {
                    //check if visuchannels exist
                    if (this.visuChlSettings !== undefined) {
                        //get visuchannels of graph instance
                        const visuChls = this.visuChlSettings.get(e.detail.instID);
                        if (visuChls !== undefined) {
                            //get visuchannel with id
                            let visuChl = visuChls.get(e.detail.chlID);
                            if (visuChl !== undefined) {
                                //build reference new
                                visuChl.chlReference = await this._buildChlReferenece(visuChl);                               
                                //fire channel reference update event
                                dispatchEvent(new CustomEvent('_DA_CHANNEL_REFERENCE_CHANGED', {
                                    detail: {
                                        graphInstID: e.detail.instID,
                                        visuChlID: e.detail.chlID,
                                        chlReference: visuChl.chlReference
                                    }
                                }));
                            }
                            else {
                                console.log("_registerEvents(): get visu channel failed");
                            }                                
                        }
                        else {
                            console.log("_registerEvents(): failed to get channels");
                        }                        
                    }
                }
                else {
                    console.log("_registerEvents(): invalid data");
                }
            }); 
            
            
            //-----------------------------------------------------------------------------------------------------
            //-- register for login of graph view
            //-----------------------------------------------------------------------------------------------------             
            window.addEventListener('_DA_LOGIN_GRAPH_VIEW', async (e) => {
                if (e.detail !== undefined) {
                    //check if map for graph views exist
                    if (this.graphViewInstances === undefined) {
                        this.graphViewInstances = new Map();
                    }
                    //set graph view infos
                    this.graphViewInstances.set(e.detail.graphInstID, e.detail.graphViewInfos);
                    //dispatch event to inform various controls that graph view has logged in
                    dispatchEvent(new CustomEvent('_DA_GRAPH_VIEW_LOGGED_IN', {
                        detail: {
                            graphInstID: e.detail.graphInstID
                        }
                    }));
                }
                else {
                    console.log("_registerEvents(): invalid login data");
                }
            });            
        }
        else {
            console.log("_registerEvents(): apis not ready");
        }
    }   

    /**
     * get datapoints with configured userbit for data analyzer login
     */
    async _stationLogin() {
        if ((this.datapointApi !== undefined) && (this.stationsApi !== undefined) && (this.constApi !== undefined)) {
            //get datapoint with userbits
            const dps = await sigApi.datapointManager.getDpList_DS(this.mngStation, 0);
            if ((dps !== null) && (dps !== undefined)) {
                //create list of stations to login
                this.managementStations = [];
                for (let i=0;i<dps.length;i++) {
                    //get datapoint
                    let datapoint = this.datapointApi.getDatapoint(dps[i]);
                    if (datapoint !== null) {
                        //check if station exists
                        if (this.managementStations.includes(datapoint.getStation()) !== true) {
                            this.managementStations.push(datapoint.getStation());
                        }
                    }
                    else {
                        console.log("_stationLogin(): failed to get datapoint");
                    }
                }
                //check if stations online and try to login
                for (let i=0;i<this.managementStations.length;i++) {
                    if (this.stationsApi.getStationStatus(this.managementStations[i]) === this.constApi.STAT_CPU_RUN_RAM) {
                        this._sendLoginRequest(this.managementStations[i]);
                    }
                }
            }                
        }
        else {
            console.log("_stationLogin(): apis not ready");
        }
    }

    /**
     * Send login response to stations
     */         
    _sendLoginRequest(station) {
        if (station !== undefined) {
            const buffer = new ArrayBuffer(this.loginRequest.dataOffset);
            let dv = new DataView(buffer);
            //set header
            dv.setUint32(0, this.loginRequest.version, true); //version
            dv.setUint32(4, this.loginRequest.dataOffset, true); //data offset
            //send login to stations
            if (this._sendEvent(this.loginRequest.minorID, station, dv) !== true) {
                console.log("_sendLoginRequest(): sending login response failed");
            }                 
        }  
        else {
            console.log("_sendLoginRequest(): invalid stationnumber");
        }  
    }

    /**
     * send method so setting the header does not need to be done multiple times
     * @param {*} minorID - minor id of event which should be sent
     * @param {*} minorID - destination station
     * @param {*} dv - data which should be sent
     * @returns 
     */      
    _sendEvent(minorID, station, dv) {
        if ((minorID !== undefined) && (dv !== undefined) && (station !== undefined)) {
            if ((this.evtMedApi !== undefined) && (this.evtApi !== undefined)) {
                this.evtMedApi.publishToStationWithId(this.majorID, minorID, station, dv, 0);
                return true;            
            }
            else {
                console.log("_sendEvent(): event apis not ready");
            }
        }
        else {
            console.log("_sendEvent(): invalid input parameters");
        }        
    }
    
    /**
     * parse response for station and channel data
     * @param {*} dv - dataview with login response data in it
     */
    _getLoginRspData(dv) {
        if (dv !== undefined) {
            //check if datapoint api ready
            if (this.datapointApi !== undefined) {
                //get stationnumber
                const dmsStationNumber = dv.getUint16(8, true);
                //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
                //but there are two stations in lvd project for simple split up
                if (this.managementStations.includes(dmsStationNumber)) {
                    //check for version
                    const version = dv.getUint32(this.sigHeader, true); 
                    if (version === this.loginResponse.version) {
                        //get dataoffset
                        const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                        let managers;
                        //check if station already exists
                        if (this.registerData !== undefined) {
                            //get managers map
                            managers = this.registerData.get(dmsStationNumber);
                        }
                        else  {
                            //create new map for stations
                            this.registerData = new Map();                         
                        }
                        //check if map for managers should be created
                        if (managers === undefined) {
                            //create map for managers
                            managers = new Map();                          
                        }
                        //set offset behind header
                        let tmpOffset = this.sigHeader + dataOffset;
                        //get error info
                        const errorInfo = dv.getUint32(tmpOffset, true);
                        //check for error
                        if (errorInfo === 0) {
                            tmpOffset += 4;                 
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            tmpOffset += 4;
                            //get header data of manager
                            let mngObj = {
                                noOfStations: dv.getUint32(tmpOffset, true),
                                stations: new Map()
                            }
                            //set offset behind manager data
                            tmpOffset += 4;
                            //now go and get stations
                            for (let i=0;i<mngObj.noOfStations;i++) {
                                //get stationnumber
                                const stationNumber = dv.getUint32(tmpOffset, true);
                                tmpOffset += 4;
                                //increase offset
                                let stationObj = {
                                    noOfChannels: dv.getUint32(tmpOffset, true),
                                    noOfTriggers: dv.getUint32(tmpOffset + 4, true),
                                    channels: new Map(),
                                    triggers: new Map()
                                }
                                tmpOffset += 8;
                                //now go and get channels
                                for (let j=0;j<stationObj.noOfChannels;j++) {
                                    //get channelid as identifier key
                                    const chlID = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //get channeldata
                                    let chlObj = {
                                        chlLasalID: dv.getUint32(tmpOffset, true),
                                        srcVarID: dv.getUint32(tmpOffset + 4, true),
                                        chlNameLasalID: dv.getUint32(tmpOffset + 8, true),
                                        maxNoOfValues: dv.getUint32(tmpOffset + 12, true),
                                        dataType: dv.getUint8(tmpOffset + 16),
                                        sampleInterval: dv.getUint32(tmpOffset + 17, true),
                                        group: dv.getUint32(tmpOffset + 21, true),
                                        invalidValue: this._getValueByType(dv, tmpOffset + 25, dv.getUint8(tmpOffset + 16)).value,
                                        timeFirstEntry: 0,
                                        noOfEntries: 0,
                                        actIndex: 0,
                                        buffer: [],
                                        additionalData: [],
                                        unitInfos: undefined
                                    }  
                                    //add unit observer -> save unitInfos cause if source is changed we need to remove it again
                                    this._addUnitObserver(chlObj.srcVarID, async (unit, isFloatingPoint) => {
                                        if (chlObj.unitInfos !== undefined) {
                                            try {
                                                //update zero value
                                                chlObj.unitInfos.zeroValue = await this.convertValueBack(0, unit, isFloatingPoint);
                                                dispatchEvent(new CustomEvent('_DA_UNIT_CHANGED', {
                                                    'detail': {
                                                        stationNumber: stationNumber,
                                                        chlID: chlID
                                                    }
                                                }));                                                
                                            }
                                            catch (error) {
                                                console.log("_getLoginRspData(): failed to get zero value -> " + error); 
                                            }                                            
                                        }
                                    }).then((unitInfos) => {
                                        //update unit infos
                                        chlObj.unitInfos = unitInfos;
                                    },(error) => {
                                        console.log("_getLoginRspData(): failed to add unit observer -> " + error);
                                    });
                                    //add observer for channelname
                                    this._addChannelNameObserver(stationNumber, chlObj.chlNameLasalID, () => {
                                        dispatchEvent(new CustomEvent('_DA_CHANNEL_NAME_CHANGED', {
                                            'detail': {
                                                stationNumber: stationNumber,
                                                chlID: chlID
                                            }
                                        }))
                                    });
                                    //get to next channel
                                    tmpOffset += 29;
                                    //set channel in map
                                    stationObj.channels.set(chlID, chlObj);                                        
                                }
                                //now go and get triggers
                                for (let j=0;j<stationObj.noOfTriggers;j++) {
                                    //get trigger crc
                                    const triggerCRC = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //get triggerdata
                                    let trgObj = {
                                        triggerType: dv.getUint8(tmpOffset), 
                                        triggered: Boolean(dv.getUint8(tmpOffset + 1)),
                                        unixTime: dv.getUint32(tmpOffset + 2, true),
                                        microSec: dv.getUint32(tmpOffset + 6, true),
                                        mode: dv.getUint32(tmpOffset + 10, true),
                                        destination: dv.getUint32(tmpOffset + 14, true)
                                    }  
                                    //get to next trigger
                                    tmpOffset += 18;
                                    //set trigger in map
                                    stationObj.triggers.set(triggerCRC, trgObj);                                                                    
                                }                            
                                //now that all channels are set in map go on and set station in it's map
                                mngObj.stations.set(stationNumber, stationObj);
                            }
                            //now that all stations are set in it's map go on and set managers in it's maps
                            managers.set(mngCRC, mngObj);
                            //and finally save manager in dms stations map
                            this.registerData.set(dmsStationNumber, managers);
                            //dispatch event that we logged in into manager
                            dispatchEvent(new CustomEvent('_DA_LOGGED_IN', {
                                detail: {
                                    dmsStation: dmsStationNumber,
                                    mngCRC: mngCRC
                                }
                            }))
                        } 
                        else {
                            //give some time for error config to be initialized
                            setTimeout(() => {
                                //fire login failed event for error visualisation
                                dispatchEvent(new CustomEvent('_DA_LOGIN_FAILED', {
                                    'detail': {
                                        errorNr: errorInfo
                                    }
                                }));                            
                            }, 1000);

                        }
                    }   
                    else {
                        console.log("_getLoginRspData(): invalid version received");
                    }                    
                }    
            }
            else {
                console.log("_getLoginRspData(): invalid datapoint api");
            }
        }
        else {
            console.log("_getLoginRspData(): invalid dataview");
        }
    }

    /**
     * adds an observer for the datapoint used for potential unit scheme
     * @param {*} varID - variable id of the datapoint of the source
     * @param {*} observer - method which gets called if observer is triggered
     */
    async _addUnitObserver(varID, observer) {
        //check for valid inputs
        if ((varID !== undefined) && (observer !== undefined)) {
            //check if needed apis ready
            if ((this.datapointApi !== undefined) && (this.constApi !== undefined) && (this.propApi !== undefined)) {
                //first of all we have to get the datapoint
                let datapoint = this.datapointApi.getDatapoint(varID);
                if (datapoint !== null) {
                    //get properties
                    let dpProps = datapoint.getProperties();
                    if (dpProps !== undefined) {
                        //check for available unit
                        if (dpProps.unit !== undefined) {
                            //create unit property to add observer
                            const unitProp = this.propApi.createProperty(dpProps.unit);
                            if ((unitProp !== undefined) && (unitProp !== null)) {
                                //add observer to unit property
                                unitProp.addObserver(() => {observer(dpProps.unit, datapoint.isFloatingPoint())});
                                try {
                                    //add observer -> return id and varid to be able to remove observer if source changes
                                    return {
                                        unitProp: unitProp,
                                        zeroValue: await this.convertValueBack(0, dpProps.unit, datapoint.isFloatingPoint())
                                    }    
                                }
                                catch (error) {
                                    console.log("_addUnitObserver(): failed to get convert value back -> " + error);
                                }                                
                            }
                            else {
                                console.log("_addUnitObserver(): failed to create unit property");
                            }
                        }    
                    }
                }   
                else {
                    console.log("_addUnitObserver(): get datapoint failed");
                }                               
            }
            else {
                console.log("_addUnitObserver(): apis not ready");
            }            
        }
        else {
            console.log("_addUnitObserver(): invalid inputs");
        }
    }

    /**
     * adds an observer for the datapoint used for channelname
     * @param {*} stationNumber - stationnumber of the channel
     * @param {*} chlNameLasalID - lasal id of the channelname server
     * @param {*} observer - method which gets called if observer is triggered
     */
     async _addChannelNameObserver(stationNumber, chlNameLasalID, observer) {
        //check for valid inputs
        if ((stationNumber !== undefined) && (chlNameLasalID !== undefined) && (observer !== undefined)) {
            //check if needed apis ready
            if (this.datapointApi !== undefined) {
                //get var id by lasal id
                let varID = await this.datapointApi.getIdFromLasalId(chlNameLasalID, stationNumber);
                if (varID !== undefined) {
                    //result is array so var id is the first entry since we only requested one
                    varID = varID[0];
                    if (varID !== undefined) {
                        //get datapoint
                        const datapoint = this.datapointApi.getDatapoint(varID);
                        if (datapoint !== null) {
                            //add observer
                            datapoint.addObserver(observer);
                        }
                        else {
                            console.log("_addChannelNameObserver(): failed to get datapoint");
                        } 
                    }
                    else {
                        console.log("_addChannelNameObserver(): invalid variable id");
                    }                     
                } 
                else {
                    console.log("_addChannelNameObserver(): get varid failed");
                }                                               
            }
            else {
                console.log("_addChannelNameObserver(): invalid datapoint api");
            }            
        }
        else {
            console.log("_addChannelNameObserver(): invalid inputs");
        }
    }

    /**
     * send logout event to stations
     */
    _sendLogout() {
        //check if logged in somewhere
        if ((this.registerData !== undefined) && (this.registerData.size > 0)) {
            for (let [key, value] of this.registerData) {
                //send logout to station
                const buffer = new ArrayBuffer(this.logoutRequest.dataOffset);
                let dv = new DataView(buffer);
                //set header
                dv.setUint32(0, this.logoutRequest.version, true); //version
                dv.setUint32(4, this.logoutRequest.dataOffset, true); //data offset
                if (this._sendEvent(this.logoutRequest.minorID, 0x0100, dv) !== true) {
                    console.log("_sendLogout(): sending logout failed");
                }                  
            }
        }
    }

    /**
     * get data out of event
     * @param {*} dv - dataview with data in it
     */
    _handleData(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {           
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.dataResponse.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get number of stations
                                const noOfStations = dv.getUint32(tmpOffset, true);
                                //check if stations available
                                if (noOfStations > 0) {
                                    //set offset behind manager data
                                    tmpOffset += 4;
                                    //now go and get stations
                                    for (let i=0;i<noOfStations;i++) {
                                        //get stationnumber
                                        const stationNumber = dv.getUint32(tmpOffset, true);
                                        //get station
                                        let station = manager.stations.get(stationNumber);
                                        if (station !== undefined) {
                                            tmpOffset += 4;
                                            //get number of channels
                                            const noOfChannels = dv.getUint32(tmpOffset, true);
                                            tmpOffset += 4;
                                            //now go and get channels
                                            for (let j=0;j<noOfChannels;j++) {
                                                //get channelid as identifier key
                                                const chlID = dv.getUint32(tmpOffset, true);
                                                //get channel
                                                let channel = station.channels.get(chlID);
                                                if (channel !== undefined) {
                                                    tmpOffset += 4;
                                                    //get info
                                                    const info = dv.getUint8(tmpOffset);
                                                    tmpOffset += 1;
                                                    //get index of first data
                                                    const firstIndex = dv.getUint32(tmpOffset, true);
                                                    tmpOffset += 4;                                                    
                                                    //reset buffer and times
                                                    if (info & 0b1) {
                                                        this._resetBufferValues(stationNumber, chlID, channel, true);
                                                    }   
                                                    //get date and time of first entry
                                                    const unixTime = dv.getUint32(tmpOffset, true);
                                                    tmpOffset += 4;
                                                    //get microsecond offset
                                                    const microSec = dv.getUint32(tmpOffset, true); 
                                                    tmpOffset += 4;                                                                                                                                               
                                                    //get number of values in buffer
                                                    const noOfValues = dv.getUint32(tmpOffset, true);
                                                    //check if values available
                                                    if (noOfValues > 0) {
                                                        //calculate time in µs of new data
                                                        //as it fits in one variable (safe integer is bigger) we can save directly in µs
                                                        const newDataTime = (unixTime * 1000000) + microSec;
                                                        //check if time already set or data are new
                                                        if (channel.timeFirstEntry === 0) { 
                                                            channel.timeFirstEntry = newDataTime;
                                                        }
                                                        //calculate time of records in buffer
                                                        let recordsTime = (channel.sampleInterval * channel.noOfEntries) + channel.microSecFirstEntry;
                                                        //add recordstime to first time to get time of latest entry
                                                        let latestRecTime = channel.timeFirstEntry + recordsTime;
                                                        //check for gaps in recording
                                                        if (newDataTime >= latestRecTime) {
                                                            let noOfGaps = (newDataTime - latestRecTime)/channel.sampleInterval;
                                                            if (noOfGaps > 0) {
                                                                console.log("_handleData(): gaps detected");
                                                            }
                                                        }
                                                        let microSecToWrite = 0;
                                                        //check if date time should be overwritten
                                                        if (channel.noOfEntries < channel.maxNoOfValues) {
                                                            //check for overflow
                                                            if ((channel.noOfEntries + noOfValues) > channel.maxNoOfValues) {
                                                                //calculate timespace which exceeds buffer
                                                                microSecToWrite = ((channel.noOfEntries + noOfValues) - channel.maxNoOfValues) * channel.sampleInterval;
                                                            }
                                                        }
                                                        else {
                                                            microSecToWrite = noOfValues * channel.sampleInterval;
                                                        }
                                                        //add time of overwritten entries to time of first entry
                                                        channel.timeFirstEntry += microSecToWrite                                                 
                                                        tmpOffset += 4;
                                                        let data;
                                                        for (let k=0;k<noOfValues;k++) {
                                                            //get data out of dataview
                                                            data = this._getValueByType(dv, tmpOffset, channel.dataType);
                                                            if (data !== undefined) {
                                                                //Save value in buffer
                                                                channel.buffer[channel.actIndex] = data.value;
                                                                tmpOffset += data.size;
                                                                //increase number of entries
                                                                if (channel.noOfEntries < channel.maxNoOfValues) {
                                                                    channel.noOfEntries += 1;
                                                                }                                                            
                                                                //check for overflow
                                                                if (channel.actIndex < (channel.maxNoOfValues - 1)) {
                                                                    channel.actIndex += 1;
                                                                }
                                                                else {
                                                                    channel.actIndex = 0;
                                                                }
                                                            }
                                                            else {
                                                                console.log("_handleData(): get data failed");
                                                                return;
                                                            }                                                          
                                                        }                                            
                                                        //fire event to trigger drawing of curves
                                                        dispatchEvent(new CustomEvent('_DA_CHANNEL_BUFFER_CHANGED', {
                                                            'detail': {
                                                                stationNumber: stationNumber,
                                                                chlID: chlID,
                                                                recordTime: newDataTime
                                                            }
                                                        }));                                                    
                                                    }
                                                    else {
                                                        console.log("_handleData(): no values available");
                                                        return;
                                                    }                                
                                                }
                                                else {
                                                    console.log("_handleData(): channel not available");
                                                    return;
                                                }
                                            }                                    
                                        }
                                        else {
                                            console.log("_handleData(): station not available");
                                            return;
                                        }
                                    }                                
                                }
                                else {
                                    console.log("_handleData(): no stations available");
                                }
                            }
                            else {
                                console.log("_handleData(): manager not available"); 
                            }
                        }
                        else {
                            console.log("_handleData(): dms station not available"); 
                        }
                    }
                    else {
                        console.log("_handleData(): no data registered");
                    }
                }   
                else {
                    console.log("_handleData(): invalid version received");
                } 
            }           
        }
        else {
            console.log("_handleData(): invalid dataview");
        }
    }   

    /**
     * get additional data out of event
     * @param {*} dv - dataview with data in it
     */
    _handleAdditionalData(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {            
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.dataResponse.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get number of stations
                                const noOfStations = dv.getUint32(tmpOffset, true);
                                //check if stations available
                                if (noOfStations > 0) {
                                    //set offset behind manager data
                                    tmpOffset += 4;
                                    //now go and get stations
                                    for (let i=0;i<noOfStations;i++) {
                                        //get stationnumber
                                        const stationNumber = dv.getUint32(tmpOffset, true);
                                        //get station
                                        let station = manager.stations.get(stationNumber);
                                        if (station !== undefined) {
                                            tmpOffset += 4;
                                            //get number of channels
                                            const noOfChannels = dv.getUint32(tmpOffset, true);
                                            tmpOffset += 4;
                                            //now go and get channels
                                            for (let j=0;j<noOfChannels;j++) {
                                                //get channelid as identifier key
                                                const chlID = dv.getUint32(tmpOffset, true);
                                                //get channel
                                                let channel = station.channels.get(chlID);
                                                if (channel !== undefined) {
                                                    tmpOffset += 4;
                                                    //get number of additional buffers
                                                    const noOfBuffers = dv.getUint8(tmpOffset);
                                                    if (noOfBuffers > 0) {
                                                        tmpOffset += 1;
                                                        for (let k=0;k<noOfBuffers;k++) {
                                                            //get index of additional buffer
                                                            const index = dv.getUint8(tmpOffset);
                                                            tmpOffset += 1;
                                                            //get info
                                                            const info = dv.getUint8(tmpOffset);
                                                            tmpOffset += 1;                                                    
                                                            //get date and time of first entry
                                                            const unixTime = dv.getUint32(tmpOffset, true);
                                                            tmpOffset += 4;
                                                            //get microsecond offset
                                                            const microSec = dv.getUint32(tmpOffset, true); 
                                                            tmpOffset += 4;                                                                                                                                               
                                                            //get number of values in buffer
                                                            const noOfValues = dv.getUint32(tmpOffset, true);
                                                            //check if values available
                                                            if (noOfValues > 0) {
                                                                //calculate time in µs of new data
                                                                //as it fits in one variable (safe integer is bigger) we can save directly in µs
                                                                const newDataTime = (unixTime * 1000000) + microSec;                                                            
                                                                //check if additional data need to be initialized
                                                                if ((channel.additionalData[index] === undefined) || (info & 0b1)) {
                                                                    channel.additionalData[index] = {
                                                                        timeFirstEntry: newDataTime,
                                                                        noOfEntries: 0,
                                                                        actIndex: 0,
                                                                        buffer: []
                                                                    }
                                                                }
                                                                //calculate time of records in buffer
                                                                let recordsTime = (channel.sampleInterval * channel.additionalData[index].noOfEntries) + channel.additionalData[index].microSecFirstEntry;
                                                                let latestRecTime = channel.additionalData[index].timeFirstEntry + recordsTime;
                                                                //check for gaps in recording
                                                                if (newDataTime >= latestRecTime) {
                                                                    let noOfGaps = (newDataTime - latestRecTime)/channel.sampleInterval;
                                                                    if (noOfGaps > 0) {
                                                                        console.log("_handleData(): gaps detected");
                                                                    }
                                                                }
                                                                let microSecToWrite = 0;
                                                                //check if date time should be overwritten
                                                                if (channel.additionalData[index].noOfEntries < channel.maxNoOfValues) {
                                                                    //check for overflow
                                                                    if ((channel.additionalData[index].noOfEntries + noOfValues) > channel.maxNoOfValues) {
                                                                        //calculate timespace which exceeds buffer
                                                                        microSecToWrite = ((channel.additionalData[index].noOfEntries + noOfValues) - channel.maxNoOfValues) * channel.sampleInterval;
                                                                    }
                                                                }
                                                                else {
                                                                    microSecToWrite = noOfValues * channel.sampleInterval;
                                                                }
                                                                //add time of overwritten entries to time of first entry
                                                                channel.additionalData[index].timeFirstEntry += microSecToWrite;                                                       
                                                                tmpOffset += 4;
                                                                let data;
                                                                for (let l=0;l<noOfValues;l++) {
                                                                    //get data out of dataview
                                                                    data = this._getValueByType(dv, tmpOffset, channel.dataType);
                                                                    if (data !== undefined) {
                                                                        //Save value in buffer
                                                                        channel.additionalData[index].buffer[channel.additionalData[index].actIndex] = data.value;
                                                                        tmpOffset += data.size;
                                                                        //increase number of entries
                                                                        if (channel.additionalData[index].noOfEntries < channel.maxNoOfValues) {
                                                                            channel.additionalData[index].noOfEntries += 1;
                                                                        }                                                            
                                                                        //check for overflow
                                                                        if (channel.additionalData[index].actIndex < (channel.maxNoOfValues - 1)) {
                                                                            channel.additionalData[index].actIndex += 1;
                                                                        }
                                                                        else {
                                                                            channel.additionalData[index].actIndex = 0;
                                                                        }
                                                                    }
                                                                    else {
                                                                        console.log("_handleAdditionalData(): get data failed");
                                                                        return;
                                                                    }                                                          
                                                                }                                               
                                                                //fire event to trigger drawing of curves
                                                                dispatchEvent(new CustomEvent('_DA_CHANNEL_ADDITIONAL_BUFFER_CHANGED', {
                                                                    'detail': {
                                                                        stationNumber: stationNumber,
                                                                        chlID: chlID,
                                                                        index: index
                                                                    }
                                                                }));                                                    
                                                            }
                                                            else {
                                                                console.log("_handleAdditionalData(): no values available");
                                                                return;
                                                            }                                                         
                                                        }
                                                        
                                                    }
                                                    else {
                                                        console.log("_handleAdditionalData(): no buffers available");
                                                        return;
                                                    }                               
                                                }
                                                else {
                                                    console.log("_handleAdditionalData(): channel not available");
                                                    return;
                                                }
                                            }                                    
                                        }
                                        else {
                                            console.log("_handleAdditionalData(): station not available");
                                            return;
                                        }
                                    }                                
                                }
                                else {
                                    console.log("_handleAdditionalData(): no stations available");
                                }
                            }
                            else {
                                console.log("_handleAdditionalData(): manager not available"); 
                            }
                        }
                        else {
                            console.log("_handleAdditionalData(): dms station not available"); 
                        }
                    }
                    else {
                        console.log("_handleAdditionalData(): no data registered");
                    }
                }   
                else {
                    console.log("_handleAdditionalData(): invalid version received");
                } 
            }           
        }
        else {
            console.log("_handleAdditionalData(): invalid dataview");
        }
    } 

    /**
     * method is used to start calculation in data worker
     * @param {*} stationNumber - stationnumber where the channel is located
     * @param {*} chlID - ID of the channel
     * @param {*} channel - channel to get values from
     */
    _startDataWorker(stationNumber, chlID, channel) {
        //check for valid input
        if ((channel !== undefined) && (stationNumber !== undefined) && (chlID !== undefined)) {
            const workerData = {
                stationNumber: stationNumber,
                chlID: chlID,
                noOfEntries: channel.noOfEntries,
                buffer: channel.buffer
            }
            //start dataworker
            this.dataWorker.postMessage(workerData);
            channel.dataWorkerActive = true;            
        }
        else {
            console.log("_startDataWorker(): invalid inputs");
        }        
    }

    /**
     * gets data out of data view by info of size and offset
     * @param {*} dv - dataview to get the value from
     * @param {*} offset - offset in dataview
     * @param {*} dataType - type of the data
     */
    _getValueByType(dv, offset, dataType) {
        //check for valid inputs
        if ((dv !== undefined) && (offset !== undefined) && (dataType !== undefined)) {
            let retvals = {
                value: undefined,
                size: undefined
            }
            //now we have to check for the data type to know how the values should be converted
            switch (dataType) {
                //********************************************************************************************
                //** 8 Bit signed integer
                //********************************************************************************************
                case this.dataTypes.int8:
                    retvals.value = dv.getInt8(offset);
                    retvals.size = 1;
                    break;
                
                //********************************************************************************************
                //** 16 Bit signed integer
                //********************************************************************************************
                case this.dataTypes.int16:
                    retvals.value = dv.getInt16(offset, true);
                    retvals.size = 2;
                    break;  
                    
                //********************************************************************************************
                //** 32 Bit signed integer
                //********************************************************************************************
                case this.dataTypes.int32:
                    retvals.value = dv.getInt32(offset, true);
                    retvals.size = 4;
                    break;

                //********************************************************************************************
                //** 64 Bit signed integer
                //********************************************************************************************
                case this.dataTypes.int64:
                    retvals.value = dv.getBigInt64(offset, true);
                    retvals.size = 8;
                    break;                    

                //********************************************************************************************
                //** 8 Bit unsigned integer
                //********************************************************************************************
                case this.dataTypes.uint8, this.dataTypes.bool:
                    retvals.value = dv.getUint8(offset);
                    retvals.size = 1;
                    break;  

                //********************************************************************************************
                //** 16 Bit unsigned integer
                //********************************************************************************************
                case this.dataTypes.uint16:
                    retvals.value = dv.getUint16(offset, true);
                    retvals.size = 2;
                    break;  
                    
                //********************************************************************************************
                //** 32 Bit unsigned integer
                //********************************************************************************************
                case this.dataTypes.uint32:
                    retvals.value = dv.getUint32(offset, true);
                    retvals.size = 4;
                    break;                    

                //********************************************************************************************
                //** 64 Bit unsigned integer
                //********************************************************************************************
                case this.dataTypes.uint64:
                    retvals.value = dv.getBigUint64(offset, true);
                    retvals.size = 8;
                    break; 

                //********************************************************************************************
                //** 32 Bit float
                //********************************************************************************************
                case this.dataTypes.float32:
                    retvals.value = dv.getFloat32(offset, true);
                    retvals.size = 4;
                    break;                    

                //********************************************************************************************
                //** 64 Bit float
                //********************************************************************************************
                case this.dataTypes.float64:
                    retvals.value = dv.getFloat64(offset, true);
                    retvals.size = 8;
                    break;                     

                default:
                    console.log("_getValueByType(): invalid datatype");                   
            }
            return retvals;
        }
        else {
            console.log("_getValueByType(): invalid inputs");
        }
    }

    /**
     * method can be used to reset buffer
     * @param {*} stationNumber - number of the station the channel is located at
     * @param {*} chlID - ID of the channel
     * @param {*} channel - channel whiches buffer should be reset
     */
    _resetBufferValues(stationNumber, chlID, channel) {
        //check for valid input
        if ((stationNumber !== undefined) && (chlID !== undefined) && (channel !== undefined)) {
            channel.timeFirstEntry = 0;
            channel.noOfEntries = 0;
            channel.buffer = [];
            channel.actIndex = 0;
            //dispatch event to inform others that buffer was resetted
            dispatchEvent(new CustomEvent('_DA_BUFFER_RESETTED', {
                detail: {
                    stationNumber: stationNumber,
                    chlID: chlID
                }
            }))
        }
        else {
            console.log("_resetBufferValues(): invalid inputs");
        }
    }

    /**
     * clears the buffer values and sets new size parameters
     * @param {*} dv - dataview with information of which buffer should be resized
     */
     _reallocBuffer(dv) {
        //check for valid input
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {            
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.reallocRequest.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get das station
                                const dasStationNumber = dv.getUint32(tmpOffset, true);
                                //check if das station exists
                                let dasStation = manager.stations.get(dasStationNumber);
                                if (dasStation !== undefined) {
                                    tmpOffset += 4;
                                    //get channel ID
                                    const chlID = dv.getUint32(tmpOffset, true);
                                    //check if channel exists
                                    let channel = dasStation.channels.get(chlID);
                                    if (channel !== undefined) {
                                        tmpOffset += 4;
                                        //get sampleinterval
                                        const sampleInterval = dv.getUint32(tmpOffset, true);
                                        tmpOffset += 4;
                                        //get maximum number of values
                                        const maxNoOfValues = dv.getUint32(tmpOffset, true);
                                        //reset buffer and set new values of buffer
                                        this._resetBufferValues(dasStationNumber, chlID, channel);
                                        channel.sampleInterval = sampleInterval;
                                        channel.maxNoOfValues = maxNoOfValues;
                                        //dispatch event that buffer was reallocated
                                        dispatchEvent(new CustomEvent('_DA_BUFFER_REALLOC', {
                                            detail: {
                                                stationNumber: dasStationNumber,
                                                chlID: chlID
                                            }
                                        }));
                                    }
                                    else {
                                        console.log("_reallocBuffer(): channel not found");
                                    }
                                }
                                else {
                                    console.log("_reallocBuffer(): das station not found");
                                }
                            }
                            else {
                                console.log("_reallocBuffer(): manager not found");
                            }
                        }    
                        else {
                            console.log("_reallocBuffer(): dms station not found");
                        }
                    }
                    else {
                        console.log("_reallocBuffer(): no channels registered");
                    }
                }     
                else {
                    console.log("_reallocBuffer(): unknown version of event");
                } 
            }                  
        }
        else {
            console.log("_reallocBuffer(): invalid dataview");
        }
    }

    /**
     * method is used for login of visu channels
     * @param {*} props - properties of visuchannel
     */
    async loginVisuChannel(props) {
        //check for valid input
        if (props !== undefined) {
            //check if visuchannel settings already allocated
            if (this.visuChlSettings === undefined) {
                this.visuChlSettings = new Map();
            }
            //check if graph already exists
            let graph = this.visuChlSettings.get(props.graphInstID);
            if (graph === undefined) {
                graph = new Map();
                this.visuChlSettings.set(props.graphInstID, graph);
            }
            //check if channel already exists
            let channel = graph.get(props.visuChlID);
            if (channel === undefined) {
                //build properties
                let visuChl = new VisuChannel(props, this.constApi);
                //build real channel reference
                visuChl.chlReference = await this._buildChlReferenece(visuChl);
                graph.set(props.visuChlID, visuChl);

                //sort map
                graph = new Map([...graph.entries()].sort());
                //set new map
                this.visuChlSettings.set(props.graphInstID, graph);
                
                //update graphs control
                dispatchEvent(new CustomEvent('_DA_NEW_CHANNEL_LOGGED_IN', {
                    'detail': {
                        instID: props.graphInstID,
                        channelActive: visuChl.channelActive.value,
                        chlID: props.visuChlID,
                        chlReference: visuChl.chlReference
                    } 
                }));
            }
        }   
        else {
            console.log("loginVisuChannel(): invalid properties");
        }
    }

    /**
     * checks if default channel should be used or different channel was selected
     * @param {*} props - properties of visuchannel
     */
    async _buildChlReferenece(props) {
        //check for valid properties
        if (props !== undefined) {
            //check if datapoint api is ready
            if (this.datapointApi !== undefined) {
                //retvalue
                let chlRef = {
                    stationNumber: undefined,
                    chlID: undefined
                }
                //check if selected channel available
                if ((props.selectedChannel !== undefined) && (props.selectedChannel.value !== undefined) && (props.selectedChannel.value !== 0)) {
                    try {
                        //get id of datapoint to get datapoint itself
                        let ids = await this.datapointApi.getIdFromCRC(props.selectedChannel.value);  
                        if ((ids !== undefined) && (ids.length > 0)) {
                            //now get datapoint
                            let datapoint = this.datapointApi.getDatapoint(ids[0]);
                            if (datapoint !== null) {
                                chlRef.stationNumber = datapoint.getStation();
                                chlRef.chlID = await datapoint.getValue();
                                return chlRef;
                            }
                            else {
                                console.log("_buildChlReferenece(): get datapoint failed");
                            }                              
                        }
                        else {
                            console.log("_buildChlReferenece(): get id failed");
                        }                                                
                    }
                    catch (error) {
                        console.log("_buildChlReferenece(): get id failed" + error);
                    }     
                }
                else if (props.defaultChannel !== undefined) {
                    chlRef.stationNumber = props.defaultChannel.ref.getStation();
                    chlRef.chlID = props.defaultChannel.value;
                    return chlRef;
                }
            }
            else {
                console.log("_buildChlReferenece(): datapoint api not ready");
            }            
        }
        else {
            console.log("_buildChlReferenece(): invalid properties");
        }
    }

    /**
     * this method is used to get the reference datatype of the recording source
     * @param {*} realChl - channel to get the datatype from
     */
    getReferenceDatatype(realChl) {
        if (realChl !== undefined) {
            switch (realChl.dataType) {
                //-----------------------------------------------------------------------------------------
                //-- types for DINT comparision
                //-----------------------------------------------------------------------------------------
                case this.dataTypes.int8:
                case this.dataTypes.int16:
                case this.dataTypes.int32:
                    return this.referenceDataTypes.DINT;

                //-----------------------------------------------------------------------------------------
                //-- types for UDINT comparision
                //-----------------------------------------------------------------------------------------
                case this.dataTypes.bool:
                case this.dataTypes.uint8:
                case this.dataTypes.uint16: 
                case this.dataTypes.uint32:
                    return this.referenceDataTypes.UDINT;
                    
                //-----------------------------------------------------------------------------------------
                //-- types for REAL comparision
                //-----------------------------------------------------------------------------------------
                case this.dataTypes.float32:
                    return this.referenceDataTypes.REAL; 
                    
                //-----------------------------------------------------------------------------------------
                //-- rest is invalid
                //-----------------------------------------------------------------------------------------
                default:
                    console.log("getReferenceDatatype(): invalid datatype");                    
            }            
        }
        else {
            console.log("getReferenceDatatype(): invalid inputs");
        }
    }

    /**
     * returns channels belonging to graph instance id
     * @param {*} graphInstanceID 
     */
    getVisuChannels(graphInstanceID) {
        //check for valid input
        if (graphInstanceID !== undefined) {
            //check if data available
            if (this.visuChlSettings !== undefined) {
                //get channels belonging to graph
                return this.visuChlSettings.get(graphInstanceID);
            }            
        }
        else {
            console.log("getVisuChannels(): invalid instance id");            
        }
    }
    
    /**
     * method can be used to get all recording channels
     * @returns 
     */
    getRegisteredChannels() {
        return this.registerData;
    }

    /**
     * method is used to get channel data by stationnumber and channel reference
     * @param {*} stationNumber 
     * @param {*} chlID 
     */
    getChannelByID(stationNumber, chlID) {
        //check for valid inputs
        if ((stationNumber !== undefined) && (chlID !== undefined)) {
            //check if data available
            if ((this.registerData !== undefined) && (this.registerData.size > 0)) {
                //get through dms stations and managers to get channel
                for (let [dmsKey, managers] of this.registerData) {
                    if (managers.size > 0) {
                        for (let [mngKey, manager] of managers) {
                            if (manager.noOfStations > 0) {
                                //lets try and get station
                                const station = manager.stations.get(stationNumber);
                                if (station !== undefined) {
                                    if (station.noOfChannels > 0) {
                                        //now try and get channel
                                        let channel = station.channels.get(chlID); 
                                        if (channel !== undefined) {
                                            return channel;
                                        }
                                    }
                                }                                
                            }
                        }
                    }
                }
            }
        }
        else {
            console.log("getVisuChannels(): invalid inputs");
        }
    }
    
    /**
     * method is used to set a new server for recording
     * @param {*} stationNumber - stationnumber of the channel
     * @param {*} chlID - ID of the channel
     * @param {*} lasalID - lasal id of the new server
     * @param {*} crc - crc of the new server
     * @param {*} varID - variable id of the new server
     * @param {*} typeId - type id of server
     */
    setNewChannelServer(stationNumber, chlID, lasalID, crc, varID, typeId) {
        //check for valid inputs
        if ((stationNumber !== undefined) && (chlID !== undefined) && (lasalID !== undefined) && (crc !== undefined) && (varID !== undefined) && (typeId !== undefined)) {
            //get dms station number to send event to it
            if (this.registerData !== undefined) {
                for (let [dmsKey, managers] of this.registerData) {
                    if (managers.size > 0) {
                        for (let [mngKey, manager] of managers) {
                            if (manager.stations.size > 0) {
                                for (let [dasStationNumber, station] of manager.stations) {
                                    if (station.channels.size > 0) {
                                        for (let [channelID, channel] of station.channels) {
                                            //check if it is the channel we are searching for
                                            if ((channelID === chlID) && (dasStationNumber === stationNumber)) {
                                                //channel found so we know to which dms station we should send to
                                                const buffer = new ArrayBuffer(this.newServerRequest.dataOffset + this.newServerRequest.size);
                                                let dv = new DataView(buffer);
                                                //set header
                                                dv.setUint32(0, this.newServerRequest.version, true); //version
                                                dv.setUint32(4, this.newServerRequest.dataOffset, true); //data offset
                                                let tmpOffset = this.newServerRequest.dataOffset;
                                                //add manager crc
                                                dv.setUint32(tmpOffset, mngKey, true);
                                                tmpOffset += 4;                                                
                                                //add stationnumber
                                                dv.setUint32(tmpOffset, stationNumber, true);
                                                tmpOffset += 4;
                                                //add channel ID
                                                dv.setUint32(tmpOffset, chlID, true);
                                                tmpOffset += 4;  
                                                //add lasal id
                                                dv.setUint32(tmpOffset, lasalID, true);
                                                tmpOffset += 4;   
                                                //add server crc
                                                dv.setUint32(tmpOffset, crc, true);
                                                tmpOffset += 4; 
                                                //add variable id
                                                dv.setUint32(tmpOffset, varID, true);
                                                tmpOffset += 4;
                                                //add data type
                                                dv.setUint32(tmpOffset, this._convertDataType(typeId), true);
                                                if (this._sendEvent(this.newServerRequest.minorID, dmsKey, dv) !== true) {
                                                    console.log("setNewChannelServer(): sending new server request failed");
                                                }  
                                                return;                                               
                                            }                                                     
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            console.log("setNewChannelServer(): invalid inputs");
        }
    } 

    /**
     * method is used to convert the type ref id to the datatype used in lasal class
     * @param {*} typeId - type ref id of the server
     */
    _convertDataType(typeId) {
        //check for valid type id
        if (typeId !== undefined) {
            //check if api available
            if (this.constApi !== undefined) {
                switch (typeId) {
                    
                    //-----------------------------------------------------------------------------
                    // signed double integer
                    //-----------------------------------------------------------------------------
                    case this.constApi.STD_TYPE_DINT:
                        return this.dataTypes.int32;

                    //-----------------------------------------------------------------------------
                    // unsigned double integer
                    //-----------------------------------------------------------------------------
                    case this.constApi.STD_TYPE_UDINT:
                    case this.constApi.STD_TYPE_BDINT:
                    case this.constApi.STD_TYPE_HDINT:
                        return this.dataTypes.uint32;

                    //-----------------------------------------------------------------------------
                    // float
                    //-----------------------------------------------------------------------------
                    case this.constApi.STD_TYPE_REAL:
                        return this.dataTypes.float32;

                    default:
                        //invalid datatype of server
                        return this.dataTypes.void;    
                }
            }
            else {
                console.log('DA_DataManager::_convertDataType(): invalid constant api', 'ERROR');
            }            
        }
        else {
            console.log('DA_DataManager::_convertDataType(): invalid type id', 'ERROR');
        }
    }

    /**
     * gets called if new server response is received
     * @param {*} dv - dataview of event
     */
    async _setNewServer(dv) {
        //check for valid dataview
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {            
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.newServerResponse.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if error occured
                    let tmpOffset = this.sigHeader + dataOffset;
                    const errorNr = dv.getUint32(tmpOffset, true);
                    tmpOffset += 4;
                    if (errorNr === 0) {
                        //check if station already exists
                        if (this.registerData !== undefined) {
                            //get station entry
                            let dmsStation = this.registerData.get(dmsStationNumber);
                            if (dmsStation !== undefined) {              
                                //get manager crc
                                const mngCRC = dv.getUint32(tmpOffset, true);
                                //check if manager exists
                                let manager = dmsStation.get(mngCRC);
                                if (manager !== undefined) {
                                    tmpOffset += 4;
                                    //get stationnumber
                                    const stationNumber = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //get channel ID
                                    const chlID = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //get channel
                                    let channel = this.getChannelByID(stationNumber, chlID);
                                    if (channel !== undefined) {
                                        //get variable id
                                        channel.srcVarID = dv.getUint32(tmpOffset, true);
                                        tmpOffset += 4;
                                        //check if datatype changed
                                        const dataType =  dv.getUint8(tmpOffset);
                                        let dataTypeChanged = false;
                                        if (dataType !== channel.dataType) {
                                            dataTypeChanged = true;
                                        }
                                        channel.dataType = dataType;
                                        //reset buffer
                                        this._resetBufferValues(stationNumber, chlID, channel);
                                        //reset values effected by datatype 
                                        if (dataTypeChanged) {
                                            this._resetDataTypeValues(stationNumber, chlID);
                                        }
                                        //remove old unit observer
                                        if ((channel.unitInfos !== undefined) && (this.datapointApi !== undefined)) {
                                            if ((channel.unitInfos.unitProp !== null) && (channel.unitInfos.unitProp !== undefined)) {
                                                //destroy unitproperty
                                                channel.unitInfos.unitProp.destroy();
                                                //reset observer infos
                                                channel.unitInfos = undefined;
                                            }
                                        }
                                        try {
                                            //add new observer
                                            channel.unitInfos = await this._addUnitObserver(channel.srcVarID, async (unit, isFloatingPoint) => {
                                                if (channel.unitInfos !== undefined) {
                                                    try {
                                                        //update zero value
                                                        channel.unitInfos.zeroValue = await this.convertValueBack(0, unit, isFloatingPoint);
                                                        dispatchEvent(new CustomEvent('_DA_UNIT_CHANGED', {
                                                            'detail': {
                                                                stationNumber: stationNumber,
                                                                chlID: chlID
                                                            }
                                                        }));                                                
                                                    }
                                                    catch (error) {
                                                        console.log("_setNewServer(): failed to get zero value -> " + error); 
                                                    }                                                
                                                }
                                            });
                                            //dispatch event that server source changed
                                            dispatchEvent(new CustomEvent('_DA_SERVER_CHANGED', {
                                                'detail': {
                                                    stationNumber: stationNumber,
                                                    chlID: chlID
                                                }
                                            }));                                                                                
                                        }
                                        catch (error) {
                                            console.log("_setNewServer(): failed to add unit observer -> " + error); 
                                        }            
                                    }
                                    else {
                                        console.log("_setNewServer(): channel not found"); 
                                    }
                                }
                                else {
                                    console.log("_setNewServer(): manager not available"); 
                                }
                            }
                            else {
                                console.log("_setNewServer(): dms station not available"); 
                            }
                        }
                        else {
                            console.log("_setNewServer(): no data registered");
                        }
                    }
                    else {
                        //dispatch event that server source changed
                        dispatchEvent(new CustomEvent('_DA_SERVER_CHANGE_FAILED', {
                            'detail': {
                                errorNr: errorNr
                            }
                        }));                     
                    }
                }   
                else {
                    console.log("_setNewServer(): invalid version received");
                }  
            }               
        }
        else {
            console.log('_setNewServer(): invalid dataview', 'ERROR');
        }
    }
    
    /**
     * method is used to reset min and max scale and value per division values of visuchannels
     * @param {*} stationNumber - number of the station the channel is located at
     * @param {*} chlID - channel ID
     */
    _resetDataTypeValues(stationNumber, chlID) {
        //check for inputs
        if ((stationNumber !== undefined) && (chlID !== undefined)) {
            //check if data available
            if (this.visuChlSettings !== undefined) {
                //get through visu channels and reset min max
                for (let [graphInstId, visuChls] of this.visuChlSettings) {
                    for (let [visuChlID, channel] of visuChls) {
                        //check for reference of channel
                        if (channel.chlReference !== undefined) {
                            if ((channel.chlReference.stationNumber === stationNumber) && (channel.chlReference.chlID === chlID)) {
                                //reset min scale
                                if (channel.minScale.ref !== undefined) {
                                    if (this.datapointApi !== undefined) {
                                        this.datapointApi.writeDataPoint(channel.minScale.ref.getId(), 0);
                                    }
                                    else {
                                        console.log("_resetDataTypeValues(): invalid datapoint api", 'ERROR')
                                    }
                                }
                                channel.minScale.value = 0;  
                                //reset max scale                              
                                if (channel.maxScale.ref !== undefined) {
                                    if (this.datapointApi !== undefined) {
                                        this.datapointApi.writeDataPoint(channel.maxScale.ref.getId(), 0);
                                    }
                                    else {
                                        console.log("_resetDataTypeValues(): invalid datapoint api", 'ERROR')
                                    }                        
                                }
                                channel.maxScale.value = 0;
                                //reset value per division
                                if (channel.valuePerDivision.ref !== undefined) {
                                    if (this.datapointApi !== undefined) {
                                        this.datapointApi.writeDataPoint(channel.valuePerDivision.ref.getId(), 0);
                                    }
                                    else {
                                        console.log("_resetDataTypeValues(): invalid datapoint api", 'ERROR')
                                    }                        
                                }
                                channel.valuePerDivision.value = 0;
                            }
                        }
                    }
                }
            }                                          
        }
        else {
            console.log('_resetDataTypeValues(): invalid inputs', 'ERROR');
        }
    }

    /**
     * gets called if trigger was raised
     * @param {*} dv - dataview with trigger data in it
     */
    _triggerRaised(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.triggerRaised.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get stationnumber
                                const stationNumber = dv.getUint32(tmpOffset, true);
                                tmpOffset += 4;
                                //get station
                                let station = manager.stations.get(stationNumber);
                                if (station !== undefined) {
                                    //get number of triggers
                                    const noOfTriggers = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //now go and get triggers
                                    for (let j=0;j<noOfTriggers;j++) {
                                        //get triggerCRC as identifier key
                                        const triggerCRC = dv.getUint32(tmpOffset, true);
                                        //get trigger
                                        let trigger = station.triggers.get(triggerCRC);
                                        if (trigger !== undefined) {
                                            tmpOffset += 4;
                                            //fill in trigger data
                                            trigger.unixTime = dv.getUint32(tmpOffset, true);
                                            tmpOffset += 4;
                                            //get microsecond offset
                                            trigger.microSec = dv.getUint32(tmpOffset, true); 
                                            tmpOffset += 4;
                                            //set channel source
                                            trigger.channel = dv.getUint32(tmpOffset, true); 
                                            tmpOffset += 4;
                                            //get triggerAction
                                            trigger.triggerAction = dv.getUint32(tmpOffset, true);
                                            tmpOffset += 4;
                                            //get triggermode
                                            trigger.mode = dv.getUint32(tmpOffset, true);
                                            tmpOffset += 4; 
                                            //get destination
                                            trigger.destination = dv.getUint32(tmpOffset, true);
                                            tmpOffset += 4;
                                            //get presamples
                                            trigger.preSamples = dv.getUint8(tmpOffset);
                                            tmpOffset += 1;
                                            //get postsamples
                                            trigger.postSamples = dv.getUint8(tmpOffset);
                                            tmpOffset += 1;
                                            //set triggered
                                            trigger.triggered = true;
                                        }
                                        else {
                                            console.log("_triggerRaised(): trigger not available");
                                            return;
                                        }
                                    }                                    
                                }
                                else {
                                    console.log("_triggerRaised(): station not available");
                                }
                            }
                            else {
                                console.log("_triggerRaised(): manager not available"); 
                            }
                        }
                        else {
                            console.log("_triggerRaised(): dms station not available"); 
                        }
                    }
                    else {
                        console.log("_triggerRaised(): no data registered");
                    }
                }   
                else {
                    console.log("_triggerRaised(): invalid version received");
                } 
            }           
        }
        else {
            console.log("_triggerRaised(): invalid dataview");
        }        
    } 

    /**
     * gets called if reset triggerstates should be done
     * @param {*} dv - dataview which contains the information which channel got started
     */
    _resetTriggersReceived(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {            
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.resetTriggers.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get stationnumber
                                const stationNumber = dv.getUint32(tmpOffset, true);
                                tmpOffset += 4;
                                //get station
                                let station = manager.stations.get(stationNumber);
                                if (station !== undefined) {
                                    //get number of triggers
                                    const noOfTriggers = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //now go and get triggers
                                    for (let j=0;j<noOfTriggers;j++) {
                                        //get trigger CRC as identifier key
                                        const triggerCRC = dv.getUint32(tmpOffset, true);
                                        tmpOffset += 4;
                                        //get trigger
                                        const trigger = station.triggers.get(triggerCRC);
                                        //reset triggerstate
                                        trigger.triggered = false;                                                    
                                    }                                    
                                }
                                else {
                                    console.log("_resetTriggersReceived(): station not available");
                                }
                            }
                            else {
                                console.log("_resetTriggersReceived(): manager not available"); 
                            }
                        }
                        else {
                            console.log("_resetTriggersReceived(): dms station not available"); 
                        }
                    }
                    else {
                        console.log("_resetTriggersReceived(): no data registered");
                    }
                }   
                else {
                    console.log("_resetTriggersReceived(): invalid version received");
                } 
            }           
        }
        else {
            console.log("_resetTriggersReceived(): invalid dataview");
        }          
    }    

    /**
     * method gets called if clear data event was received
     * @param {*} dv - dataview of event
     */    
    _clearData(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {               
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.clearData.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get stationnumber
                                const stationNumber = dv.getUint32(tmpOffset, true);
                                tmpOffset += 4;
                                //get station
                                let station = manager.stations.get(stationNumber);
                                if (station !== undefined) {
                                    //get number of channels
                                    const noOfChannels = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //now go and get channels
                                    for (let j=0;j<noOfChannels;j++) {
                                        //get channelID as identifier key
                                        const channelID = dv.getUint32(tmpOffset, true);
                                        tmpOffset += 4;
                                        //get channel
                                        let channel = station.channels.get(channelID);
                                        if (channel !== undefined) {
                                            //reset buffer
                                            this._resetBufferValues(stationNumber, channelID, channel);
                                            //fire clear event to update graphs
                                            dispatchEvent(new CustomEvent('_DA_CLEAR_DATA', {
                                                detail: {
                                                    stationNumber: stationNumber,
                                                    chlID: channelID
                                                }
                                            }));
                                        }
                                        else {
                                            console.log("_clearData(): channel not available");
                                            return;
                                        }
                                    }                                    
                                }
                                else {
                                    console.log("_clearData(): station not available");
                                }
                            }
                            else {
                                console.log("_clearData(): manager not available"); 
                            }
                        }
                        else {
                            console.log("_clearData(): dms station not available"); 
                        }
                    }
                    else {
                        console.log("_clearData(): no data registered");
                    }
                }   
                else {
                    console.log("_clearData(): invalid version received");
                }
            }            
        }
        else {
            console.log("_clearData(): invalid dataview");
        }  
    }

    /**
     * method gets called if group update event was received
     * @param {*} dv - dataview of event
     */    
    _groupUpdate(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {               
                //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.groupUpdate.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get stationnumber
                                const stationNumber = dv.getUint32(tmpOffset, true);
                                tmpOffset += 4;
                                //get station
                                let station = manager.stations.get(stationNumber);
                                if (station !== undefined) {
                                    //get number of channels
                                    const noOfChannels = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //now go and get channels
                                    for (let j=0;j<noOfChannels;j++) {
                                        //get channelID as identifier key
                                        const channelID = dv.getUint32(tmpOffset, true);
                                        tmpOffset += 4;
                                        //get channel
                                        let channel = station.channels.get(channelID);
                                        if (channel !== undefined) {
                                            //set new group
                                            channel.group = dv.getUint32(tmpOffset, true);
                                            tmpOffset += 4;
                                        }
                                        else {
                                            console.log("_groupUpdate(): channel not available");
                                            return;
                                        }
                                    }                                    
                                }
                                else {
                                    console.log("_groupUpdate(): station not available");
                                }
                            }
                            else {
                                console.log("_groupUpdate(): manager not available"); 
                            }
                        }
                        else {
                            console.log("_groupUpdate(): dms station not available"); 
                        }
                    }
                    else {
                        console.log("_groupUpdate(): no data registered");
                    }
                }   
                else {
                    console.log("_groupUpdate(): invalid version received");
                }  
            }          
        }
        else {
            console.log("_groupUpdate(): invalid dataview");
        }  
    }

    /**
     * method is used to return an array of triggers which got raised
     */
    getActiveTriggers() {
        //check if data available
        if (this.registerData !== undefined) {
            //init map for triggers
            let activeTriggers = new Map();
            for (let [dmsStationNumber, dmsStation] of this.registerData) {
                //check for managers
                for (let [mngCRC, manager] of dmsStation) {
                    //check for stations
                    if (manager.noOfStations > 0) {
                        for (let [stationNumber, station] of manager.stations) {
                            //at least check for triggers
                            for (let [triggerCRC, trigger] of station.triggers) {
                                //check if trigger got raised
                                if (trigger.triggered === true) {
                                    //build triggerdata
                                    let triggerData = {
                                        unixTime: trigger.unixTime,
                                        microSec: trigger.microSec,
                                        mode: trigger.mode,
                                        destination: trigger.destination
                                    }
                                    //check if station already available
                                    let triggerStation = activeTriggers.get(stationNumber);
                                    if (triggerStation === undefined) {
                                        triggerStation = []
                                    }
                                    //add trigger to station
                                    triggerStation.push(triggerData);
                                    //Set in map
                                    activeTriggers.set(stationNumber, triggerStation);
                                }
                            }
                        }                        
                    }
                }
            }
            //return map of active triggers
            return activeTriggers;
        }
    }

    /**
     * method is used to get a trigger by its crc
     * @param {*} triggerCRC - crc of the trigger
     * @returns 
     */
     getTriggerByCRC(triggerCRC) {
        //check valid inputs
        if (triggerCRC !== undefined) {
            //check if data available
            if (this.registerData !== undefined) {
                for (let [dmsStationNumber, dmsStation] of this.registerData) {
                    //check for managers
                    for (let [mngCRC, manager] of dmsStation) {
                        //chech stations
                        for (let [stationNumber, station] of manager.stations) {
                            //at last check for triggers
                            for (let [keyTriggerCRC, trigger] of station.triggers) {
                                //check if trigger we are searchin for
                                if (triggerCRC === keyTriggerCRC) {
                                    //return trigger with extra info
                                    return {
                                        trigger: trigger,
                                        dmsStation: dmsStationNumber,
                                        managerCRC: mngCRC,
                                        stationNumber: stationNumber
                                    }    
                                }
                            }                               
                        }
                    }
                }
            }
        }
        else {
            console.log('getTriggerByCRC(): invalid inputs');
        } 
    } 
    
    /**
     * method is used to read pre and postsamples of trigger
     * @param {*} triggerCRC - crc of the trigger
     * @returns 
     */
    getPrePostSamples(triggerCRC) {
        //check valid inputs
        if (triggerCRC !== undefined) {
            //check if apis available
            if ((this.evtApi !== undefined) && (this.evtMedApi !== undefined)) {
                //get trigger data to send event to correct station
                const triggerData = this.getTriggerByCRC(triggerCRC);
                if (triggerData !== undefined) {
                    //send event to dmsstation
                    const buffer = new ArrayBuffer(this.getPrePostRequest.dataOffset + this.getPrePostRequest.size);
                    let dv = new DataView(buffer);
                    //set header
                    dv.setUint32(0, this.getPrePostRequest.version, true); //version
                    dv.setUint32(4, this.getPrePostRequest.dataOffset, true); //data offset
                    let tmpOffset = this.getPrePostRequest.dataOffset;
                    //add manager crc
                    dv.setUint32(tmpOffset, triggerData.managerCRC, true);
                    tmpOffset += 4;                    
                    //add stationnumber
                    dv.setUint32(tmpOffset, triggerData.stationNumber, true);
                    tmpOffset += 4;
                    //add trigger crc
                    dv.setUint32(tmpOffset, triggerCRC, true);
                    if (this._sendEvent(this.getPrePostRequest.minorID, triggerData.dmsStation, dv) !== true) {
                        console.log("getPrePostSamples(): get pre and postsamples failed");
                    }
                }
                else {
                    console.log('getPrePostSamples(): get trigger data failed')
                }
            }
            else {
                console.log('getPrePostSamples(): invalid apis');
            }
        }
        else {
            console.log('getPrePostSamples(): invalid inputs');
        } 
    } 

    /**
     * gets called if the response for getting pre and postsamples was received
     * @param {*} dv - dataview of event
     */
    _updatePrePost(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check for version
            const version = dv.getUint32(this.sigHeader, true); 
            if (version === this.getPrePostResponse.version) {
                //get dataoffset
                const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                //set offset behind header
                let tmpOffset = this.sigHeader + dataOffset;
                //fire event for updating graphs
                dispatchEvent(new CustomEvent('_DA_UPDATE_PREPOST', {
                    detail: {
                        triggerCRC: dv.getUint32(tmpOffset, true),
                        preSamples: dv.getUint32(tmpOffset + 4, true),
                        postSamples: dv.getUint32(tmpOffset + 8, true)
                    }
                }));                      
            }   
            else {
                console.log("_updatePrePost(): invalid version received");
            }        
        }
        else {
            console.log("_updatePrePost(): invalid dataview");
        } 
    }

    /**
     * gets called if the response for getting threshold was received
     * @param {*} dv - dataview of event
     */
     _updateThreshold(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check for version
            const version = dv.getUint32(this.sigHeader, true); 
            if (version === this.getThresholdResponse.version) {
                //get dataoffset
                const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                //set offset behind header
                let tmpOffset = this.sigHeader + dataOffset;
                const triggerCRC = dv.getUint32(tmpOffset, true);
                tmpOffset += 4;
                let threshold = dv.getInt32(tmpOffset, true); 
                //fire event for updating graphs
                dispatchEvent(new CustomEvent('_DA_UPDATE_THRESHOLD', {
                    detail: {
                        triggerCRC: triggerCRC,
                        threshold: threshold
                    }
                }));                      
            }   
            else {
                console.log("_updateThreshold(): invalid version received");
            }        
        }
        else {
            console.log("_updateThreshold(): invalid dataview");
        } 
    }

    /**
     * method is used to set pre and postsamples of trigger
     * @param {*} triggerCRC - crc of the trigger
     * @param {*} preSamples - presamples
     * @param {*} postSamples - postsamples
     * @returns 
     */
    setPrePostSamples(triggerCRC, preSamples, postSamples) {
        //check valid inputs
        if ((triggerCRC !== undefined) && (preSamples !== undefined) && (postSamples !== undefined)) {
            //check if apis available
            if ((this.evtApi !== undefined) && (this.evtMedApi !== undefined)) {
                //get trigger data to send event to correct station
                const triggerData = this.getTriggerByCRC(triggerCRC);
                if (triggerData !== undefined) {
                    //send event to dmsstation
                    const buffer = new ArrayBuffer(this.setPrePost.dataOffset + this.setPrePost.size);
                    let dv = new DataView(buffer);
                    //set header
                    dv.setUint32(0, this.setPrePost.version, true); //version
                    dv.setUint32(4, this.setPrePost.dataOffset, true); //data offset
                    let tmpOffset = this.setPrePost.dataOffset;
                    //add manager crc
                    dv.setUint32(tmpOffset, triggerData.managerCRC, true);
                    tmpOffset += 4;                    
                    //add stationnumber
                    dv.setUint32(tmpOffset, triggerData.stationNumber, true);
                    tmpOffset += 4;
                    //add trigger crc
                    dv.setUint32(tmpOffset, triggerCRC, true);
                    tmpOffset += 4;
                    //add presamples
                    dv.setUint32(tmpOffset, preSamples, true);
                    tmpOffset += 4; 
                    //add postsamples
                    dv.setUint32(tmpOffset, postSamples, true);                                       
                    if (this._sendEvent(this.setPrePost.minorID, triggerData.dmsStation, dv) !== true) {
                        console.log("setPrePostSamples(): set pre and postsamples failed");
                    }
                }
                else {
                    console.log('setPrePostSamples(): get trigger data failed')
                }
            }
            else {
                console.log('setPrePostSamples(): invalid apis');
            }
        }
        else {
            console.log('setPrePostSamples(): invalid inputs');
        } 
    }     

    /**
     * method is used to read threshold of trigger
     * @param {*} triggerCRC - crc of the trigger
     * @returns 
     */
     getThreshold(triggerCRC) {
        //check valid inputs
        if (triggerCRC !== undefined) {
            //check if apis available
            if ((this.evtApi !== undefined) && (this.evtMedApi !== undefined)) {
                //get trigger data to send event to correct station
                const triggerData = this.getTriggerByCRC(triggerCRC);
                if (triggerData !== undefined) {
                    //send event to dmsstation
                    const buffer = new ArrayBuffer(this.getThresholdRequest.dataOffset + this.getThresholdRequest.size);
                    let dv = new DataView(buffer);
                    //set header
                    dv.setUint32(0, this.getThresholdRequest.version, true); //version
                    dv.setUint32(4, this.getThresholdRequest.dataOffset, true); //data offset
                    let tmpOffset = this.getThresholdRequest.dataOffset;
                    //add manager crc
                    dv.setUint32(tmpOffset, triggerData.managerCRC, true);
                    tmpOffset += 4;                    
                    //add stationnumber
                    dv.setUint32(tmpOffset, triggerData.stationNumber, true);
                    tmpOffset += 4;
                    //add trigger crc
                    dv.setUint32(tmpOffset, triggerCRC, true);
                    if (this._sendEvent(this.getThresholdRequest.minorID, triggerData.dmsStation, dv) !== true) {
                        console.log("getThreshold(): get threshold failed");
                    }
                }
                else {
                    console.log('getThreshold(): get trigger data failed')
                }
            }
            else {
                console.log('getThreshold(): invalid apis');
            }
        }
        else {
            console.log('getThreshold(): invalid inputs');
        } 
    } 

    /**
     * method is used to set threshold of trigger
     * @param {*} triggerInfo - stationnumber and crc of the trigger
     * @param {*} threshold - threshold
     * @param {*} triggerChannel - trigger channel used to get threshold type
     * @returns 
     */
     setThreshold(triggerInfo, threshold, triggerChannel) {
        //check valid inputs
        if ((triggerInfo !== undefined) && (threshold !== undefined) && (triggerChannel !== undefined)) {
            //check if apis available
            if ((this.evtApi !== undefined) && (this.evtMedApi !== undefined)) {
                //get trigger data to send event to correct station
                const triggerData = this.getTriggerByCRC(triggerInfo.CRC);
                if (triggerData !== undefined) {
                    //get channel
                    const channel = this.getChannelByID(triggerInfo.stationNumber, triggerChannel);
                    if (channel !== undefined) {
                        //send event to dmsstation
                        const buffer = new ArrayBuffer(this.setTriggerThreshold.dataOffset + this.setTriggerThreshold.size);
                        let dv = new DataView(buffer);
                        //set header
                        dv.setUint32(0, this.setTriggerThreshold.version, true); //version
                        dv.setUint32(4, this.setTriggerThreshold.dataOffset, true); //data offset
                        let tmpOffset = this.setTriggerThreshold.dataOffset;
                        //add manager crc
                        dv.setUint32(tmpOffset, triggerData.managerCRC, true);
                        tmpOffset += 4;                        
                        //add stationnumber
                        dv.setUint32(tmpOffset, triggerInfo.stationNumber, true);
                        tmpOffset += 4;
                        //add trigger crc
                        dv.setUint32(tmpOffset, triggerInfo.CRC, true);
                        tmpOffset += 4;
                        //add threshold
                        //check for datatype of recorded value
                        switch (channel.dataType) {
                            case this.dataTypes.int8:
                            case this.dataTypes.int16:
                            case this.dataTypes.int32:
                                dv.setInt32(tmpOffset, threshold, true);
                                break;

                            case this.dataTypes.bool:
                            case this.dataTypes.uint8:
                            case this.dataTypes.uint16:
                            case this.dataTypes.uint32:
                                dv.setUint32(tmpOffset, threshold, true);
                                break;
                                
                            case this.dataTypes.float32:
                                dv.setFloat32(tmpOffset, threshold, true);
                                break;
                                
                            default:
                                console.log('setThreshold(): invalid datatype');
                                return;  
                        }                                                                
                        if (this._sendEvent(this.setTriggerThreshold.minorID, triggerData.dmsStation, dv) !== true) {
                            console.log("setThreshold(): set threshold failed");
                        }                            
                    }
                    else {
                        console.log("setThreshold(): get channel failed");
                    }
                }
                else {
                    console.log('setThreshold(): get trigger data failed')
                }
            }
            else {
                console.log('setThreshold(): invalid apis');
            }
        }
        else {
            console.log('setThreshold(): invalid inputs');
        } 
    } 

    /**
     * method gets called if invalid value update event was received
     * @param {*} dv - dataview of event
     */    
     _invalidValueUpdate(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {               
                 //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.invalidValueUpdate.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //check if station already exists
                    if (this.registerData !== undefined) {
                        //get station entry
                        let dmsStation = this.registerData.get(dmsStationNumber);
                        if (dmsStation !== undefined) {
                            //set offset behind header
                            let tmpOffset = this.sigHeader + dataOffset;                  
                            //get manager crc
                            const mngCRC = dv.getUint32(tmpOffset, true);
                            //check if manager exists
                            let manager = dmsStation.get(mngCRC);
                            if (manager !== undefined) {
                                tmpOffset += 4;
                                //get stationnumber
                                const stationNumber = dv.getUint32(tmpOffset, true);
                                tmpOffset += 4;
                                //get station
                                let station = manager.stations.get(stationNumber);
                                if (station !== undefined) {
                                    //get number of channels
                                    const noOfChannels = dv.getUint32(tmpOffset, true);
                                    tmpOffset += 4;
                                    //now go and get channels
                                    for (let j=0;j<noOfChannels;j++) {
                                        //get channelID as identifier key
                                        const channelID = dv.getUint32(tmpOffset, true);
                                        tmpOffset += 4;
                                        //get channel
                                        let channel = station.channels.get(channelID);
                                        if (channel !== undefined) {
                                            //set new group
                                            channel.invalidValue = this._getValueByType(dv, tmpOffset, channel.dataType);
                                            tmpOffset += 4;
                                        }
                                        else {
                                            console.log("_invalidValueUpdate(): channel not available");
                                            return;
                                        }
                                    }                                    
                                }
                                else {
                                    console.log("_invalidValueUpdate(): station not available");
                                }
                            }
                            else {
                                console.log("_invalidValueUpdate(): manager not available"); 
                            }
                        }
                        else {
                            console.log("_invalidValueUpdate(): dms station not available"); 
                        }
                    }
                    else {
                        console.log("_invalidValueUpdate(): no data registered");
                    }
                }   
                else {
                    console.log("_invalidValueUpdate(): invalid version received");
                }   
            }        
        }
        else {
            console.log("_invalidValueUpdate(): invalid dataview");
        }  
    }

    /**
     * method is used to get the channel reference of a visuchannel
     * @param {*} graphInstanceID - id of the graph the channel belongs to
     * @param {*} visuChlID - id of the visu channel
     */
    getChannelReference(graphInstanceID, visuChlID) {
        if ((graphInstanceID !== undefined) && (visuChlID !== undefined)) {
            //check if visuchannels available
            if (this.visuChlSettings !== undefined) {
                //get channels with graph id
                const visuChls = this.visuChlSettings.get(graphInstanceID);
                if (visuChls !== undefined) {
                    //get visu channel
                    const channel = visuChls.get(visuChlID);
                    if (channel !== undefined) {
                        return channel.chlReference;
                    }
                    else {
                        console.log('getChannelReference(): get channel failed');
                    }
                }
                else {
                    console.log('getChannelReference(): get channels failed');
                }                
            }
            else {
                console.log('getChannelReference(): no visuchannels available');
            }
        }
        else {
            console.log('getChannelReference(): invalid inputs');
        }
    }

    /**
     * method is used to get a value of a visu channel prop casted to the datatype used at real channel
     * @param {*} realChl - real channel reference
     * @param {*} channelProp - channel property to get value from
     */
    getCastedValue(realChl, channelProp) {
        //check inputs
        if ((realChl !== undefined) && (channelProp !== undefined)) {
            //check for constant api
            if (this.constApi !== undefined) {
                //get value
                let value = channelProp.value; 
                //check if property is datapoint
                if (channelProp.ref !== undefined) {
                    if (channelProp.src === this.constApi.PROP_SRC_DATAPOINT) {
                        //get type ref id of datapoint
                        const typeRefId = channelProp.ref.getTypeRefId();
                        //dataview used to cast datatypes of value
                        let valueDV = new DataView(new ArrayBuffer(4));
                        switch (typeRefId) {
                            //---------------------------------------------------------------------------------------------
                            //-- datapoint is a dint
                            //---------------------------------------------------------------------------------------------
                            case this.constApi.STD_TYPE_DINT:
                                //write uncasted values to dv
                                valueDV.setInt32(0, value);
                                break;

                            //---------------------------------------------------------------------------------------------
                            //-- datapoint is a udint
                            //---------------------------------------------------------------------------------------------
                            case this.constApi.STD_TYPE_UDINT:
                                //write uncasted values to dv
                                valueDV.setUint32(0, value);
                                break; 
                                
                            //---------------------------------------------------------------------------------------------
                            //-- datapoint is a real
                            //---------------------------------------------------------------------------------------------
                            case this.constApi.STD_TYPE_REAL:
                                //write uncasted values to dv
                                valueDV.setFloat32(0, value);
                                break;
                                
                            default:
                                console.log('getCastedValue(): invalid datapoint type');
                                return;    
                        }

                        //check for datatype of recorded value
                        switch (realChl.dataType) {
                            case this.dataTypes.int8:
                            case this.dataTypes.int16:
                            case this.dataTypes.int32:
                                value = valueDV.getInt32(0);
                                break;

                            case this.dataTypes.bool:
                            case this.dataTypes.uint8:
                            case this.dataTypes.uint16:
                            case this.dataTypes.uint32:
                                value = valueDV.getUint32(0);
                                break;
                                
                            case this.dataTypes.float32:
                                value = valueDV.getFloat32(0);
                                break;
                                
                            default:
                                console.log('getCastedValue(): invalid datatype');
                                return;  
                        }                        
                    }
                }
                return value;        
            }
            else {
                console.log('getCastedValue(): invalid constant api');
            }
        }   
        else {
            console.log('getCastedValue(): invalid inputs');
        }
    }

    /**
     * method is used to get the value casted to the datatype of the datapoint it should be written on
     * @param {*} realChl - real channel reference
     * @param {*} value - value which should be casted to dint
     * @param {*} dpRef - datapoint reference the value should be written on
     */
    getUncastedValue(realChl, value, dpRef) {
        //check inputs
        if ((realChl !== undefined) && (value !== undefined)) {
            let retValue = value;
            if (dpRef !== undefined) {
                //allocate dv for casting
                let valueDV = new DataView(new ArrayBuffer(4)); 
                //check for datatype of recorded value
                switch (realChl.dataType) {
                    case this.dataTypes.int8:
                    case this.dataTypes.int16:
                    case this.dataTypes.int32:
                        valueDV.setInt32(0, retValue);

                    case this.dataTypes.bool:
                    case this.dataTypes.uint8:
                    case this.dataTypes.uint16:
                    case this.dataTypes.uint32:
                        valueDV.setUint32(0, retValue);
                        break;
                        
                    case this.dataTypes.float32:
                        valueDV.setFloat32(0, retValue);
                        break;
                        
                    default:
                        console.log('getUncastedValue(): invalid datatype'); 
                        return; 
                }
                //get type ref id of datapoint
                const typeRefId = dpRef.getTypeRefId();
                switch (typeRefId) {
                    //---------------------------------------------------------------------------------------------
                    //-- datapoint is a dint
                    //---------------------------------------------------------------------------------------------
                    case this.constApi.STD_TYPE_DINT:
                        //get value casted to dint
                        retValue = valueDV.getInt32(0);
                        break;

                    //---------------------------------------------------------------------------------------------
                    //-- datapoint is a udint
                    //---------------------------------------------------------------------------------------------
                    case this.constApi.STD_TYPE_UDINT:
                        //get value casted to udint
                        retValue = valueDV.getUint32(0);
                        break;
                        
                    //---------------------------------------------------------------------------------------------
                    //-- datapoint is a real
                    //---------------------------------------------------------------------------------------------
                    case this.constApi.STD_TYPE_REAL:
                        //get value casted to real
                        retValue = valueDV.getFloat32(0);
                        break;
                        
                    default:
                        console.log('getUncastedValue(): invalid datapoint type');
                        return;    
                } 
            }
            return retValue;          
        }   
        else {
            console.log('getUncastedValue(): invalid inputs');
        }
    }

    /**
     * method is used to convert a value back to base units
     * @param {*} value - value which should be converted back
     * @param {*} unitInfo - unit property of the datapoint
     * @param {*} isFloatingPoint - value is evaluated as floating point
     */
     async convertValueBack(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) {
                        return await this.propApi.convertValueBackWithUnit(unitInfo.value, value, isFloatingPoint);
                    }
                    else if (unitInfo.src === this.constApi.PROP_SRC_SCHEME) {
                        const schemeVals = unitInfo.value.split(':');
                        return await this.propApi.convertValueBackWithUnitscheme(schemeVals[1], schemeVals[0], value, 0, isFloatingPoint, 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(':');
                            return await this.propApi.convertValueBackWithUnitscheme(schemeVals[1], schemeVals[0], value, unit, isFloatingPoint, false);                            
                        }
                        else {
                            console.log('_convertValueBack(): invalid constellation');
                        }
                    }
                }
                else {
                    console.log('_convertValueBack(): api not ready');
                }                
            }
            else {
                //value doesn't need to be converted back
                return value;
            }
        }
        else {
            console.log('_convertValueBack(): invalid value');
        }
    }

    /**
     * method is used to get limit values depending on datatype
     * @param {*} chlDataType - datatype of the channel values
     */
     getLimitValues(chlDataType) {
        if (chlDataType !== undefined) {
            //check for datatype of recorded value
            switch (chlDataType) {
                case this.dataTypes.int8:
                case this.dataTypes.int16:
                case this.dataTypes.int32:
                    return {
                        limitHigh: 2147483648,
                        limitLow: -2147483648
                    }

                case this.dataTypes.bool:
                case this.dataTypes.uint8:
                case this.dataTypes.uint16:
                case this.dataTypes.uint32:
                    return {
                        limitHigh: 4294967295,
                        limitLow: 0
                    }
                    
                case this.dataTypes.float32:
                    return {
                        limitHigh: 3.4 * Math.pow(10, 38),
                        limitLow: -3.4 * Math.pow(10, 38),                    
                    } 
                    
                default:
                    console.log('getLimitValues(): invalid datatype');  
            } 
        }
        else {
            console.log('getLimitValues(): invalid input', 'ERROR');
        }
    }

    /**
     * limit minimum and maximum value to limits of datatype
     * @param {*} chlDataType - datatype of the channel values
     * @param {*} minValue - minimum value which needs to be limited
     * @param {*} maxValue - maximum value which needs to be limited
     */
    limitValues(chlDataType, minValue, maxValue) {
        if ((chlDataType !== undefined) && (minValue !== undefined) && (maxValue !== undefined)) {
            const limitValues = this.getLimitValues(chlDataType);
            if (limitValues !== undefined) {
                let limitedValues = {
                    minValue: minValue,
                    maxValue: maxValue
                }
                if (limitedValues.maxValue > limitValues.limitHigh) {
                    limitedValues.maxValue = limitValues.limitHigh;
                }
                if (limitedValues.minValue < limitValues.limitLow) {
                    limitedValues.minValue = limitValues.limitLow;
                }
                return limitedValues;
            }
            else {
                console.log('limitValues(): failed to get limitvalues');
            }
        }
        else {
            console.log('limitValues(): invalid input parameters');
        }
    }

    /**
     * method is used to get infos of graph view instance like mode and divisions
     * @param {*} graphInstID - id of the graph view instance to get the infos of
     */
    getGraphViewInfos(graphInstID) {
        //check for valid input
        if (graphInstID !== undefined) {
            //check if instances logged in
            if ((this.graphViewInstances !== undefined) && (this.graphViewInstances.size > 0)) {
                //return the graphview instance -> if not logged in undefined will be returned
                return this.graphViewInstances.get(graphInstID);
            }
        }
        else {
            console.log('_convertValueBack(): invalid graphview instance');
        }
    }
    
    /**
     * method gets called if export channel names event was received
     * @param {*} dv - dataview of event
     */    
    async _exportRequestChannelNames(dv) {
        if (dv !== undefined) {
            //get stationnumber
            const dmsStationNumber = dv.getUint16(8, true);
            //check if station is management station -> getting a response of a non management station is possible in case of a single cpu solution
            //but there are two stations in lvd project for simple split up
            if (this.managementStations.includes(dmsStationNumber)) {               
                 //check for version
                const version = dv.getUint32(this.sigHeader, true); 
                if (version === this.exportChannelNameRequest.version) {
                    //get dataoffset
                    const dataOffset = dv.getUint32(this.sigHeader + 4, true);
                    //set offset behind header
                    let tmpOffset = this.sigHeader + dataOffset;
                    //get ManagerCRC 
                    const managerCRC = dv.getUint32(tmpOffset, true);
                    tmpOffset +=4;                  
                    //get number of ChannelIDs 
                    const numChannelIds = dv.getUint32(tmpOffset, true);
                    if (numChannelIds >= 0) {
                        tmpOffset +=4;
                        //get LanguageCode 
                        let LanguageCode = "";
                        for (let index = 0; index < 10; index++) {
                            let charCode = dv.getUint8(tmpOffset, true);
                            if (charCode != 0) {
                                LanguageCode += String.fromCharCode(charCode);
                            }
                            tmpOffset +=1;
                        }
                        //get Text Selection 
                        const textSelection = dv.getUint32(tmpOffset, true);
                        tmpOffset +=4;

                        let requestedChannels = [];
                        for (let index = 0; index < numChannelIds; index++) {
                            let channel = {};
                            channel.stationNumber =  dv.getUint32(tmpOffset, true);
                            tmpOffset +=4;
                            channel.chlID = dv.getUint32(tmpOffset, true);
                            tmpOffset +=4; 
                            requestedChannels.push(channel);
                        }
                        let infos = await this._exportCreateChannelInfos(LanguageCode,textSelection,requestedChannels);
                        this._sendExportChannelNames(dmsStationNumber,infos,managerCRC,'plc');
                    }
                    else {
                        console.log("_exportRequestChannelNames(): number of channels is invalid");
                    } 
                }   
                else {
                    console.log("_exportRequestChannelNames(): invalid version received");
                }   
            }        
        }
        else {
            console.log("_exportRequestChannelNames(): invalid dataview");
        }  
    }


    /**
     * gets called from sig-control-da-graphview if user wants to export the data
     *
     * @param {*} graphinstanceid - id of graph
     * @param {*} userData - Event parameter 
     *                              [0]..Language Code (string) 
     *                              [1]..Text Selection (Text1,Text2,Text3) 
     *                              [2]..Selection Mode 
     *                                      0..all channels of graphview
     *                                      1..active channels of graphview
     */
    async startExport(graphinstanceid,userData) {
        let requestedChannels = await this._exportCreateChannelInfosFromControl(graphinstanceid,userData[2]);
        if (requestedChannels) {
            if (requestedChannels.length > 0) {
                let dmsInfo = this.getDMSInfoByChannel(requestedChannels[0].stationNumber,requestedChannels[0].chlID);
                let infos = await this._exportCreateChannelInfos(userData[0],userData[1],requestedChannels);
                this._sendExportChannelNames(dmsInfo.stationNumber,infos,dmsInfo.crc,'visu');
            } else {
                console.log("startExport(): no channels selected - length");
            }
        } else {
            console.log("startExport(): no channels selected - undefined");
        }
       
    }

    /**
     * create the requested channel names for exporting
     */  
    async _exportCreateChannelInfosFromControl(graphinstanceid,mode) {
        //get visuchannels
        const visuChls = this.getVisuChannels(graphinstanceid);
        if ((visuChls !== undefined) && (visuChls.size > 0)) {
            let requestedChannels = [];
            for (let [visuChlID, channel] of visuChls) {
                let tmpchannel = {};
                if (channel.chlReference) {
                    if (mode == 0) {
                        tmpchannel.stationNumber =  channel.chlReference.stationNumber;
                        tmpchannel.chlID = channel.chlReference.chlID;
                        requestedChannels.push(tmpchannel);
                    } else {
                        if (channel.channelActive.value == 1) {
                            tmpchannel.stationNumber =  channel.chlReference.stationNumber;
                            tmpchannel.chlID = channel.chlReference.chlID;
                            requestedChannels.push(tmpchannel);
                        }
                    }    
                }
            }
            return requestedChannels;
        } else {
            return undefined;
            console.log("_exportCreateChannelInfos(): no visu channel registered");
        }
    }
                        

    /**
     * create the requested channel names for exporting
     */  
    async _exportCreateChannelInfos(languageCode,textSelection,requestedChannels) {
        
        let channelNameInfos = [];
        // determine language
        let languageIndex = await this._exportEvaluateLanguageIndex(languageCode);
        // determine text selection
        let textproperty = undefined;
        switch (textSelection) {
            case 1:
                textproperty = 'text1';
                break;
            case 2:
                textproperty = 'text2';
                break;

            case 3:
                textproperty = 'text3';
                break;

            default:
                textproperty = 'text1';
                break;
        }

        for (let index = 0; index < requestedChannels.length; index++) {
            const element = requestedChannels[index];
            let channelinfo = this.getChannelByID(element.stationNumber,element.chlID);
            let name = await this._exportCreateChannelName(element.stationNumber,channelinfo,languageIndex,textproperty);
            let nameInfos = {};
            nameInfos.chlID = element.chlID;
            nameInfos.channelName = name;
            nameInfos.stationNumber = element.stationNumber;
            channelNameInfos.push(nameInfos);
        }
        return channelNameInfos;
    }

    /**
     * get the languageIndex of ther requested LanguageCode
     */   
    async _exportEvaluateLanguageIndex(languageCode) {
        
        let actLanguage = await sigApi.textManager.getCurrentLanguageAsync();
        let languageIndex = actLanguage.languageIndex;
        if (languageCode != 'local') {
            let languages = await sigApi.textManager.getLanguages();
            for (let index = 0; index < languages.length; index++) {
                const element = languages[index];
                if (element.languageCode == languageCode) {
                    languageIndex = element.languageIndex;
                    return languageIndex;
                }
            }
        }
        return languageIndex;
    }

    /**
     * get the channel name of on visu channel
     */   
    async _exportCreateChannelName(stationNumber,channelinfo,languageIndex,textSelection) {
        let channelname = '';
        //get channel name
        try {                                          
            
            //get id of channel name datapoint
            let result = await this.datapointApi.getIdFromLasalId(channelinfo.chlNameLasalID, stationNumber);
            if ((result !== undefined) && (result[0] !== undefined)) {
                const varID = result[0];
                //get data point
                const datapoint = this.datapointApi.getDatapoint(varID);
                if (datapoint !== null) {
                    channelname = await datapoint.getValue();
                    if (channelname === '') {
                        //if no channelname configured, we take the var textSelection(text1,text2,text3) of the source
                        let dpProperty = sigApi.datapointManager.getDatapoint(channelinfo.srcVarID).getProperties();
                        let dpTextBluePrint = undefined;
                        switch (textSelection) {
                            case 'text1':
                                if (dpProperty?.text1) {
                                    dpTextBluePrint = dpProperty.text1;
                                }
                                else {
                                    channelname = sigApi.datapointManager.getDatapoint(channelinfo.srcVarID).getFullNameWithStation();
                                }
                                break;

                            case 'text2':
                                if (dpProperty?.text2){
                                    dpTextBluePrint = dpProperty.text2;
                                }
                                else {
                                    channelname = sigApi.datapointManager.getDatapoint(channelinfo.srcVarID).getFullNameWithStation();
                                }
                                break;

                            case 'text3':
                                if (dpProperty?.text3) {
                                    dpTextBluePrint = dpProperty.text3;
                                }
                                else {
                                    channelname = sigApi.datapointManager.getDatapoint(channelinfo.srcVarID).getFullNameWithStation();
                                }
                                break;
                        }
                        if (dpTextBluePrint != undefined) {
                            dpTextBluePrint.lang = languageIndex;
                            let dpText1Prop = sigApi.properties.createProperty(dpTextBluePrint);
                            channelname = dpText1Prop.getValue();
                            dpText1Prop.destroy();
                            dpText1Prop = undefined;
                            dpTextBluePrint = undefined;
                        }
                    }
                }
                else {
                    console.log("_exportCreateChannelName(): get datapoint failed");   
                    channelname = sigApi.datapointManager.getDatapoint(channelinfo.srcVarID).getFullNameWithStation();                                                                    
                }                                                         
            }   
            else {
                console.log("_exportCreateChannelName(): get varid failed"); 
                channelname = sigApi.datapointManager.getDatapoint(channelinfo.srcVarID).getFullNameWithStation();                                                                                                                                       
            }                                                                                                                                                                       
        }
        catch (error) {
            console.log('_exportCreateChannelName(): get channel name lasal id failed -> ' + error);
            channelname = sigApi.datapointManager.getDatapoint(channelinfo.srcVarID).getFullNameWithStation();                                                                    
        }
        return channelname;   
    }

    /**
     * Send requested channel names to station
     */         
    _sendExportChannelNames(station,channelNameInfos,managerCRC,mode) {
        if (station !== undefined) {
            // calculate length of needed buffer
            let length = 0;
            length += 4; // length of version
            length += 4; // length of managerCRC
            length += 4; // length of mode
            length += 4; // length of number of entries
            for (let index = 0; index < channelNameInfos.length; index++) {
                const element = channelNameInfos[index];
                length += 4; // length of ChannelId (element.chlID)
                length += 4; // length of StationNumber (element.stationNumber)
                length += 4; // length of String (element.channelName)
                let lenstring = this._getCharCodes(element.channelName);
                length += lenstring.length;
            }
            
            // create Buffer
            const buffer = new ArrayBuffer(length);
            let dv = new DataView(buffer);
            let offset = 0;

            
            // fill header
            dv.setUint32(offset, this.exportChannelNameResponse.version, true);  // fill version number
            offset +=4;
            dv.setUint32(offset, managerCRC, true);  //  fill ManagerCRC
            offset +=4;
            switch (mode) {
                case 'visu':
                    dv.setUint32(offset, 1, true);  //  fill mode
                    break;

                case 'plc':
                    dv.setUint32(offset, 0, true);  //  fill mode
                    break;
            }
            offset +=4;
            dv.setUint32(offset, channelNameInfos.length, true);  //  fill number of entries
            offset +=4;

            // set data
            for (let index = 0; index < channelNameInfos.length; index++) {
                const element = channelNameInfos[index];
                
                dv.setUint32(offset, element.stationNumber, true); //StationNumber (element.stationNumber)
                offset += 4; 

                dv.setUint32(offset, element.chlID, true); //ChannelId (element.chlID)
                offset += 4; 

                let stringChar = this._getCharCodes(element.channelName);
                dv.setUint32(offset, stringChar.length, true); // length of String (element.nameInfos)
                offset += 4;

                for (let index = 0; index < stringChar.length; index++) {
                    const element = stringChar[index];
                    dv.setUint8(offset, element, true); // one character of the string
                    offset +=1;
                }
            }
            
            //send data to stations
            if (this._sendEvent(this.exportChannelNameResponse.minorID, station, dv) !== true) {
                console.log("_sendExportChannelNames(): sending channel names response failed");
            }                 
        }  
        else {
            console.log("_sendExportChannelNames(): invalid stationnumber");
        }  
    }


    /****************************************************************************************************
     * methode converts a string to a array of character
     *
     * @param {*} stringToConvert - source string
     * @return [] - Array of Char
     ****************************************************************************************************/
    _getCharCodes(stringToConvert){
        let charCodeArr = [];
        for(let i = 0; i < stringToConvert.length; i++){
            let code = stringToConvert.charCodeAt(i);
            charCodeArr.push(code);
        }
        return charCodeArr;
    }

    /****************************************************************************************************
     * method is used to check which dms the channel belongs to
     *
     * @param {*} stationNumber - station number of the channel
     * @param {*} channelID - id of the channel
     * @return {Object} - containing information of the dms where the channel is handled
     * @memberof DA_DataManager
     ****************************************************************************************************/
    getDMSInfoByChannel(stationNumber, channelID) {
        //check if register data available
        if (this.registerData !== undefined) {
            //go through dms stations
            for (let [dmsStationNumber, dmsStation] of this.registerData) {
                //go through dms objects
                for (let [dmsCRC, dmsObject] of dmsStation) {
                    //check if das stations available
                    if (dmsObject.stations.size > 0) {
                        //check if station with searched station number is available
                        const station = dmsObject.stations.get(stationNumber);
                        if (station !== undefined) {
                            //check if channels available
                            if (station.channels.size > 0) {
                                //check if channel id available              
                                if (station.channels.has(channelID)) {
                                    return {stationNumber: dmsStationNumber, crc: dmsCRC, sendMode: dmsObject.sendMode};
                                }
                            }
                        }
                    }
                }
            }
        }
    }

}

//property-class for visu channel
class VisuChannel {
	constructor(props, constApi) {
        //check for valid props
        if ((props !== undefined) && (constApi !== undefined)) {
            //default channel selection -> no need to do complex property stuff simply save property structure
            this.recordMask = this._getComplexProp(props.recordMask, constApi, props.graphInstID, props.visuChlID, '_DA_RECORD_MASK_CHANGED');
            this.defaultChannel = props.defaultChl;
            this.selectedChannel = this._getComplexProp(props.selectedChl, constApi, props.graphInstID, props.visuChlID, '_DA_SELECTED_CHANNEL_CHANGED');
            this.channelActive = this._getComplexProp(props.channelActive, constApi, props.graphInstID, props.visuChlID, '_DA_CHANNEL_ACTIVE_CHANGED');
            this.scalePos = this._getComplexProp(props.scalePos, constApi, props.graphInstID, props.visuChlID, '_DA_SCALE_POSITION_CHANGED');
            this.splitView = this._getComplexProp(props.splitView, constApi, props.graphInstID, props.visuChlID, '_DA_SPLIT_VIEW_CHANGED');
            this.splitArea = this._getComplexProp(props.splitArea, constApi, props.graphInstID, props.visuChlID, '_DA_SPLIT_AREA_CHANGED');
            this.unitPos = this._getComplexProp(props.unitPos, constApi, props.graphInstID, props.visuChlID, '_DA_UNIT_POSITION_CHANGED');
            this.scaleType = this._getComplexProp(props.scaleType, constApi, props.graphInstID, props.visuChlID, '_DA_SCALE_TYPE_CHANGED');
            this.maxScale = this._getComplexProp(props.maxScale, constApi, props.graphInstID, props.visuChlID, '_DA_MAX_SCALE_CHANGED');
            this.minScale = this._getComplexProp(props.minScale, constApi, props.graphInstID, props.visuChlID, '_DA_MIN_SCALE_CHANGED');
            this.defaultColor = props.defaultColor;
            this.selectedColor = this._getComplexProp(props.selectedColor, constApi, props.graphInstID, props.visuChlID, '_DA_SELECTED_COLOR_CHANGED');
            this.lineWidth = this._getComplexProp(props.lineWidth, constApi, props.graphInstID, props.visuChlID, '_DA_LINE_WIDTH_CHANGED');
            this.lineStyle = this._getComplexProp(props.lineStyle, constApi, props.graphInstID, props.visuChlID, '_DA_LINE_STYLE_CHANGED');
            this.zeroLineActive = this._getComplexProp(props.zeroLineActive, constApi, props.graphInstID, props.visuChlID, '_DA_ZERO_LINE_ACTIVE_CHANGED');
            this.zeroLineOffset = this._getComplexProp(props.zeroLineOffset, constApi, props.graphInstID, props.visuChlID, '_DA_ZERO_LINE_OFFSET_CHANGED');
            this.valuePerDivision = this._getComplexProp(props.valuePerDivision, constApi, props.graphInstID, props.visuChlID, '_DA_VALUE_PER_DIVISION_CHANGED');
        }
        else {
            console.log("VisuChannel::constructor(): invalid input");
        }
	}

    /**
     * checks if property is datapoint and allocates observer if so
     * @param {*} prop - property which needs to be checked
     * @param {*} constApi - api for sig constants
     * @param {*} graphInstID - graph id the channel belongs to
     * @param {*} visuChlID - channel id
     * @param {*} event - event which should be fired if observer is called
     */
    _getComplexProp(prop, constApi, graphInstID, visuChlID, event) {
        //check if property is set
        if (prop !== undefined) {
            //check for valid inputs
            if ((constApi !== undefined) && (graphInstID !== undefined) && (visuChlID !== undefined) && (event !== undefined)) {
                let retProp = {
                    value: undefined,
                    ref: undefined,
                    src: prop.src
                };
                //check if datapoint, scheme or constant
                if ((prop.src === constApi.PROP_SRC_DATAPOINT) || (prop.src === constApi.PROP_SRC_SCHEME)) {
                    //it will be a complex prop
                    retProp = new VisuChannelProp(event, graphInstID, visuChlID);
                    //add observer to datapoint
                    prop.ref.addObserver(retProp.observer);
                    //set value for first time
                    retProp.value = prop.value;
                    //add datapoint as reverence
                    retProp.ref =  prop.ref;
                    //add source cause ref is different in structure as for datapoint or scheme
                    retProp.src = prop.src;
                }
                else if (prop.src === constApi.PROP_SRC_CONSTANT) {
                    //simply prop
                    retProp.value = prop.value;
                }
                else {
                    console.log("VisuChannel::_getComplexProp(): invalid property source");
                    return;
                }
                return retProp;
            }
            else {
                console.log("VisuChannel::_getComplexProp(): invalid input");
            }
        }
    }
}

//property-class for visu channel property
class VisuChannelProp {
	constructor(event, graphInstanceID, visuChlID) {
		this.observer = (value) => {
			this.value = value;
			dispatchEvent(new CustomEvent(event, {
				'detail': {
					instID: graphInstanceID,
					chlID: visuChlID,
					value: value
				}
			}));
		}
	}
}

//create directly cause we want the data and we want it now
DA_DataManager.requestInstance();