Bug 1383 Error when consulting NS instance's topology
[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 } from 'SharedService';
46 import { isNullOrUndefined } from 'util';
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   // tslint:disable-next-line:no-any
128   private svg: any;
129   /** Contains the Drag line */
130   // tslint:disable-next-line: no-any
131   private dragLine: any;
132   /** Contains VL node @private */
133   // tslint:disable-next-line:no-any
134   private vlNode: any;
135   /** Contains VNFD node @private */
136   // tslint:disable-next-line:no-any
137   private vnfdnode: any;
138   /** Contains CP node @private */
139   // tslint:disable-next-line:no-any
140   private cpnode: any;
141   /** Rendered nodes represent VL @private */
142   // tslint:disable-next-line:no-any
143   private gvlNode: any;
144   /** Rendered nodes represent VL @private */
145   // tslint:disable-next-line:no-any
146   private gvnfdNode: any;
147   /** Rendered nodes represent VL @private */
148   // tslint:disable-next-line:no-any
149   private gcpNode: any;
150   /** Contains forced node animations @private */
151   // tslint:disable-next-line:no-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   // tslint:disable-next-line:no-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 instantiate @public */
211   public ngOnInit(): void {
212     // tslint:disable-next-line:no-backbone-get-set-outside-model
213     this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
214     this.generateData();
215     this.headers = new HttpHeaders({
216       'Content-Type': 'application/zip',
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   // tslint:disable-next-line:no-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     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();
396   }
397   /** Event to freeze the animation @public */
398   public onFreeze(): void {
399     this.classApplied = !this.classApplied;
400     const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
401     d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
402     if (alreadyFixedIsActive) {
403       this.force.stop();
404     }
405     this.forceSimulationActive = alreadyFixedIsActive;
406     this.nodes.forEach((d: COMPOSERNODES): void => {
407       d.fx = (alreadyFixedIsActive) ? null : d.x;
408       d.fy = (alreadyFixedIsActive) ? null : d.y;
409     });
410     if (alreadyFixedIsActive) {
411       this.force.restart();
412     }
413   }
414   /** Events handles when dragended @public */
415   public toggleSidebar(): void {
416     this.sideBarOpened = !this.sideBarOpened;
417     this.deselectAllNodes();
418     this.showRightSideInfo(true, false, false, false);
419   }
420   /** Prepare information for node creation of VNFD @private */
421   private generateData(): void {
422     this.generateVNFData();
423     this.generateDataNSDTopology();
424     this.sideBarOpened = false;
425   }
426   /** Prepare the information of the VNFD @private */
427   private generateVNFData(): void {
428     this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFD[]): void => {
429       this.vnfList = vnfdPackageData;
430     }, (error: ERRORDATA): void => {
431       this.restService.handleError(error, 'get');
432     });
433   }
434   /** Prepare information for node creation of NSD Topology @private */
435   private generateDataNSDTopology(): void {
436     this.nodes = [];
437     this.links = [];
438     this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL + '/' + this.identifier).subscribe((nsData: NSDDetails): void => {
439       delete nsData._admin;
440       delete nsData._id;
441       delete nsData._links;
442       this.nsData = nsData;
443       this.generateNSInfo(nsData);
444       if (nsData['virtual-link-desc'] !== undefined) {
445         /** Details of the VL */
446         this.nsDataVLD(nsData);
447       }
448       if (this.nsData.df.length > 0) {
449         this.nsData.df.forEach((res: DF): void => {
450           if (res['vnf-profile'] !== undefined) {
451             /** Details of the VNFD */
452             this.nsDataConstituentVNFD(nsData);
453           }
454         });
455       }
456       if (nsData.df.length > 0) {
457         this.nsDataVLDLinkCreation(nsData);
458       }
459       this.separateAndCreatenode();
460     }, (error: ERRORDATA): void => {
461       if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
462         this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
463       } else {
464         this.restService.handleError(error, 'get');
465       }
466       this.isLoadingResults = false;
467       this.isShowNSDDetails = false;
468     });
469   }
470   /** Generate the NS Package Information */
471   private generateNSInfo(nsData: NSDDetails): void {
472     this.nsPackageDetails.id = nsData.id;
473     this.nsPackageDetails.name = nsData.name;
474     this.nsPackageDetails.description = nsData.description;
475     this.nsPackageDetails.version = nsData.version;
476     this.nsPackageDetails.designer = nsData.designer;
477   }
478   /** nsData VL node creation function @private */
479   private nsDataVLD(nsData: NSDDetails): void {
480     nsData['virtual-link-desc'].forEach((res: VLD): void => {
481       this.nodes.push({ id: res.id, reflexive: false, type: 'vld', name: res.id, selectorId: res.id });
482     });
483   }
484   /** nsData VNFD node creation function @private */
485   private nsDataConstituentVNFD(nsData: NSDDetails): void {
486     nsData.df.forEach((resDF: DF): void => {
487       resDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
488         this.nodes.push(
489           {
490             id: resVNF['vnfd-id'] + ':' + resVNF.id,
491             reflexive: false,
492             type: 'vnfd',
493             name: resVNF['vnfd-id'],
494             nodeIndex: resVNF.id,
495             selectorId: resVNF['vnfd-id'] + '_' + resVNF.id
496           });
497         if (resVNF['virtual-link-connectivity'] !== undefined) {
498           this.nsDataCP(resVNF, resVNF.id);
499         }
500       });
501     });
502   }
503   /** nsData CP node creation function @private */
504   private nsDataCP(resVNF: VNFPROFILE, vnfID: string): void {
505     resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
506       resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
507         this.nodes.push(
508           {
509             id: vnfID + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'],
510             reflexive: false,
511             type: 'ns',
512             name: resultCCI['constituent-cpd-id'],
513             nodeIndex: resultCCI['constituent-base-element-id'],
514             selectorId: 'osm-' + resultCCI['constituent-cpd-id'] + '-' + vnfID + resultCCI['constituent-base-element-id'] + index
515           });
516       });
517     });
518   }
519   /** nsData Link node creation function @private */
520   private nsDataVLDLinkCreation(nsData: NSDDetails): void {
521     nsData.df.forEach((resDF: DF): void => {
522       if (resDF['vnf-profile'] !== undefined) {
523         resDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
524           this.nsdCopy = resVNF['vnfd-id'] + ':' + resVNF.id;
525           if (resVNF['virtual-link-connectivity'] !== undefined) {
526             this.nsDataVNFDConnectionPointRefrence(resVNF);
527           }
528         });
529       }
530     });
531   }
532   /** nsDataVNFDConnectionPointRefrence undefined Call this function @private */
533   private nsDataVNFDConnectionPointRefrence(resVNF: VNFPROFILE): void {
534     resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
535       resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
536         this.vnfdCopy = resultVLC['virtual-link-profile-id'];
537         this.connectionPoint = resVNF.id + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'];
538         const connectionPointPos: number = this.nodes.map((e: COMPOSERNODES): string => { return e.id; }).indexOf(this.connectionPoint);
539         const nsdPos: number = this.nodes.map((e: COMPOSERNODES): string => { return e.id; }).indexOf(this.nsdCopy);
540         const vnfdPos: number = this.nodes.map((e: COMPOSERNODES): string => { return e.id; }).indexOf(this.vnfdCopy);
541         this.links.push(
542           {
543             source: this.nodes[connectionPointPos],
544             target: this.nodes[nsdPos]
545           },
546           {
547             source: this.nodes[connectionPointPos],
548             target: this.nodes[vnfdPos]
549           });
550       });
551     });
552   }
553   /** Separate and create node @private */
554   private separateAndCreatenode(): void {
555     this.seprateNodes(this.nodes);
556     this.createnode(this.nodes);
557     this.isLoadingResults = false;
558   }
559   /** Get the default Configuration of containers @private */
560   private getGraphContainerAttr(): GRAPHDETAILS {
561     return {
562       width: 700,
563       height: 400,
564       nodeHeight: 50,
565       nodeWidth: 35,
566       textX: -35,
567       textY: 30,
568       radius: 5,
569       distance: 50,
570       strength: -500,
571       forcex: 2,
572       forcey: 2,
573       sourcePaddingYes: 17,
574       sourcePaddingNo: 12,
575       targetPaddingYes: 4,
576       targetPaddingNo: 3,
577       alphaTarget: 0.3,
578       imageX: -25,
579       imageY: -25,
580       shiftKeyCode: 17
581     };
582   }
583   /** Separate the nodes along with its tyep @private */
584   private seprateNodes(node: COMPOSERNODES[]): void {
585     this.vlNodes = []; this.vnfNodes = []; this.cpNodes = [];
586     node.forEach((nodeList: COMPOSERNODES): void => {
587       if (nodeList.type === 'vld') {
588         this.vlNodes.push(nodeList);
589       } else if (nodeList.type === 'vnfd') {
590         this.vnfNodes.push(nodeList);
591       } else if (nodeList.type === 'ns') {
592         this.cpNodes.push(nodeList);
593       }
594     });
595   }
596   /** Node is created and render at D3 region @private */
597   private createnode(node: COMPOSERNODES[]): void {
598     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
599     d3.selectAll('svg#graphContainer > *').remove();
600     d3.select(window).on('keydown', (): void => { this.keyDown(); });
601     d3.select(window).on('keyup', (): void => { this.keyUp(); });
602     this.svg = d3.select('#graphContainer')
603       .attr('oncontextmenu', 'return false;')
604       .attr('viewBox', `0 0 ${graphContainerAttr.width} ${graphContainerAttr.height}`)
605       .on('mousemove', (): void => { this.mousemove(); });
606     this.force = d3.forceSimulation()
607       .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
608       .force('link', d3.forceLink().id((d: TickPath): string => d.id).distance(graphContainerAttr.distance))
609       .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
610         graphContainerAttr.height / graphContainerAttr.forcey))
611       .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
612       .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
613       .on('tick', (): void => { this.tick(); });
614     this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
615     this.path = this.svg.append('svg:g').selectAll('path');
616     this.vlNode = this.svg.append('svg:g').selectAll('vlnode');
617     this.vnfdnode = this.svg.append('svg:g').selectAll('vnfdnode');
618     this.cpnode = this.svg.append('svg:g').selectAll('cpnode');
619     // app starts here
620     this.restart(node);
621   }
622   /** update force layout (called automatically each iteration) @private */
623   private tick(): void {
624     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
625     // draw directed edges with proper padding from node centers
626     this.path.attr('class', 'link').attr('d', (d: Tick): string => {
627       const deltaX: number = d.target.x - d.source.x;
628       const deltaY: number = d.target.y - d.source.y;
629       const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
630       const normX: number = deltaX / dist;
631       const normY: number = deltaY / dist;
632       const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
633       const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
634       const sourceX: number = d.source.x + (sourcePadding * normX);
635       const sourceY: number = d.source.y + (sourcePadding * normY);
636       const targetX: number = d.target.x - (targetPadding * normX);
637       const targetY: number = d.target.y - (targetPadding * normY);
638       return `M${sourceX},${sourceY}L${targetX},${targetY}`;
639     }).on('dblclick', (d: Tick): void => { this.getDeleteLinkConfirmation(d); });
640     this.vlNode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
641     this.vnfdnode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
642     this.cpnode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
643   }
644   /** Update graph (called when needed) at D3 region @private */
645   private restart(node: COMPOSERNODES[]): void {
646     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
647     this.path = this.path.data(this.links);
648     this.vlNode = this.vlNode.data(this.vlNodes, (d: COMPOSERNODES): string => d.id);
649     this.vnfdnode = this.vnfdnode.data(this.vnfNodes, (d: COMPOSERNODES): string => d.id);
650     this.cpnode = this.cpnode.data(this.cpNodes, (d: COMPOSERNODES): string => d.id);
651     this.resetAndCreateNodes();
652     this.force.nodes(node).force('link').links(this.links);
653     this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
654   }
655   /** Rest and create nodes @private */
656   private resetAndCreateNodes(): void {
657     this.path.exit().remove();
658     this.vlNode.exit().remove();
659     this.vnfdnode.exit().remove();
660     this.cpnode.exit().remove();
661     this.getPathNodes();
662     this.getVLNodes();
663     this.getVNFDNodes();
664     this.getCPNodes();
665     this.path.merge(this.path);
666     this.vlNode = this.gvlNode.merge(this.vlNode);
667     this.vnfdnode = this.gvnfdNode.merge(this.vnfdnode);
668     this.cpnode = this.gcpNode.merge(this.cpnode);
669   }
670   /** setting the Path @private */
671   private getPathNodes(): void {
672     this.path = this.path.enter().append('svg:path');
673   }
674   /** Setting all the VL nodes @private */
675   private getVLNodes(): void {
676     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
677     this.gvlNode = this.vlNode.enter().append('svg:g');
678     this.gvlNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
679     this.gvlNode.append('svg:image')
680       .style('opacity', 1)
681       .attr('x', graphContainerAttr.imageX)
682       .attr('y', graphContainerAttr.imageY)
683       .call(this.onDragDrop())
684       .attr('id', (d: COMPOSERNODES): string => { return d.selectorId; })
685       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
686       .attr('xlink:href', 'assets/images/VL.svg')
687       .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
688       .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
689       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.vlNode, d); this.onNodeClickToggleSidebar(); })
690       .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
691     this.gvlNode.append('svg:text')
692       .attr('class', 'node_text')
693       .attr('y', graphContainerAttr.textY)
694       .text((d: COMPOSERNODES): string => d.id);
695   }
696   /** Setting all the VNFD nodes @private */
697   private getVNFDNodes(): void {
698     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
699     this.gvnfdNode = this.vnfdnode.enter().append('svg:g');
700     this.gvnfdNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
701     this.gvnfdNode.append('svg:image')
702       .style('opacity', 1)
703       .attr('x', graphContainerAttr.imageX)
704       .attr('y', graphContainerAttr.imageY)
705       .call(this.onDragDrop())
706       .attr('id', (d: COMPOSERNODES): string => { return d.selectorId; })
707       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
708       .attr('xlink:href', 'assets/images/VNFD.svg')
709       .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
710       .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
711       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.vnfdnode, d); this.onNodeClickToggleSidebar(); })
712       .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
713     this.gvnfdNode.append('svg:text')
714       .attr('class', 'node_text')
715       .attr('y', graphContainerAttr.textY)
716       .text((d: COMPOSERNODES): string => d.name);
717   }
718   /** Setting all the CP nodes @private */
719   private getCPNodes(): void {
720     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
721     this.gcpNode = this.cpnode.enter().append('svg:g');
722     this.gcpNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
723     this.gcpNode.append('svg:image')
724       .style('opacity', 1)
725       .attr('x', graphContainerAttr.imageX)
726       .attr('y', graphContainerAttr.imageY)
727       .call(this.onDragDrop())
728       .attr('id', (d: COMPOSERNODES): string => { return d.selectorId; })
729       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
730       .attr('xlink:href', 'assets/images/CP.svg')
731       .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
732       .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
733       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.cpnode, d); this.onNodeClickToggleSidebar(); })
734       .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
735     this.gcpNode.append('svg:text')
736       .attr('class', 'node_text')
737       .attr('y', graphContainerAttr.textY)
738       .text((d: COMPOSERNODES): string => d.name);
739   }
740   /** Events handles when mousemove it will capture the selected node data @private */
741   private mousemove(): void {
742     if (!this.mousedownNode) { return; }
743     this.dragLine.attr('d',
744       `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
745   }
746   /** Get confirmation Before Deleting the Link in Topology @private */
747   private getAddConfirmation(mouseData: COMPOSERNODES, getNsData: NSDDetails, addType: string, getVLDIndex: string): void {
748     let findVNFName: string = '';
749     let findVLDID: string = '';
750     if (mouseData.type === 'vld') {
751       findVNFName = this.mouseupNode.name;
752       findVLDID = this.mousedownNode.id;
753       this.vlName = this.mousedownNode.name;
754     } else {
755       findVNFName = this.mousedownNode.name;
756       findVLDID = this.mouseupNode.id;
757       this.vlName = this.mouseupNode.name;
758     }
759     if (getNsData['vnfd-id'] !== undefined) {
760       getNsData['vnfd-id'].forEach((resVNFid: string): void => {
761         if (resVNFid === findVNFName) {
762           this.getVNFSelectedData = this.vnfList.filter((vnfList: VNFD): boolean => vnfList.id === findVNFName)[0];
763           this.setVnfdConnectionPointRef = this.getVNFSelectedData['mgmt-cp'];
764           this.setVnfdName = this.getVNFSelectedData['product-name'];
765           this.selectedVNFProfile = getNsData.df[0]['vnf-profile'];
766         }
767       });
768     }
769     if (this.vlName !== undefined && this.setVnfdName !== undefined && this.setVnfdConnectionPointRef !== undefined) {
770       const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
771       modalRef.componentInstance.topologyType = 'Add';
772       modalRef.componentInstance.cpDetails = this.getVNFSelectedData['ext-cpd'];
773       this.translateService.get('PAGE.TOPOLOGY.ADDINGCP', {
774         vlname: '<b>' + this.vlName + '</b>',
775         vnfdname: '<b>' + this.setVnfdName + '</b>',
776         cpname: '<b>' + this.setVnfdConnectionPointRef + '</b>'
777       }).subscribe((res: string): void => {
778         modalRef.componentInstance.topologyname = res;
779       });
780       modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.CONNECTIONPOINT');
781       modalRef.result.then((result: MODALCLOSERESPONSEWITHCP): void => {
782         if (result) {
783           this.generateCPForVNF(this.selectedVNFProfile, result.connection_point, getVLDIndex);
784           this.addData(environment.NSDESCRIPTORS_URL, this.identifier, getNsData, addType);
785         } else {
786           this.deselectPath();
787         }
788       }).catch();
789     } else {
790       this.deselectPath();
791       this.notifierService.notify('error', this.translateService.instant('ERROR'));
792     }
793   }
794   /** Generate connection point for vnf using vld @private */
795   private generateCPForVNF(result: VNFPROFILE[], cp: string, getVLDIndex: string): void {
796     if (result !== undefined) {
797       result.forEach((resultVNFPROFILE: VNFPROFILE, index: number): void => {
798         if (getVLDIndex === resultVNFPROFILE.id) {
799           resultVNFPROFILE['virtual-link-connectivity'].push({
800             'constituent-cpd-id': [{
801               'constituent-base-element-id': getVLDIndex,
802               'constituent-cpd-id': cp
803             }],
804             'virtual-link-profile-id': this.vlName
805           });
806         }
807       });
808     } else {
809       Object.assign(result, {
810         'virtual-link-connectivity': [{
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   }
820   /** Events handles when mousedown click it will capture the selected node data @private */
821   private mouseDown(d: COMPOSERNODES): void {
822     event.preventDefault();
823     if (d3.event.ctrlKey) { return; }
824     if (d3.event.shiftKey) {
825       if (d.type === 'vnfd') {
826         this.selectedNode.push(d);
827       }
828       this.mousedownNode = d;
829       this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
830       this.currentSelectedLink = null;
831       this.dragLine.style('marker-end', 'url(#end-arrow)').classed('hidden', false)
832         .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
833     }
834   }
835   /** Event handles when mouseup event occures @private */
836   private mouseUp(d: COMPOSERNODES): void {
837     if (!this.mousedownNode) { return; }
838     this.dragLine.classed('hidden', true).style('marker-end', '');
839     this.mouseupNode = d;
840     if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vnfd') {
841       const getOldVLDIndex: string[] = this.mouseupNode.id.split(':');
842       const setOldVLDindex: string = getOldVLDIndex[1];
843       this.putType = 'cpAdded';
844       this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
845     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vld') {
846       const getOldVLDIndex: string[] = this.mousedownNode.id.split(':');
847       const setOldVLDindex: string = getOldVLDIndex[1];
848       this.putType = 'cpAdded';
849       this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
850     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'ns') {
851       this.deselectPath();
852       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
853     } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'ns') {
854       this.deselectPath();
855       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
856     } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vld') {
857       this.deselectPath();
858       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVL'));
859     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vnfd') {
860       this.deselectPath();
861       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNF'));
862     } else if (this.mousedownNode.type === 'ns' && this.mouseupNode.type === 'ns') {
863       this.deselectPath();
864       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKCP'));
865     } else {
866       this.deselectPath();
867       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVLVNF'));
868     }
869     this.resetMouseVars();
870     // select new link
871     this.currentSelectedLink = d;
872     this.currentSelectedNode = null;
873   }
874   /** Mosue Drag Line false if it is not satisfied @private */
875   private deselectPath(): void {
876     this.dragLine.classed('hidden', true).style('marker-end', '').attr('d', 'M0,0L0,0');
877   }
878   /** reset Mouse varaibles @private */
879   private resetMouseVars(): void {
880     this.mousedownNode = null;
881     this.mouseupNode = null;
882     this.mousedownLink = null;
883   }
884   /** De-select all the selected nodes @private */
885   private deselectAllNodes(): void {
886     this.vlNode.select('image').classed(this.activeClass, false);
887     this.vnfdnode.select('image').classed(this.activeClass, false);
888     this.cpnode.select('image').classed(this.activeClass, false);
889   }
890   /** Show the right-side information @private */
891   private showRightSideInfo(nsdDetails: boolean, vldDetails: boolean, vnfDeails: boolean, cpDetails: boolean): void {
892     this.isShowNSDDetails = nsdDetails;
893     this.isShowVLDetails = vldDetails;
894     this.isShowVNFDetails = vnfDeails;
895     this.isShowCPDetails = cpDetails;
896   }
897   /** Events handles when Shift Click to perform create cp @private */
898   // tslint:disable-next-line: no-any
899   private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
900     this.selectNodeExclusive(nodeSelected, d);
901   }
902   /** Selected nodes @private */
903   // tslint:disable-next-line: no-any
904   private selectNodeExclusive(nodeSeleced: any, d: COMPOSERNODES): void {
905     const alreadyIsActive: boolean = nodeSeleced.select('#' + d.selectorId).classed(this.activeClass);
906     this.deselectAllNodes();
907     nodeSeleced.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
908     if (d.type === 'vld' && !alreadyIsActive) {
909       this.nsData['virtual-link-desc'].forEach((result: VLD): void => {
910         if (result.id === d.id) {
911           this.showRightSideInfo(false, true, false, false);
912           this.virtualLinkDesc = result;
913         }
914       });
915     } else if (d.type === 'vnfd' && !alreadyIsActive) {
916       this.nsData.df.forEach((res: DF): void => {
917         if (res['vnf-profile'] !== undefined) {
918           res['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
919             if (resVNF.id === d.nodeIndex && resVNF['vnfd-id'] === d.name) {
920               this.showRightSideInfo(false, false, true, false);
921               this.vnfData = resVNF;
922             }
923           });
924         }
925       });
926     } else if (d.type === 'ns' && !alreadyIsActive) {
927       this.nsData.df.forEach((resultDF: DF): void => {
928         if (resultDF['vnf-profile'] !== undefined) {
929           resultDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
930             if (resVNF['virtual-link-connectivity'] !== undefined) {
931               resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
932                 resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
933                   const connectionPointID: string = resVNF.id + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'];
934                   if (connectionPointID === d.id) {
935                     this.cpData = resultCCI;
936                     this.vnfData = resVNF;
937                     this.virtualLinkProfileID = resultVLC['virtual-link-profile-id'];
938                     this.showRightSideInfo(false, false, false, true);
939                   }
940                 });
941               });
942             }
943           });
944         }
945       });
946     } else {
947       this.showRightSideInfo(true, false, false, false);
948     }
949   }
950   /** Get confirmation Before Deleting the Link in Topology @private */
951   private getDeleteLinkConfirmation(d: Tick): void {
952     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
953     modalRef.componentInstance.topologyType = 'Delete';
954     modalRef.componentInstance.topologyname = this.translateService.instant('PAGE.TOPOLOGY.LINK') + ' - ' + d.source.id;
955     modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.LINK';
956     modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
957       if (result) {
958         this.doubleClickLink(d);
959       }
960     }).catch();
961   }
962   /** Events handles when Double Click to Delete the link @private */
963   private doubleClickLink(d: Tick): void {
964     let getID: string = '';
965     let getName: string = '';
966     let getNodeIndex: string;
967     if (d.source.type === 'ns') {
968       getID = d.source.id;
969       getName = d.source.name;
970       getNodeIndex = d.source.nodeIndex;
971     }
972     /** Split the selected node of connectionpoint */
973     const selectedNode: string[] = getID.split(':');
974     this.nsData.df.forEach((resultDF: DF): void => {
975       if (resultDF['vnf-profile'] !== undefined) {
976         resultDF['vnf-profile'].forEach((elementVNF: VNFPROFILE): void => {
977           const selectedVNFProfileID: string = selectedNode[0];
978           /** 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 */
979           if (selectedVNFProfileID === elementVNF.id) {
980             elementVNF['virtual-link-connectivity'].forEach((elementVLC: VLC, index: number): void => {
981               const posCCI: number = elementVLC['constituent-cpd-id'].findIndex((e: CCI): boolean => {
982                 const getCID: string = elementVNF.id + ':' + e['constituent-base-element-id'] + index + ':' + e['constituent-cpd-id'];
983                 return getID === getCID;
984               });
985               if (posCCI !== -1) {
986                 elementVNF['virtual-link-connectivity'].splice(index, 1);
987               }
988             });
989           }
990         });
991       }
992     });
993     this.putType = 'linkdelete';
994     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
995   }
996   /** Get confirmation Before Deleting the Node in Topology @private */
997   private getDeleteConfirmation(d: COMPOSERNODES): void {
998     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
999     modalRef.componentInstance.topologyType = 'Delete';
1000     modalRef.componentInstance.topologyname = d.name;
1001     if (d.type === 'vld') {
1002       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VIRTUALLINK';
1003     } else if (d.type === 'vnfd') {
1004       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VNF';
1005     } else if (d.type === 'ns') {
1006       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
1007     }
1008     modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
1009       if (result) {
1010         this.doubleClick(d);
1011       }
1012     }).catch();
1013   }
1014   /** Events handles when Double Click to Delete @private */
1015   private doubleClick(d: COMPOSERNODES): void {
1016     const deletedNode: COMPOSERNODES = d;
1017     this.nodes.forEach((res: COMPOSERNODES, i: number): void => {
1018       if (res.id === d.id) {
1019         if (deletedNode.type === 'vld') {
1020           /** Remove the virtual-link-desc related to VL */
1021           const pos: number = this.nsData['virtual-link-desc'].map((e: VLD): string => { return e.id; }).indexOf(d.id);
1022           this.nsData['virtual-link-desc'].splice(pos, 1);
1023           /** Remove the virtual-link-connectivity between VL and VNFD */
1024           this.nsData.df.forEach((resultDF: DF): void => {
1025             if (resultDF['vnf-profile'] !== undefined) {
1026               resultDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
1027                 const getVLArray: number[] = resVNF['virtual-link-connectivity'].map((e: VLC, index: number): number => {
1028                   if (e['virtual-link-profile-id'] === d.id) {
1029                     return index;
1030                   }
1031                 });
1032                 if (getVLArray.length > 0) {
1033                   getVLArray.forEach((removeIndex: number): void => {
1034                     const index: string = removeIndex.toString();
1035                     resVNF['virtual-link-connectivity'].splice(resVNF['virtual-link-connectivity'][index], 1);
1036                   });
1037                 }
1038               });
1039             }
1040           });
1041           this.putType = 'nsddelete';
1042         } else if (deletedNode.type === 'vnfd') {
1043           this.nsData.df.forEach((resultDF: DF): void => {
1044             if (resultDF['vnf-profile'] !== undefined) {
1045               /** Remove the vnf-profile related to VNFD */
1046               const posVNF: number = resultDF['vnf-profile'].findIndex((e: VNFPROFILE): boolean => {
1047                 return e['vnfd-id'] === d.name && e.id === d.nodeIndex;
1048               });
1049               resultDF['vnf-profile'].splice(posVNF, 1);
1050               /** Check the VNFD exists in any vnf-profile */
1051               const isVNFDExists: boolean = resultDF['vnf-profile'].some((e: VNFPROFILE): boolean => {
1052                 return e['vnfd-id'] === d.name;
1053               });
1054               /** If VNFD not exists in the vnf-profile remove from vnfd-id */
1055               if (!isVNFDExists) {
1056                 const posVNFD: number = this.nsData['vnfd-id'].findIndex((e: string): boolean => {
1057                   return e === d.name;
1058                 });
1059                 this.nsData['vnfd-id'].splice(posVNFD, 1);
1060               }
1061             }
1062           });
1063           this.putType = 'vnfddelete';
1064         } else if (deletedNode.type === 'ns') {
1065           /** Split the selected node */
1066           const selectedNode: string[] = d.id.split(':');
1067           this.nsData.df.forEach((resultDF: DF): void => {
1068             if (resultDF['vnf-profile'] !== undefined) {
1069               resultDF['vnf-profile'].forEach((elementVNF: VNFPROFILE): void => {
1070                 const selectedVNFProfileID: string = selectedNode[0];
1071                 /** 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 */
1072                 if (selectedVNFProfileID === elementVNF.id) {
1073                   elementVNF['virtual-link-connectivity'].forEach((elementVLC: VLC, index: number): void => {
1074                     const posCCI: number = elementVLC['constituent-cpd-id'].findIndex((e: CCI): boolean => {
1075                       const getID: string = elementVNF.id + ':' + e['constituent-base-element-id'] + index + ':' + e['constituent-cpd-id'];
1076                       return d.id === getID;
1077                     });
1078                     if (posCCI !== -1) {
1079                       elementVNF['virtual-link-connectivity'].splice(index, 1);
1080                     }
1081                   });
1082                 }
1083               });
1084             }
1085           });
1086           this.putType = 'nsdelete';
1087         }
1088         this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
1089       }
1090     });
1091   }
1092   /** drag event @private */
1093   // tslint:disable-next-line: no-any
1094   private onDragDrop(): any {
1095     return d3.drag().filter(this.dragFilter)
1096       .on('start', this.dragstarted)
1097       .on('drag', this.dragged)
1098       .on('end', this.dragended);
1099   }
1100   /** Key press event @private */
1101   private keyDown(): void {
1102     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1103     if (this.lastKeyDown !== -1) { return; }
1104     this.lastKeyDown = d3.event.keyCode;
1105     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1106       this.svg.classed('ctrl', true);
1107     }
1108   }
1109   /** Key realse event @private */
1110   private keyUp(): void {
1111     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1112     this.lastKeyDown = -1;
1113     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1114       this.gvlNode.on('.drag', null);
1115       this.gvnfdNode.on('.drag', null);
1116       this.gcpNode.on('.drag', null);
1117       this.svg.classed('ctrl', false);
1118     }
1119   }
1120   /** Events handles when to drag using filter for the keys @private */
1121   private dragFilter(): boolean {
1122     return d3.event.ctrlKey && !d3.event.button;
1123   }
1124   /** Events handles when dragstarted @private */
1125   private dragstarted(d: COMPOSERNODES): void {
1126     d.fx = d.x;
1127     d.fy = d.y;
1128   }
1129   /** Events handles when dragged @private */
1130   private dragged(d: COMPOSERNODES): void {
1131     d.fx = d.x = d3.event.x;
1132     d.fy = d.y = d3.event.y;
1133   }
1134   /** Events handles when dragended @private */
1135   private dragended(d: COMPOSERNODES): void {
1136     if (this.forceSimulationActive) {
1137       d.fx = null;
1138       d.fy = null;
1139     } else {
1140       d.fx = d.x;
1141       d.fy = d.y;
1142       this.forceSimulationActive = false;
1143     }
1144   }
1145   /** Events handles when node double click   @private */
1146   private onNodedblClickToggleSidebar(): void {
1147     this.sideBarOpened = false;
1148   }
1149   /** Events handles when node single click   @private */
1150   private onNodeClickToggleSidebar(): void {
1151     this.sideBarOpened = true;
1152   }
1153 }