/*-------------------------------------------------------------------------------------------------------------- * Copyright (c) insite-gmbh. All rights reserved. * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------------------------*/ import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { InaxAlarmService, AlarmListChangeEvent, IHmiAlarmEntry } from '../../../../@inax/alarm'; import { InaxTranslateService } from '../../../../@inax/translate'; import { Subscription } from 'rxjs/Rx'; import { MotionUiResourceManager } from './../resources/resource.service'; import { InaxMotionService } from './../../../motion/src/motion'; import { IMotionEx } from './../../../motion/src/domain/motion'; import { MovingDirection } from './../../../motion/src/domain/movingDirection'; import { MethodPropertyChangeEvent } from './../../../script/src/domain/propertyChangedEvent'; import { IPlcEventProxy } from '../../../plc/src/domain/plcEventProxy'; import { DataChangeEvent } from '../../../plc/src/domain/dataChangedEvent'; import { IUdtMotion } from '../../../motion/src/domain/udtMotion'; import { IFinalPositionEx } from '../../../motion/src/domain/finalPosition'; import { ViewMode } from '../../../motion/src/domain/viewMode'; import { InaxMotionTextsService } from '../../../motion/src/motionTexts'; import { Converter } from '../../../plc/src/converter'; import { InViewInfo } from '../../../commonUi/src/inView/inViewInfo'; enum LineState { NotSelected, Selecting, Selected }; @Component({ selector: 'motion-line', templateUrl: './@inax/motionUi/src/motionLine/motionline.component.html', styleUrls: ['./@inax/motionUi/src/motionLine/motionline.component.css'] }) export class MotionLineComponent implements OnInit, OnDestroy { private _neededVariables: Array = ["MovingState1", "MovingState2", "Executability1", "Executability2", "NumberOfFinalPosition", "HmiId", "FinalPosition"]; private _movingSubscription: Subscription; private _selectionSubscription: Subscription; private _activeDirection: MovingDirection = MovingDirection.None; private _lineState: LineState = LineState.NotSelected; private _timeToTakeover: number = 0; private _eventProxy: IPlcEventProxy; private _selectedMotion: IMotionEx; private _changeSubscription: Subscription; @Input() public motion: IMotionEx; @Input() public set selectedMotion(value: IMotionEx) { if (this._selectedMotion != value) { this._selectedMotion = value; if (value == this.motion) this.activateLine(); else this.deactivateLine(); } } public get selectedMotion(): IMotionEx { return this._selectedMotion; } @Input() public viewMode: ViewMode; @Output() public deselect: EventEmitter = new EventEmitter(); public showStateLine: boolean; public get udtMotion(): IUdtMotion { return this.motion.UdtModiondata; } public get timeToTakeover(): number { return this._timeToTakeover; } public get lineState(): LineState { return this._lineState; } public get movingDirection(): MovingDirection { return this._activeDirection; } public get takeoverRequested(): boolean { return this.lineState == LineState.Selected && this.timeToTakeover > 0 } public get currentHmiId(): number { return this.udtMotion.HmiId; } public get visibleFinalPositions(): Array { return this.motion.FinalPositions.slice(0, this.udtMotion.NumberOfFinalPosition); } public get isSelecting(): boolean { return this.lineState == LineState.Selecting; } public get isSelected(): boolean { return this.lineState == LineState.Selected; } public get isMovingToTheRight(): boolean { return this.movingDirection == MovingDirection.Right; } public get isMovingToTheLeft(): boolean { return this.movingDirection == MovingDirection.Left; } public get otherHmi(): boolean { return !this.isSelected && this.motion.OtherHmiId && !this.motion.MotionIsLocked } public get isLocked(): boolean { return this.motion.MotionIsLocked; } public get showTakeoverPanel(): boolean { return !this.motion.OtherHmiId && this.takeoverRequested; } public get showTakeoverTime(): boolean { return this.motion.OtherHmiId && this.isSelecting; } public get isLeftButtonDisabled(): boolean { return ((!this.udtMotion.Executability1 || this.isSelecting || this.motion.MotionIsLocked) && !this.isMovingToTheLeft) } public get isRightButtonDisabled(): boolean { return ((!this.udtMotion.Executability2 || this.isSelecting || this.motion.MotionIsLocked) && !this.isMovingToTheRight); } public get showExternalContent(): boolean { return this.isSelected && !this.motion.MotionIsLocked; } public get inViewId(): string { return this.motion.MappingName; } constructor(private _inaxMotion: InaxMotionService, private _inaxTranslate: InaxTranslateService, private _cdr:ChangeDetectorRef) { } ngOnInit() { //subscribe to the services this.createProxy(); } ngOnDestroy() { //unsubscribe from the services this.disposeSelection(); this.disposeMoving(); if (this._changeSubscription) this._changeSubscription.unsubscribe(); if (this._eventProxy) this._eventProxy.dispose(); } /** * This method will be called if the line selection state changes */ public onSelectionChange(isSelected: boolean) { if (isSelected) { this.activateLine(); } else { this.deactivateLine(); } } /** * This method will be called i the line is out of view */ public onViewStateChanges(inViewInfo: InViewInfo) { console.log(`line: ${inViewInfo.id} linestate: ${this.lineState} in View: ${inViewInfo.inView}`); if (this.lineState == LineState.NotSelected) return; if (!inViewInfo.inView) { //this is necessary because of double check of angular. setTimeout(() => this.deactivateLine()); } } /** * This method will be called if one of the moving buttons will be pressed */ public onStartMoving(direction: MovingDirection) { //check selection if (this.selectedMotion != null && this.selectedMotion.Id == this.motion.Id) { if (this._activeDirection == direction) return; // already moving in this direction this._activeDirection = direction; if (this._activeDirection != MovingDirection.None) { this.disposeMoving(); this._movingSubscription = this._inaxMotion.startMoving(this.motion, this.directionNumber(direction)) .subscribe((event) => { this.onScriptEvent(event); }); } } } /** * This method will be called if one of the moving buttons will be released */ public onStopMoving(direction: MovingDirection) { if (this.lineState == LineState.NotSelected) return; this._inaxMotion.stopMoving(this.motion, this.directionNumber(direction)); this._activeDirection == MovingDirection.None; this.disposeMoving(); } /** * This method will be called if the user clicks the permit takeover button. */ public onPermitTakeover() { if (this.lineState == LineState.NotSelected) return; this._inaxMotion.permitTakeover(this.motion); } /** * This method will be called if the user clicks the refuse takeover button. */ public onRefuseTakeover() { if (this.lineState == LineState.NotSelected) return; this._inaxMotion.refuseTakeover(this.motion); } private directionNumber(direction: MovingDirection): MovingDirection { if (this.lineState == LineState.NotSelected) return 0; return direction == 1 ? 1 : 2; } private createProxy() { if (this._eventProxy != null) { this._eventProxy.dispose(); this._eventProxy = null; } this._eventProxy = this._inaxMotion.createMotionProxy(this.motion, this._neededVariables); this._changeSubscription = this._eventProxy.ChangeEvent.subscribe( (dce: DataChangeEvent) => this.updateMotionProperties(dce), (error: any) => { console.warn("Attempt to join channel failed!", error); } ); } private activateLine() { if (this.lineState == LineState.NotSelected) { this._timeToTakeover = 0; this.disposeSelection(); this._lineState = LineState.Selecting; this._selectionSubscription = this._inaxMotion.selectMotion(this.motion) .subscribe((event) => { this.onScriptEvent(event); }); } } private deactivateLine() { if (this.lineState != LineState.NotSelected) { this._timeToTakeover = 0; this._lineState = LineState.NotSelected; this.selectedMotion = null; this.deselect.emit(this.motion); this.disposeSelection(); } } private onScriptEvent(event: MethodPropertyChangeEvent) { if (event.IsFinished) { this._activeDirection == MovingDirection.None; if (event.CallerInfo != null) { if (event.CallerInfo.FunctionName == "StartSelection") { this.deactivateLine(); } else if (event.CallerInfo.FunctionName == "StartMoving") { console.log(`StartMoving finished`); } } } else if (event.Event != null) { for (let i: number = 0; i < event.Event.Properties.length; i++) { let property: string = event.Event.Properties[i]; let value: any = event.Event.Values[i]; //console.log(`function: ${event.CallerInfo.FunctionName}=>property:${property}=${value}`); if (event.CallerInfo != null && event.CallerInfo.FunctionName == "StartSelection") { if ((this.lineState == LineState.Selected || this.lineState == LineState.Selecting) && property == "SelectedSlotId" && value == 0) { this._inaxMotion.signalOngoingSelection(this.motion); } else if (property == "SelectedSlotId_TakeoverTime" && value > -1) { this._timeToTakeover = Math.round(value / 10); } } else if (event.CallerInfo != null && event.CallerInfo.FunctionName == "StartMoving") { let dir = this.directionNumber(this._activeDirection); if (this.lineState == LineState.Selected && (property == `PressedButton${Number(dir)}SlotId` && value == 0)) { this._inaxMotion.signalOngoingMovement(this.motion, dir); console.log(`signal ongoing!`); } } else { } } } } private disposeSelection() { if (this._selectionSubscription != null && !this._selectionSubscription.closed) this._selectionSubscription.unsubscribe(); } private disposeMoving() { if (this._movingSubscription != null && !this._movingSubscription.closed) this._movingSubscription.unsubscribe(); } private updateMotionProperties(dce: DataChangeEvent) { try { let expectedMapping = `${this.motion.Plc}.${this.motion.MappingName}`; if (dce.Mapping == expectedMapping) { for (let [key, value] of Converter.flatten(dce.Data)) { if (key == "MovingState1") { this.udtMotion.MovingState1 = value; } else if (key == "MovingState2") { this.udtMotion.MovingState2 = value; } else if (key == "Executability1") { this.udtMotion.Executability1 = value; } else if (key == "Executability2") { this.udtMotion.Executability2 = value; } else if (key == "NumberOfFinalPosition") { this.udtMotion.NumberOfFinalPosition = value; } else if (key == "HmiId") { this.udtMotion.HmiId = value; this.motion.OtherHmiId = value != 0 && value != this._inaxMotion.HmiId; this._lineState = value == this._inaxMotion.HmiId ? LineState.Selected : LineState.NotSelected; } else if (key.startsWith("FinalPosition")) { let idx = key.substring(key.lastIndexOf(".") + 1); if (idx.length > 0) { let index = Number(idx); if (index >= 0 && index <= 15) { this.motion.FinalPositions[index].PositionFlagged = value; } } } } } } catch (error) { console.warn(`Error updating data! ${error}`); } } }