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