blob: af4d82d8355d9fc85e708c1fb9f3dc52208ed4a1 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
import { Component, OnInit, OnDestroy } from '@angular/core';
import { NavigatorService } from 'src/app/navigator/navigator.service';
import { MDMNotificationService } from 'src/app/core/mdm-notification.service';
import { Node } from '../../../navigator/node';
import { TYPE_CHANNEL, TYPE_CHANNELGROUP, TYPE_MEASUREMENT } from '../../model/constants';
import { Subscription, forkJoin } from 'rxjs';
import { NodeService } from 'src/app/navigator/node.service';
import { map, tap } from 'rxjs/operators';
import { MDMItem } from 'src/app/core/mdm-item';
import { ChartViewerService } from '../../services/chart-viewer.service';
@Component({
selector: 'app-xy-chart-viewer-nav-card',
templateUrl: './xy-chart-viewer-nav-card.component.html'
})
export class XyChartViewerNavCardComponent implements OnInit, OnDestroy {
public channels = new Map<string, Node[]>();
public channelGroups: Node[];
public measurement: Node;
private selectedNode: Node;
// Subscriptions
private selectedNodeSub: Subscription;
constructor(
private navigatorService: NavigatorService,
private notificationService: MDMNotificationService,
private nodeService: NodeService,
private chartViewerService: ChartViewerService) {}
ngOnInit() {
this.selectedNodeChanged(this.navigatorService.getSelectedNode());
this.selectedNodeSub = this.navigatorService.selectedNodeChanged.subscribe(
node => this.selectedNodeChanged(node),
error => this.notificationService.notifyError('details.mdm-detail-view.cannot-update-node', error)
);
}
ngOnDestroy() {
this.selectedNodeSub.unsubscribe();
}
/**
* Handle node selection in navigation tree.
* Loads necessary data for xy chart, if not present:
* - Measurement:
* + Loaded if a channel or channelgroup is selected that is not present.
* + Also loads all channels and channelgroups for that measurement.
* - Channelgroups:
* + Loaded if a measurement is selected/loaded that is not present.
* + Also loads all channels for all newly loaded channelgroups.
* - Channels:
* + Allways loaded if some node is not present.
*
* @param node the selected node
*/
private selectedNodeChanged(node: Node) {
this.selectedNode = node;
if (node != undefined) {
switch (node.type) {
case TYPE_MEASUREMENT:
this.selectedMeasurement(node);
break;
case TYPE_CHANNELGROUP:
this.selectedChannelGroup(node);
break;
case TYPE_CHANNEL:
this.selectedChannel(node);
break;
}
}
}
// reload all, if channel is not present yet.
private selectedChannel(node: Node) {
if (!this.isChannelPresent(node)) {
this.loadMeasurement(node);
} else {
this.chartViewerService.sendNodeMeta(this.selectedNode);
}
}
private selectedChannelGroup(node: Node) {
if (!this.isChannelGroupPresent(node)) {
this.loadMeasurement(node);
} else {
this.chartViewerService.sendNodeMeta(this.selectedNode);
}
}
private selectedMeasurement(node: Node) {
if (this.measurement == undefined || this.measurement.id !== node.id) {
this.measurement = node;
this.loadChannelGroups(node);
} else {
this.chartViewerService.sendNodeMeta(this.selectedNode);
}
}
private isChannelPresent(node: Node) {
if (this.channels != undefined) {
/**
* @TODO more readable code, but got the impression that performance is bad. Read up on performance topic in depth.
*/
// Array.from(this.channels.values())
// .reduce((a,b) => a.concat(b), [])
// .findIndex(c => c.id === node.id);
let index = -1;
const iterator = this.channels.values();
let res = iterator.next();
while (index === -1 && !res.done) {
index = res.value.findIndex(c => c.id === node.id);
res = iterator.next();
}
return index > -1;
}
return false;
}
private isChannelGroupPresent(node: Node) {
if (this.channelGroups != undefined) {
return this.channelGroups.findIndex(channelGroup => channelGroup.id === node.id) > -1;
}
return false;
}
private loadMeasurement(node: Node) {
this.searchNodes(node, TYPE_MEASUREMENT)
.pipe(
/** @TODO in general true? */
// parent measurement must be distinct
map(measurements => measurements[0]),
).subscribe(measurement => {
this.measurement = measurement;
this.loadChannelGroups(this.measurement);
});
}
private loadChannelGroups(measurement: Node) {
this.searchNodes(measurement, TYPE_CHANNELGROUP)
.subscribe(channelGroups => {
this.channelGroups = channelGroups;
if (this.channelGroups != undefined) {
this.loadChannels(channelGroups);
}
});
}
private loadChannels(channelGroups: Node[]) {
this.channels.clear();
let obsArray = channelGroups.map(channelGroup => this.searchNodes(channelGroup, TYPE_CHANNEL));
forkJoin(obsArray).pipe(
tap(array => array.forEach((channels, index) => this.channels.set(channelGroups[index].id, channels)))
).subscribe(datasets => this.chartViewerService.sendNodeMeta(this.selectedNode));
}
private searchNodes(node: Node, targetType: string) {
const filter = 'filter=' + node.type + '.Id eq \"' + node.id + '\"';
return this.nodeService.searchNodes(filter, node.sourceName, targetType);
}
}