Angular upgrade
[osm/NG-UI.git] / src / app / packages / ns-packages / ns-composer / NSComposerComponent.ts
1 /*
2  Copyright 2020 TATA ELXSI
3
4  Licensed under the Apache License, Version 2.0 (the 'License');
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8   http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15
16  Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
17 */
18 /**
19  * @file NS Compose Component
20  */
21 import { HttpHeaders } from '@angular/common/http';
22 import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
23 import { ActivatedRoute, Router } from '@angular/router';
24 import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
25 import { TranslateService } from '@ngx-translate/core';
26 import { NotifierService } from 'angular-notifier';
27 import { APIURLHEADER, CONSTANTNUMBER, ERRORDATA, MODALCLOSERESPONSEDATA, MODALCLOSERESPONSEWITHCP } from 'CommonModel';
28 import { ConfirmationTopologyComponent } from 'ConfirmationTopology';
29 import * as d3 from 'd3';
30 import { DataService } from 'DataService';
31 import { environment } from 'environment';
32 import * as HttpStatus from 'http-status-codes';
33 import * as jsyaml from 'js-yaml';
34 import {
35   CCI,
36   COMPOSERNODES,
37   DF,
38   GRAPHDETAILS,
39   NSData,
40   NSDATACREATION,
41   NSDDetails,
42   Tick, TickPath, VLC, VLD, VNFPROFILE
43 } from 'NSDModel';
44 import { RestService } from 'RestService';
45 import { SharedService, isNullOrUndefined } from 'SharedService';
46 import { VNFD, VNFData } from 'VNFDModel';
47
48 /**
49  * Creating component
50  * @Component takes NSComposerComponent.html as template url
51  */
52 @Component({
53   selector: 'app-ns-composer',
54   templateUrl: './NSComposerComponent.html',
55   styleUrls: ['./NSComposerComponent.scss'],
56   encapsulation: ViewEncapsulation.None
57 })
58 /** Exporting a class @exports NSComposerComponent */
59 export class NSComposerComponent {
60   /** To inject services @public */
61   public injector: Injector;
62   /** View child contains graphContainer ref @public  */
63   @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
64   /** dataService to pass the data from one component to another @public */
65   public dataService: DataService;
66   /** Contains VNFD Informations @public */
67   public nsPackageDetails: NSData = { id: '', name: '', description: '', version: '', designer: '' };
68   /** Contains VL Details @public */
69   public virtualLinkDesc: VLD = {
70     id: '',
71     'mgmt-network': true
72   };
73   /** Contains the information of the type of modification @public  */
74   public putType: string;
75   /** Contains index of old VLD @public  */
76   public getOldVLDIndex: string[];
77   /** Conatins mousedown action @public */
78   public mousedownNode: COMPOSERNODES = null;
79   /** Conatins mouseup action @public */
80   public mouseupNode: COMPOSERNODES = null;
81   /** Conatins mousedownLink action @public */
82   public mousedownLink: COMPOSERNODES = null;
83   /** Conatins current Selection node action @public */
84   public currentSelectedNode: COMPOSERNODES = null;
85   /** Conatins current Selection node action @public */
86   public currentSelectedLink: COMPOSERNODES = null;
87   /** Need to show the NSD Details @public */
88   public isShowNSDDetails: boolean = true;
89   /** Contains the node information of VL @public */
90   public vlNodes: {}[] = [];
91   /** Need to show the VL Details @public */
92   public isShowVLDetails: boolean = false;
93   /** Contains the node information of VNF @public */
94   public vnfNodes: {}[] = [];
95   /** contains the VNF Details @public */
96   public vnfData: VNFPROFILE;
97   /** contains the Virtual Link connectivity Details @public */
98   public virtualLinkProfileID: string;
99   /** Need to show the VNF Details @public */
100   public isShowVNFDetails: boolean = false;
101   /** Contains the node information of CP @public */
102   public cpNodes: {}[] = [];
103   /** Need to show the CP Details */
104   public cpData: CCI;
105   /** Need to show the VNF Details @public */
106   public isShowCPDetails: boolean = false;
107   /** random number count @public */
108   public randomNumberLength: number;
109   /** Contains the vnfd information @public */
110   public vnfList: VNFD[] = [];
111   /** Add the activeclass for the selected @public */
112   public activeClass: string = 'active';
113   /** Add the fixed class for the freeze @public */
114   public fixedClass: string = 'fixed';
115   /** Check the loading results @public */
116   public isLoadingResults: boolean = true;
117   /** Give the message for the loading @public */
118   public message: string = 'PLEASEWAIT';
119   /** Get VNF selected node @public */
120   public getVNFSelectedData: VNFD;
121   /** Assign the forcesimulation active @public */
122   public forceSimulationActive: boolean = false;
123   /** Assign pinned class for the button when freezed @public */
124   public classApplied: boolean = false;
125   /** Contains sidebar open status @public */
126   public sideBarOpened: boolean = false;
127   /** Contains SVG attributes @private */
128   // eslint-disable-next-line @typescript-eslint/no-explicit-any
129   private svg: any;
130   /** Contains the Drag line */
131   // eslint-disable-next-line @typescript-eslint/no-explicit-any
132   private dragLine: any;
133   /** Contains VL node @private */
134   // eslint-disable-next-line @typescript-eslint/no-explicit-any
135   private vlNode: any;
136   /** Contains VNFD node @private */
137   // eslint-disable-next-line @typescript-eslint/no-explicit-any
138   private vnfdnode: any;
139   /** Contains CP node @private */
140   // eslint-disable-next-line @typescript-eslint/no-explicit-any
141   private cpnode: any;
142   /** Rendered nodes represent VL @private */
143   // eslint-disable-next-line @typescript-eslint/no-explicit-any
144   private gvlNode: any;
145   /** Rendered nodes represent VL @private */
146   // eslint-disable-next-line @typescript-eslint/no-explicit-any
147   private gvnfdNode: any;
148   /** Rendered nodes represent VL @private */
149   // eslint-disable-next-line @typescript-eslint/no-explicit-any
150   private gcpNode: any;
151   /** Contains forced node animations @private */
152   // eslint-disable-next-line @typescript-eslint/no-explicit-any
153   private force: any;
154   /** Contains all the selected node @private */
155   private selectedNode: COMPOSERNODES[] = [];
156   /** Contains the connected point @private */
157   private connectionPoint: string;
158   /** Contains id of the node @private */
159   private identifier: string;
160   /** Contains copy of NSD information @private */
161   private nsdCopy: string;
162   /** Contains the VNFD copy @private */
163   private vnfdCopy: string;
164   /** Contains path information of the node */
165   // eslint-disable-next-line @typescript-eslint/no-explicit-any
166   private path: any;
167   /** Contains the node information @private */
168   private nodes: COMPOSERNODES[] = [];
169   /** Contains the link information of nodes @private */
170   private links: {}[] = [];
171   /** Contains the NS information @private */
172   private nsData: NSDDetails;
173   /** Instance of the rest service @private */
174   private restService: RestService;
175   /** Service holds the router information @private */
176   private router: Router;
177   /** Holds teh instance of AuthService class of type AuthService @private */
178   private activatedRoute: ActivatedRoute;
179   /** Notifier service to popup notification @private */
180   private notifierService: NotifierService;
181   /** Controls the header form @private */
182   private headers: HttpHeaders;
183   /** Contains tranlsate instance @private */
184   private translateService: TranslateService;
185   /** Contains lastkeypressed instance @private */
186   private lastKeyDown: number = -1;
187   /** Instance of the modal service @private */
188   private modalService: NgbModal;
189   /** Setting the Value of connection point refrence of the CP @private */
190   private setVnfdConnectionPointRef: string;
191   /** Setting the Value of VL name for confirmation @private */
192   private vlName: string;
193   /** Setting the Value of VNFD name for confirmation @private */
194   private setVnfdName: string;
195   /** Contains all methods related to shared @private */
196   private sharedService: SharedService;
197   /** Contains selected node VNF profile objects @private */
198   private selectedVNFProfile: VNFPROFILE[];
199
200   constructor(injector: Injector) {
201     this.injector = injector;
202     this.restService = this.injector.get(RestService);
203     this.dataService = this.injector.get(DataService);
204     this.router = this.injector.get(Router);
205     this.activatedRoute = this.injector.get(ActivatedRoute);
206     this.notifierService = this.injector.get(NotifierService);
207     this.translateService = this.injector.get(TranslateService);
208     this.modalService = this.injector.get(NgbModal);
209     this.sharedService = this.injector.get(SharedService);
210   }
211   /** Lifecyle Hooks the trigger before component is instantiated @public */
212   public ngOnInit(): void {
213     this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
214     this.generateData();
215     this.headers = new HttpHeaders({
216       'Content-Type': 'application/gzip',
217       Accept: 'application/json',
218       'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
219     });
220   }
221   /** Events handles at drag on D3 region @public */
222   // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
223   public drag(ev: any): void {
224     if (ev.target.id === 'vl') {
225       ev.dataTransfer.setData('text', ev.target.id);
226     } else {
227       ev.dataTransfer.setData('text', ev.target.attributes['data-id'].value);
228     }
229   }
230   /** On clicking redirect to NS edit page @public */
231   public onEdit(): void {
232     this.router.navigate(['/packages/ns/edit/', this.identifier]).catch((): void => {
233       // Catch Navigation Error
234     });
235   }
236   /** Events handles drop at D3 region @public */
237   public drop(ev: DragEvent): void {
238     ev.preventDefault();
239     const getDropedName: string = ev.dataTransfer.getData('text');
240     if (getDropedName === 'vl') {
241       this.svg.selectAll('*').remove();
242       this.vldropComposer();
243     } else {
244       this.svg.selectAll('*').remove();
245       const vnfdName: string = ev.dataTransfer.getData('text');
246       this.vnfdropComposer(vnfdName);
247     }
248   }
249   /** Drop VL Composer Data @public */
250   public vldropComposer(): void {
251     this.randomNumberLength = CONSTANTNUMBER.randomNumber;
252     const generateId: string = 'ns_vl_' + this.sharedService.randomString();
253     if (this.nsData['virtual-link-desc'] === undefined) {
254       this.nsData['virtual-link-desc'] = [];
255     }
256     this.nsData['virtual-link-desc'].push({
257       id: generateId,
258       'mgmt-network': false
259     });
260     this.putType = 'nsdadd';
261     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
262   }
263   /** Drop VNFD Composer Data @public */
264   public vnfdropComposer(vnfdName: string): void {
265     const vnfID: string = 'ns_vnfd_' + this.sharedService.randomString();
266     if (this.nsData.df.length > 0) {
267       this.addVNFDID(vnfdName);
268       this.nsData.df.forEach((res: DF): void => {
269         if (res['vnf-profile'] === undefined) {
270           res['vnf-profile'] = [];
271         }
272         res['vnf-profile'].push({
273           id: vnfID,
274           'virtual-link-connectivity': [],
275           'vnfd-id': vnfdName
276         });
277       });
278     } else {
279       Object.assign(this.nsData.df, {
280         id: 'default-df',
281         'vnf-profile': [{
282           id: vnfID,
283           'virtual-link-connectivity': [],
284           'vnfd-id': vnfdName
285         }]
286       });
287     }
288     this.putType = 'vnfdadd';
289     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
290   }
291   /** Add the VNFD-ID while drop VNFD if not exists @public */
292   public addVNFDID(vnfdName: string): void {
293     const vnfdIDArray: string[] = this.nsData['vnfd-id'];
294     if (vnfdIDArray !== undefined) {
295       if (vnfdIDArray.indexOf(vnfdName) === -1) {
296         vnfdIDArray.push(vnfdName);
297       }
298     } else {
299       Object.assign(this.nsData, {
300         'vnfd-id': [vnfdName]
301       });
302     }
303   }
304   /** Events handles allow drop on D3 region @public */
305   public allowDrop(ev: DragEvent): void {
306     ev.preventDefault();
307   }
308   /** Save NSD Information @public */
309   public saveNSD(): void {
310     if (this.nsPackageDetails.id !== undefined) {
311       this.nsData.id = this.nsPackageDetails.id;
312     }
313     if (this.nsPackageDetails.name !== undefined) {
314       this.nsData.name = this.nsPackageDetails.name;
315     }
316     if (this.nsPackageDetails.description !== undefined) {
317       this.nsData.description = this.nsPackageDetails.description;
318     }
319     if (this.nsPackageDetails.version !== undefined) {
320       this.nsData.version = this.nsPackageDetails.version;
321     }
322     if (this.nsPackageDetails.designer !== undefined) {
323       this.nsData.designer = this.nsPackageDetails.designer;
324     }
325     this.putType = 'nsdUpdate';
326     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
327   }
328   /** Save Virtual Link @public */
329   public saveVL(vlid: string): void {
330     this.nsData['virtual-link-desc'].forEach((result: VLD): void => {
331       if (result.id === vlid) {
332         result['mgmt-network'] = !isNullOrUndefined(this.virtualLinkDesc['mgmt-network']) ? this.virtualLinkDesc['mgmt-network'] : true;
333       }
334     });
335     this.putType = 'vlUpdate';
336     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
337   }
338   /** Add the new Data @public */
339   public addData(apiURL: string, identifier: string, data: NSDDetails, putType: string): void {
340     this.isLoadingResults = true;
341     let successMessage: string = '';
342     if (putType === 'nsdadd') {
343       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNSD';
344     } else if (putType === 'vnfdadd') {
345       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDVNFD';
346     } else if (putType === 'cpAdded') {
347       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNS';
348     } else if (putType === 'nsdUpdate') {
349       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
350     } else if (putType === 'vlUpdate') {
351       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
352     } else if (putType === 'nsddelete') {
353       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENSD';
354     } else if (putType === 'vnfddelete') {
355       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETEVNFD';
356     } else if (putType === 'nsdelete') {
357       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENS';
358     } else if (putType === 'linkdelete') {
359       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETELINK';
360     }
361     /** Below hide for conflicts with light weight UI */
362     const apiURLHeader: APIURLHEADER = {
363       url: apiURL + '/' + identifier + '/nsd_content',
364       httpOptions: { headers: this.headers }
365     };
366     const nsData: NSDATACREATION = { nsd: { nsd: [] } };
367     nsData.nsd.nsd = [];
368     nsData.nsd.nsd.push(data);
369     const descriptorInfo: string = jsyaml.dump(nsData, { sortKeys: true });
370     this.sharedService.targzFile({ packageType: 'nsd', id: this.identifier, descriptor: descriptorInfo })
371       .then((content: ArrayBuffer): void => {
372         this.restService.putResource(apiURLHeader, content).subscribe((res: {}): void => {
373           this.generateData();
374           this.notifierService.notify('success', this.translateService.instant(successMessage));
375           this.isLoadingResults = false;
376         }, (error: ERRORDATA): void => {
377           this.generateData();
378           this.restService.handleError(error, 'put');
379           this.isLoadingResults = false;
380         });
381       }).catch((): void => {
382         this.notifierService.notify('error', this.translateService.instant('ERROR'));
383         this.isLoadingResults = false;
384       });
385   }
386   /** Show Info @public */
387   public showInfo(): void {
388     // eslint-disable-next-line security/detect-non-literal-fs-filename
389     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
390     modalRef.componentInstance.topologyType = 'Info';
391     modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
392     modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
393       if (result) {
394         // empty
395       }
396     }).catch((): void => {
397       // Catch Navigation Error
398     });
399   }
400   /** Event to freeze the animation @public */
401   public onFreeze(): void {
402     this.classApplied = !this.classApplied;
403     const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
404     d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
405     if (alreadyFixedIsActive) {
406       this.force.stop();
407     }
408     this.forceSimulationActive = alreadyFixedIsActive;
409     this.nodes.forEach((d: COMPOSERNODES): void => {
410       d.fx = (alreadyFixedIsActive) ? null : d.x;
411       d.fy = (alreadyFixedIsActive) ? null : d.y;
412     });
413     if (alreadyFixedIsActive) {
414       this.force.restart();
415     }
416   }
417   /** Events handles when dragended @public */
418   public toggleSidebar(): void {
419     this.sideBarOpened = !this.sideBarOpened;
420     this.deselectAllNodes();
421     this.showRightSideInfo(true, false, false, false);
422   }
423   /** Prepare information for node creation of VNFD @private */
424   private generateData(): void {
425     this.generateVNFData();
426     this.generateDataNSDTopology();
427     this.sideBarOpened = false;
428   }
429   /** Prepare the information of the VNFD @private */
430   private generateVNFData(): void {
431     this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFD[]): void => {
432       this.vnfList = vnfdPackageData;
433     }, (error: ERRORDATA): void => {
434       this.restService.handleError(error, 'get');
435     });
436   }
437   /** Prepare information for node creation of NSD Topology @private */
438   private generateDataNSDTopology(): void {
439     this.nodes = [];
440     this.links = [];
441     this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL + '/' + this.identifier).subscribe((nsData: NSDDetails): void => {
442       delete nsData._admin;
443       delete nsData._id;
444       delete nsData._links;
445       this.nsData = nsData;
446       this.generateNSInfo(nsData);
447       if (nsData['virtual-link-desc'] !== undefined) {
448         /** Details of the VL */
449         this.nsDataVLD(nsData);
450       }
451       if (this.nsData.df.length > 0) {
452         this.nsData.df.forEach((res: DF): void => {
453           if (res['vnf-profile'] !== undefined) {
454             /** Details of the VNFD */
455             this.nsDataConstituentVNFD(nsData);
456           }
457         });
458       }
459       if (nsData.df.length > 0) {
460         this.nsDataVLDLinkCreation(nsData);
461       }
462       this.separateAndCreatenode();
463     }, (error: ERRORDATA): void => {
464       if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
465         this.router.navigateByUrl('404', { skipLocationChange: true }).catch((): void => {
466           // Catch Navigation Error
467         });
468       } else {
469         this.restService.handleError(error, 'get');
470       }
471       this.isLoadingResults = false;
472       this.isShowNSDDetails = false;
473     });
474   }
475   /** Generate the NS Package Information */
476   private generateNSInfo(nsData: NSDDetails): void {
477     this.nsPackageDetails.id = nsData.id;
478     this.nsPackageDetails.name = nsData.name;
479     this.nsPackageDetails.description = nsData.description;
480     this.nsPackageDetails.version = nsData.version;
481     this.nsPackageDetails.designer = nsData.designer;
482   }
483   /** nsData VL node creation function @private */
484   private nsDataVLD(nsData: NSDDetails): void {
485     nsData['virtual-link-desc'].forEach((res: VLD): void => {
486       this.nodes.push({ id: res.id, reflexive: false, type: 'vld', name: res.id, selectorId: res.id });
487     });
488   }
489   /** nsData VNFD node creation function @private */
490   private nsDataConstituentVNFD(nsData: NSDDetails): void {
491     nsData.df.forEach((resDF: DF): void => {
492       resDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
493         this.nodes.push(
494           {
495             id: resVNF['vnfd-id'] + ':' + resVNF.id,
496             reflexive: false,
497             type: 'vnfd',
498             name: resVNF['vnfd-id'],
499             nodeIndex: resVNF.id,
500             selectorId: resVNF['vnfd-id'] + '_' + resVNF.id
501           });
502         if (resVNF['virtual-link-connectivity'] !== undefined) {
503           this.nsDataCP(resVNF, resVNF.id);
504         }
505       });
506     });
507   }
508   /** nsData CP node creation function @private */
509   private nsDataCP(resVNF: VNFPROFILE, vnfID: string): void {
510     resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
511       resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
512         this.nodes.push(
513           {
514             id: vnfID + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'],
515             reflexive: false,
516             type: 'ns',
517             name: resultCCI['constituent-cpd-id'],
518             nodeIndex: resultCCI['constituent-base-element-id'],
519             selectorId: 'osm-' + resultCCI['constituent-cpd-id'] + '-' + vnfID + resultCCI['constituent-base-element-id'] + index
520           });
521       });
522     });
523   }
524   /** nsData Link node creation function @private */
525   private nsDataVLDLinkCreation(nsData: NSDDetails): void {
526     nsData.df.forEach((resDF: DF): void => {
527       if (resDF['vnf-profile'] !== undefined) {
528         resDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
529           this.nsdCopy = resVNF['vnfd-id'] + ':' + resVNF.id;
530           if (resVNF['virtual-link-connectivity'] !== undefined) {
531             this.nsDataVNFDConnectionPointRefrence(resVNF);
532           }
533         });
534       }
535     });
536   }
537   /** nsDataVNFDConnectionPointRefrence undefined Call this function @private */
538   private nsDataVNFDConnectionPointRefrence(resVNF: VNFPROFILE): void {
539     resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
540       resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
541         this.vnfdCopy = resultVLC['virtual-link-profile-id'];
542         this.connectionPoint = resVNF.id + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'];
543         const connectionPointPos: number = this.nodes.map((e: COMPOSERNODES): string => e.id).indexOf(this.connectionPoint);
544         const nsdPos: number = this.nodes.map((e: COMPOSERNODES): string => e.id).indexOf(this.nsdCopy);
545         const vnfdPos: number = this.nodes.map((e: COMPOSERNODES): string => e.id).indexOf(this.vnfdCopy);
546         this.links.push(
547           {
548             // eslint-disable-next-line security/detect-object-injection
549             source: this.nodes[connectionPointPos],
550             // eslint-disable-next-line security/detect-object-injection
551             target: this.nodes[nsdPos]
552           },
553           {
554             // eslint-disable-next-line security/detect-object-injection
555             source: this.nodes[connectionPointPos],
556             // eslint-disable-next-line security/detect-object-injection
557             target: this.nodes[vnfdPos]
558           });
559       });
560     });
561   }
562   /** Separate and create node @private */
563   private separateAndCreatenode(): void {
564     this.seprateNodes(this.nodes);
565     this.createnode(this.nodes);
566     this.isLoadingResults = false;
567   }
568   /** Get the default Configuration of containers @private */
569   private getGraphContainerAttr(): GRAPHDETAILS {
570     return {
571       width: 700,
572       height: 400,
573       nodeHeight: 50,
574       nodeWidth: 35,
575       textX: -35,
576       textY: 30,
577       radius: 5,
578       distance: 50,
579       strength: -500,
580       forcex: 2,
581       forcey: 2,
582       sourcePaddingYes: 17,
583       sourcePaddingNo: 12,
584       targetPaddingYes: 4,
585       targetPaddingNo: 3,
586       alphaTarget: 0.3,
587       imageX: -25,
588       imageY: -25,
589       shiftKeyCode: 17
590     };
591   }
592   /** Separate the nodes along with its tyep @private */
593   private seprateNodes(node: COMPOSERNODES[]): void {
594     this.vlNodes = []; this.vnfNodes = []; this.cpNodes = [];
595     node.forEach((nodeList: COMPOSERNODES): void => {
596       if (nodeList.type === 'vld') {
597         this.vlNodes.push(nodeList);
598       } else if (nodeList.type === 'vnfd') {
599         this.vnfNodes.push(nodeList);
600       } else if (nodeList.type === 'ns') {
601         this.cpNodes.push(nodeList);
602       }
603     });
604   }
605   /** Node is created and render at D3 region @private */
606   private createnode(node: COMPOSERNODES[]): void {
607     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
608     d3.selectAll('svg#graphContainer > *').remove();
609     d3.select(window).on('keydown', (): void => { this.keyDown(); });
610     d3.select(window).on('keyup', (): void => { this.keyUp(); });
611     this.svg = d3.select('#graphContainer')
612       .attr('oncontextmenu', 'return false;')
613       .attr('viewBox', `0 0 ${graphContainerAttr.width} ${graphContainerAttr.height}`)
614       .on('mousemove', (): void => { this.mousemove(); });
615     this.force = d3.forceSimulation()
616       .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
617       .force('link', d3.forceLink().id((d: TickPath): string => d.id).distance(graphContainerAttr.distance))
618       .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
619         graphContainerAttr.height / graphContainerAttr.forcey))
620       .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
621       .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
622       .on('tick', (): void => { this.tick(); });
623     this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
624     this.path = this.svg.append('svg:g').selectAll('path');
625     this.vlNode = this.svg.append('svg:g').selectAll('vlnode');
626     this.vnfdnode = this.svg.append('svg:g').selectAll('vnfdnode');
627     this.cpnode = this.svg.append('svg:g').selectAll('cpnode');
628     // app starts here
629     this.restart(node);
630   }
631   /** update force layout (called automatically each iteration) @private */
632   private tick(): void {
633     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
634     // draw directed edges with proper padding from node centers
635     this.path.attr('class', 'link').attr('d', (d: Tick): string => {
636       const deltaX: number = d.target.x - d.source.x;
637       const deltaY: number = d.target.y - d.source.y;
638       const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
639       const normX: number = deltaX / dist;
640       const normY: number = deltaY / dist;
641       const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
642       const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
643       const sourceX: number = d.source.x + (sourcePadding * normX);
644       const sourceY: number = d.source.y + (sourcePadding * normY);
645       const targetX: number = d.target.x - (targetPadding * normX);
646       const targetY: number = d.target.y - (targetPadding * normY);
647       return `M${sourceX},${sourceY}L${targetX},${targetY}`;
648     }).on('dblclick', (d: Tick): void => { this.getDeleteLinkConfirmation(d); });
649     this.vlNode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
650     this.vnfdnode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
651     this.cpnode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
652   }
653   /** Update graph (called when needed) at D3 region @private */
654   private restart(node: COMPOSERNODES[]): void {
655     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
656     this.path = this.path.data(this.links);
657     this.vlNode = this.vlNode.data(this.vlNodes, (d: COMPOSERNODES): string => d.id);
658     this.vnfdnode = this.vnfdnode.data(this.vnfNodes, (d: COMPOSERNODES): string => d.id);
659     this.cpnode = this.cpnode.data(this.cpNodes, (d: COMPOSERNODES): string => d.id);
660     this.resetAndCreateNodes();
661     this.force.nodes(node).force('link').links(this.links);
662     this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
663   }
664   /** Rest and create nodes @private */
665   private resetAndCreateNodes(): void {
666     this.path.exit().remove();
667     this.vlNode.exit().remove();
668     this.vnfdnode.exit().remove();
669     this.cpnode.exit().remove();
670     this.getPathNodes();
671     this.getVLNodes();
672     this.getVNFDNodes();
673     this.getCPNodes();
674     this.path.merge(this.path);
675     this.vlNode = this.gvlNode.merge(this.vlNode);
676     this.vnfdnode = this.gvnfdNode.merge(this.vnfdnode);
677     this.cpnode = this.gcpNode.merge(this.cpnode);
678   }
679   /** setting the Path @private */
680   private getPathNodes(): void {
681     this.path = this.path.enter().append('svg:path');
682   }
683   /** Setting all the VL nodes @private */
684   private getVLNodes(): void {
685     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
686     this.gvlNode = this.vlNode.enter().append('svg:g');
687     this.gvlNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
688     this.gvlNode.append('svg:image')
689       .style('opacity', 1)
690       .attr('x', graphContainerAttr.imageX)
691       .attr('y', graphContainerAttr.imageY)
692       .call(this.onDragDrop())
693       .attr('id', (d: COMPOSERNODES): string => d.selectorId)
694       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
695       .attr('xlink:href', 'assets/images/VL.svg')
696       .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
697       .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
698       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.vlNode, d); this.onNodeClickToggleSidebar(); })
699       .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
700     this.gvlNode.append('svg:text')
701       .attr('class', 'node_text')
702       .attr('y', graphContainerAttr.textY)
703       .text((d: COMPOSERNODES): string => d.id);
704   }
705   /** Setting all the VNFD nodes @private */
706   private getVNFDNodes(): void {
707     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
708     this.gvnfdNode = this.vnfdnode.enter().append('svg:g');
709     this.gvnfdNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
710     this.gvnfdNode.append('svg:image')
711       .style('opacity', 1)
712       .attr('x', graphContainerAttr.imageX)
713       .attr('y', graphContainerAttr.imageY)
714       .call(this.onDragDrop())
715       .attr('id', (d: COMPOSERNODES): string => d.selectorId)
716       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
717       .attr('xlink:href', 'assets/images/VNFD.svg')
718       .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
719       .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
720       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.vnfdnode, d); this.onNodeClickToggleSidebar(); })
721       .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
722     this.gvnfdNode.append('svg:text')
723       .attr('class', 'node_text')
724       .attr('y', graphContainerAttr.textY)
725       .text((d: COMPOSERNODES): string => d.name);
726   }
727   /** Setting all the CP nodes @private */
728   private getCPNodes(): void {
729     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
730     this.gcpNode = this.cpnode.enter().append('svg:g');
731     this.gcpNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
732     this.gcpNode.append('svg:image')
733       .style('opacity', 1)
734       .attr('x', graphContainerAttr.imageX)
735       .attr('y', graphContainerAttr.imageY)
736       .call(this.onDragDrop())
737       .attr('id', (d: COMPOSERNODES): string => d.selectorId)
738       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
739       .attr('xlink:href', 'assets/images/CP.svg')
740       .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
741       .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
742       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.cpnode, d); this.onNodeClickToggleSidebar(); })
743       .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
744     this.gcpNode.append('svg:text')
745       .attr('class', 'node_text')
746       .attr('y', graphContainerAttr.textY)
747       .text((d: COMPOSERNODES): string => d.name);
748   }
749   /** Events handles when mousemove it will capture the selected node data @private */
750   private mousemove(): void {
751     if (!this.mousedownNode) { return; }
752     this.dragLine.attr('d',
753       `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
754   }
755   /** Get confirmation Before Deleting the Link in Topology @private */
756   private getAddConfirmation(mouseData: COMPOSERNODES, getNsData: NSDDetails, addType: string, getVLDIndex: string): void {
757     let findVNFName: string = '';
758     let findVLDID: string = '';
759     if (mouseData.type === 'vld') {
760       findVNFName = this.mouseupNode.name;
761       findVLDID = this.mousedownNode.id;
762       this.vlName = this.mousedownNode.name;
763     } else {
764       findVNFName = this.mousedownNode.name;
765       findVLDID = this.mouseupNode.id;
766       this.vlName = this.mouseupNode.name;
767     }
768     if (getNsData['vnfd-id'] !== undefined) {
769       getNsData['vnfd-id'].forEach((resVNFid: string): void => {
770         if (resVNFid === findVNFName) {
771           this.getVNFSelectedData = this.vnfList.filter((vnfList: VNFD): boolean => vnfList.id === findVNFName)[0];
772           this.setVnfdConnectionPointRef = this.getVNFSelectedData['mgmt-cp'];
773           this.setVnfdName = this.getVNFSelectedData['product-name'];
774           this.selectedVNFProfile = getNsData.df[0]['vnf-profile'];
775         }
776       });
777     }
778     if (this.vlName !== undefined && this.setVnfdName !== undefined && this.setVnfdConnectionPointRef !== undefined) {
779       // eslint-disable-next-line security/detect-non-literal-fs-filename
780       const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
781       modalRef.componentInstance.topologyType = 'Add';
782       modalRef.componentInstance.cpDetails = this.getVNFSelectedData['ext-cpd'];
783       this.translateService.get('PAGE.TOPOLOGY.ADDINGCP', {
784         vlname: '<b>' + this.vlName + '</b>',
785         vnfdname: '<b>' + this.setVnfdName + '</b>',
786         cpname: '<b>' + this.setVnfdConnectionPointRef + '</b>'
787       }).subscribe((res: string): void => {
788         modalRef.componentInstance.topologyname = res;
789       });
790       modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.CONNECTIONPOINT');
791       modalRef.result.then((result: MODALCLOSERESPONSEWITHCP): void => {
792         if (result) {
793           this.generateCPForVNF(this.selectedVNFProfile, result.connection_point, getVLDIndex);
794           this.addData(environment.NSDESCRIPTORS_URL, this.identifier, getNsData, addType);
795         } else {
796           this.deselectPath();
797         }
798       }).catch((): void => {
799         // Catch Navigation Error
800       });
801     } else {
802       this.deselectPath();
803       this.notifierService.notify('error', this.translateService.instant('ERROR'));
804     }
805   }
806   /** Generate connection point for vnf using vld @private */
807   private generateCPForVNF(result: VNFPROFILE[], cp: string, getVLDIndex: string): void {
808     if (result !== undefined) {
809       result.forEach((resultVNFPROFILE: VNFPROFILE, index: number): void => {
810         if (getVLDIndex === resultVNFPROFILE.id) {
811           resultVNFPROFILE['virtual-link-connectivity'].push({
812             'constituent-cpd-id': [{
813               'constituent-base-element-id': getVLDIndex,
814               'constituent-cpd-id': cp
815             }],
816             'virtual-link-profile-id': this.vlName
817           });
818         }
819       });
820     } else {
821       Object.assign(result, {
822         'virtual-link-connectivity': [{
823           'constituent-cpd-id': [{
824             'constituent-base-element-id': getVLDIndex,
825             'constituent-cpd-id': cp
826           }],
827           'virtual-link-profile-id': this.vlName
828         }]
829       });
830     }
831   }
832   /** Events handles when mousedown click it will capture the selected node data @private */
833   private mouseDown(d: COMPOSERNODES): void {
834     // eslint-disable-next-line deprecation/deprecation
835     event.preventDefault();
836     if (d3.event.ctrlKey) { return; }
837     if (d3.event.shiftKey) {
838       if (d.type === 'vnfd') {
839         this.selectedNode.push(d);
840       }
841       this.mousedownNode = d;
842       this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
843       this.currentSelectedLink = null;
844       this.dragLine.style('marker-end', 'url(#end-arrow)').classed('hidden', false)
845         .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
846     }
847   }
848   /** Event handles when mouseup event occures @private */
849   private mouseUp(d: COMPOSERNODES): void {
850     if (!this.mousedownNode) { return; }
851     this.dragLine.classed('hidden', true).style('marker-end', '');
852     this.mouseupNode = d;
853     if ((this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vnfd') ||
854       (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vld')) {
855       if (this.mouseupNode.type === 'vnfd') {
856         this.getOldVLDIndex = this.mouseupNode.id.split(':');
857       } else if (this.mousedownNode.type === 'vnfd') {
858         this.getOldVLDIndex = this.mousedownNode.id.split(':');
859       }
860       const setOldVLDindex: string = this.getOldVLDIndex[1];
861       this.putType = 'cpAdded';
862       this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
863     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'ns') {
864       this.deselectPath();
865       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
866     } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'ns') {
867       this.deselectPath();
868       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
869     } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vld') {
870       this.deselectPath();
871       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVL'));
872     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vnfd') {
873       this.deselectPath();
874       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNF'));
875     } else if (this.mousedownNode.type === 'ns' && this.mouseupNode.type === 'ns') {
876       this.deselectPath();
877       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKCP'));
878     } else {
879       this.deselectPath();
880       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVLVNF'));
881     }
882     this.resetMouseVars();
883     // select new link
884     this.currentSelectedLink = d;
885     this.currentSelectedNode = null;
886   }
887   /** Mosue Drag Line false if it is not satisfied @private */
888   private deselectPath(): void {
889     this.dragLine.classed('hidden', true).style('marker-end', '').attr('d', 'M0,0L0,0');
890   }
891   /** reset Mouse varaibles @private */
892   private resetMouseVars(): void {
893     this.mousedownNode = null;
894     this.mouseupNode = null;
895     this.mousedownLink = null;
896   }
897   /** De-select all the selected nodes @private */
898   private deselectAllNodes(): void {
899     this.vlNode.select('image').classed(this.activeClass, false);
900     this.vnfdnode.select('image').classed(this.activeClass, false);
901     this.cpnode.select('image').classed(this.activeClass, false);
902   }
903   /** Show the right-side information @private */
904   private showRightSideInfo(nsdDetails: boolean, vldDetails: boolean, vnfDeails: boolean, cpDetails: boolean): void {
905     this.isShowNSDDetails = nsdDetails;
906     this.isShowVLDetails = vldDetails;
907     this.isShowVNFDetails = vnfDeails;
908     this.isShowCPDetails = cpDetails;
909   }
910   /** Events handles when Shift Click to perform create cp @private */
911   // eslint-disable-next-line @typescript-eslint/no-explicit-any
912   private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
913     this.selectNodeExclusive(nodeSelected, d);
914   }
915   /** Selected nodes @private */
916   // eslint-disable-next-line @typescript-eslint/no-explicit-any
917   private selectNodeExclusive(nodeSeleced: any, d: COMPOSERNODES): void {
918     const alreadyIsActive: boolean = nodeSeleced.select('#' + d.selectorId).classed(this.activeClass);
919     this.deselectAllNodes();
920     nodeSeleced.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
921     if (d.type === 'vld' && !alreadyIsActive) {
922       this.nsData['virtual-link-desc'].forEach((result: VLD): void => {
923         if (result.id === d.id) {
924           this.showRightSideInfo(false, true, false, false);
925           this.virtualLinkDesc = result;
926         }
927       });
928     } else if (d.type === 'vnfd' && !alreadyIsActive) {
929       this.nsData.df.forEach((res: DF): void => {
930         if (res['vnf-profile'] !== undefined) {
931           res['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
932             if (resVNF.id === d.nodeIndex && resVNF['vnfd-id'] === d.name) {
933               this.showRightSideInfo(false, false, true, false);
934               this.vnfData = resVNF;
935             }
936           });
937         }
938       });
939     } else if (d.type === 'ns' && !alreadyIsActive) {
940       this.nsData.df.forEach((resultDF: DF): void => {
941         if (resultDF['vnf-profile'] !== undefined) {
942           resultDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
943             if (resVNF['virtual-link-connectivity'] !== undefined) {
944               resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
945                 resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
946                   const connectionPointID: string = resVNF.id + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'];
947                   if (connectionPointID === d.id) {
948                     this.cpData = resultCCI;
949                     this.vnfData = resVNF;
950                     this.virtualLinkProfileID = resultVLC['virtual-link-profile-id'];
951                     this.showRightSideInfo(false, false, false, true);
952                   }
953                 });
954               });
955             }
956           });
957         }
958       });
959     } else {
960       this.showRightSideInfo(true, false, false, false);
961     }
962   }
963   /** Get confirmation Before Deleting the Link in Topology @private */
964   private getDeleteLinkConfirmation(d: Tick): void {
965     // eslint-disable-next-line security/detect-non-literal-fs-filename
966     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
967     modalRef.componentInstance.topologyType = 'Delete';
968     modalRef.componentInstance.topologyname = this.translateService.instant('PAGE.TOPOLOGY.LINK') + ' - ' + d.source.id;
969     modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.LINK';
970     modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
971       if (result) {
972         this.doubleClickLink(d);
973       }
974     }).catch((): void => {
975       // Catch Navigation Error
976     });
977   }
978   /** Events handles when Double Click to Delete the link @private */
979   private doubleClickLink(d: Tick): void {
980     let getID: string = '';
981     let getName: string = '';
982     let getNodeIndex: string;
983     if (d.source.type === 'ns') {
984       getID = d.source.id;
985       getName = d.source.name;
986       getNodeIndex = d.source.nodeIndex;
987     }
988     /** Split the selected node of connectionpoint */
989     const selectedNode: string[] = getID.split(':');
990     this.nsData.df.forEach((resultDF: DF): void => {
991       if (resultDF['vnf-profile'] !== undefined) {
992         resultDF['vnf-profile'].forEach((elementVNF: VNFPROFILE): void => {
993           const selectedVNFProfileID: string = selectedNode[0];
994           /** If VNF ID is equal to selected VNFProfile ID check the VLC of CCI to match the id and name to remove the VLC index */
995           if (selectedVNFProfileID === elementVNF.id) {
996             elementVNF['virtual-link-connectivity'].forEach((elementVLC: VLC, index: number): void => {
997               const posCCI: number = elementVLC['constituent-cpd-id'].findIndex((e: CCI): boolean => {
998                 const getCID: string = elementVNF.id + ':' + e['constituent-base-element-id'] + index + ':' + e['constituent-cpd-id'];
999                 return getID === getCID;
1000               });
1001               if (posCCI !== -1) {
1002                 elementVNF['virtual-link-connectivity'].splice(index, 1);
1003               }
1004             });
1005           }
1006         });
1007       }
1008     });
1009     this.putType = 'linkdelete';
1010     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
1011   }
1012   /** Get confirmation Before Deleting the Node in Topology @private */
1013   private getDeleteConfirmation(d: COMPOSERNODES): void {
1014     // eslint-disable-next-line security/detect-non-literal-fs-filename
1015     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
1016     modalRef.componentInstance.topologyType = 'Delete';
1017     modalRef.componentInstance.topologyname = d.name;
1018     if (d.type === 'vld') {
1019       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VIRTUALLINK';
1020     } else if (d.type === 'vnfd') {
1021       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VNF';
1022     } else if (d.type === 'ns') {
1023       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
1024     }
1025     modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
1026       if (result) {
1027         this.doubleClick(d);
1028       }
1029     }).catch((): void => {
1030       // Catch Navigation Error
1031     });
1032   }
1033   /** Events handles when Double Click to Delete @private */
1034   private doubleClick(d: COMPOSERNODES): void {
1035     const deletedNode: COMPOSERNODES = d;
1036     this.nodes.forEach((res: COMPOSERNODES, i: number): void => {
1037       if (res.id === d.id) {
1038         if (deletedNode.type === 'vld') {
1039           /** Remove the virtual-link-desc related to VL */
1040           const pos: number = this.nsData['virtual-link-desc'].map((e: VLD): string => e.id).indexOf(d.id);
1041           this.nsData['virtual-link-desc'].splice(pos, 1);
1042           /** Remove the virtual-link-connectivity between VL and VNFD */
1043           this.nsData.df.forEach((resultDF: DF): void => {
1044             if (resultDF['vnf-profile'] !== undefined) {
1045               resultDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
1046                 const getVLArray: number[] = resVNF['virtual-link-connectivity'].map((e: VLC, index: number): number => {
1047                   if (e['virtual-link-profile-id'] === d.id) {
1048                     return index;
1049                   }
1050                 });
1051                 if (getVLArray.length > 0) {
1052                   getVLArray.forEach((removeIndex: number): void => {
1053                     const index: string = removeIndex.toString();
1054                     // eslint-disable-next-line security/detect-object-injection
1055                     resVNF['virtual-link-connectivity'].splice(resVNF['virtual-link-connectivity'][index], 1);
1056                   });
1057                 }
1058               });
1059             }
1060           });
1061           this.putType = 'nsddelete';
1062         } else if (deletedNode.type === 'vnfd') {
1063           this.nsData.df.forEach((resultDF: DF): void => {
1064             if (resultDF['vnf-profile'] !== undefined) {
1065               /** Remove the vnf-profile related to VNFD */
1066               const posVNF: number = resultDF['vnf-profile'].findIndex((e: VNFPROFILE): boolean => e['vnfd-id'] === d.name && e.id === d.nodeIndex);
1067               resultDF['vnf-profile'].splice(posVNF, 1);
1068               /** Check the VNFD exists in any vnf-profile */
1069               const isVNFDExists: boolean = resultDF['vnf-profile'].some((e: VNFPROFILE): boolean => e['vnfd-id'] === d.name);
1070               /** If VNFD not exists in the vnf-profile remove from vnfd-id */
1071               if (!isVNFDExists) {
1072                 const posVNFD: number = this.nsData['vnfd-id'].findIndex((e: string): boolean => e === d.name);
1073                 this.nsData['vnfd-id'].splice(posVNFD, 1);
1074               }
1075             }
1076           });
1077           this.putType = 'vnfddelete';
1078         } else if (deletedNode.type === 'ns') {
1079           /** Split the selected node */
1080           const selectedNode: string[] = d.id.split(':');
1081           this.nsData.df.forEach((resultDF: DF): void => {
1082             if (resultDF['vnf-profile'] !== undefined) {
1083               resultDF['vnf-profile'].forEach((elementVNF: VNFPROFILE): void => {
1084                 const selectedVNFProfileID: string = selectedNode[0];
1085                 /** If VNF ID is equal to selected VNFProfile ID check the VLC of CCI to match the id and name to remove the VLC index */
1086                 if (selectedVNFProfileID === elementVNF.id) {
1087                   elementVNF['virtual-link-connectivity'].forEach((elementVLC: VLC, index: number): void => {
1088                     const posCCI: number = elementVLC['constituent-cpd-id'].findIndex((e: CCI): boolean => {
1089                       const getID: string = elementVNF.id + ':' + e['constituent-base-element-id'] + index + ':' + e['constituent-cpd-id'];
1090                       return d.id === getID;
1091                     });
1092                     if (posCCI !== -1) {
1093                       elementVNF['virtual-link-connectivity'].splice(index, 1);
1094                     }
1095                   });
1096                 }
1097               });
1098             }
1099           });
1100           this.putType = 'nsdelete';
1101         }
1102         this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
1103       }
1104     });
1105   }
1106   /** drag event @private */
1107   // eslint-disable-next-line @typescript-eslint/no-explicit-any
1108   private onDragDrop(): any {
1109     return d3.drag().filter(this.dragFilter)
1110       .on('start', this.dragstarted)
1111       .on('drag', this.dragged)
1112       .on('end', this.dragended);
1113   }
1114   /** Key press event @private */
1115   private keyDown(): void {
1116     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1117     if (this.lastKeyDown !== -1) { return; }
1118     this.lastKeyDown = d3.event.keyCode;
1119     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1120       this.svg.classed('ctrl', true);
1121     }
1122   }
1123   /** Key realse event @private */
1124   private keyUp(): void {
1125     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1126     this.lastKeyDown = -1;
1127     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1128       this.gvlNode.on('.drag', null);
1129       this.gvnfdNode.on('.drag', null);
1130       this.gcpNode.on('.drag', null);
1131       this.svg.classed('ctrl', false);
1132     }
1133   }
1134   /** Events handles when to drag using filter for the keys @private */
1135   private dragFilter(): boolean {
1136     return d3.event.ctrlKey && !d3.event.button;
1137   }
1138   /** Events handles when dragstarted @private */
1139   private dragstarted(d: COMPOSERNODES): void {
1140     d.fx = d.x;
1141     d.fy = d.y;
1142   }
1143   /** Events handles when dragged @private */
1144   private dragged(d: COMPOSERNODES): void {
1145     d.fx = d.x = d3.event.x;
1146     d.fy = d.y = d3.event.y;
1147   }
1148   /** Events handles when dragended @private */
1149   private dragended(d: COMPOSERNODES): void {
1150     if (this.forceSimulationActive) {
1151       d.fx = null;
1152       d.fy = null;
1153     } else {
1154       d.fx = d.x;
1155       d.fy = d.y;
1156       this.forceSimulationActive = false;
1157     }
1158   }
1159   /** Events handles when node double click   @private */
1160   private onNodedblClickToggleSidebar(): void {
1161     this.sideBarOpened = false;
1162   }
1163   /** Events handles when node single click   @private */
1164   private onNodeClickToggleSidebar(): void {
1165     this.sideBarOpened = true;
1166   }
1167 }