/*
 Copyright 2020 TATA ELXSI

 Licensed under the Apache License, Version 2.0 (the 'License');
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
 */
/**
 * @file VNFComposerComponent
 */
 import { isNullOrUndefined } from 'util';
import { HttpHeaders } from '@angular/common/http';
import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { NotifierService } from 'angular-notifier';
import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
import { ConfirmationTopologyComponent } from 'ConfirmationTopology';
import * as d3 from 'd3';
import { DataService } from 'DataService';
import { environment } from 'environment';
import * as HttpStatus from 'http-status-codes';
import * as jsyaml from 'js-yaml';
import { RestService } from 'RestService';
import { SharedService } from 'SharedService';
import { COMPOSERNODES, EXTCPD, GRAPHDETAILS, INTCPD, IVLD, Tick, TickPath, VDU, VDUINTCPD, VNFD, VNFDATA, VNIR } from 'VNFDModel';

/**
 * Creating component
 * @Component takes VNFComposerComponent.html as template url
 */
@Component({
  templateUrl: './VNFComposerComponent.html',
  styleUrls: ['./VNFComposerComponent.scss'],
  encapsulation: ViewEncapsulation.None
})
/** Exporting a class @exports VNFComposerComponent */
export class VNFComposerComponent {
  /** To inject services @public */
  public injector: Injector;
  /** View child contains graphContainer ref @public  */
  @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
  /** dataService to pass the data from one component to another @public */
  public dataService: DataService;
  /** random number count @public */
  public randomNumberLength: number;
  /** Contains the vnfd information @public */
  public vnfList: string[] = [];
  /** Contains VNFD Information @public */
  public vnfdInfo: VNFD = { 'product-name': '', description: '', version: '', id: '', provider: '' };
  /** Contains right panel box information @public */
  public showRightSideInfo: string = '';
  /** Add the fixed class for the freeze @public */
  public fixedClass: string = 'fixed';
  /** Check the loading results @public */
  public isLoadingResults: boolean = true;
  /** Give the message for the loading @public */
  public message: string = 'PLEASEWAIT';
  /** Assign the forcesimulation active @public */
  public forceSimulationActive: boolean = false;
  /** Assign pinned class for the button when freezed @public */
  public classApplied: boolean = false;
  /** Contains sidebar open status @public */
  public sideBarOpened: boolean = false;
  /** Contains SVG attributes @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private svg: any;
  /** Contains forced node animations @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private force: any;
  /** Contains the Drag line */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private dragLine: any;
  /** Contains id of the node @private */
  private identifier: string;
  /** Contains path information of the node */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private path: any;
  /** Contains node network @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private network: any;
  /** Contains node network @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private virutualDeploymentUnit: any;
  /** Contains node connectionPoint @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private connectionPoint: any;
  /** Contains node intConnectionPoint @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private intConnectionPoint: any;
  /** Contains the node information @private */
  private nodes: COMPOSERNODES[] = [];
  /** Contains the link information of nodes @private */
  private links: {}[] = [];
  /** Instance of the rest service @private */
  private restService: RestService;
  /** Service holds the router information @private */
  private router: Router;
  /** Service contails all the shared service information @private */
  private sharedService: SharedService;
  /** Holds teh instance of AuthService class of type AuthService @private */
  private activatedRoute: ActivatedRoute;
  /** Notifier service to popup notification @private */
  private notifierService: NotifierService;
  /** Controls the header form @private */
  private headers: HttpHeaders;
  /** Contains tranlsate instance @private */
  private translateService: TranslateService;
  /** Rendered nodes represent network @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private gNetwork: any;
  /** Rendered nodes represent VDU @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private gVirutualDeploymentUnit: any;
  /** Rendered nodes represent connection point @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private gConnectionPoint: any;
  /** Rendered nodes represent internal connection point @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private gIntConnectionPoint: any;
  /** Contains all the information about VNF Details @private */
  private vnfdPackageDetails: VNFD;
  /** Conatins mousedown action @private */
  private mousedownNode: COMPOSERNODES = null;
  /** Conatins mouseup action @private */
  private mouseupNode: COMPOSERNODES = null;
  /** Conatins current Selection node action @private */
  private currentSelectedNode: COMPOSERNODES = null;
  /** Add the activeNode for the selected @private */
  private activeNode: string = 'active';
  /** Contains lastkeypressed instance @private */
  private lastKeyDown: number = -1;
  /** Contains VDU Information @private */
  private vduInfo: VDU;
  /** Contains VDU Old value Information @private */
  private oldVDUID: string;
  /** Contains Internal VL Information @private */
  private intvlInfo: IVLD;
  /** Contains Internal VL Old value Information @private */
  private oldintVLID: string;
  /** Contains Connection Point Information @private */
  private cpInfo: EXTCPD;
  /** Contains Connection Point Old value Information @private */
  private oldCPID: string;
  /** Contains Internal Connection Point Information @private */
  private intcpInfo: VNIR;
  /** Instance of the modal service @private */
  private modalService: NgbModal;

  constructor(injector: Injector) {
    this.injector = injector;
    this.restService = this.injector.get(RestService);
    this.dataService = this.injector.get(DataService);
    this.router = this.injector.get(Router);
    this.activatedRoute = this.injector.get(ActivatedRoute);
    this.notifierService = this.injector.get(NotifierService);
    this.translateService = this.injector.get(TranslateService);
    this.sharedService = this.injector.get(SharedService);
    this.modalService = this.injector.get(NgbModal);
  }
  /**
   * Lifecyle Hooks the trigger before component is instantiate
   */
  public ngOnInit(): void {
    this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
    this.generateData();
    this.headers = new HttpHeaders({
      'Content-Type': 'application/gzip',
      Accept: 'application/json',
      'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
    });
  }

  /** Prepare information for node creation of VNFD @public */
  public generateData(): void {
    this.nodes = []; this.links = []; this.vnfdPackageDetails = null;
    this.showRightSideInfo = 'vnfdInfo';
    this.restService.getResource(environment.VNFPACKAGESCONTENT_URL + '/' + this.identifier)
      .subscribe((vnfdPackageDetails: VNFD): void => {
        try {
          delete vnfdPackageDetails._admin;
          delete vnfdPackageDetails._id;
          delete vnfdPackageDetails._links;
          this.vnfdPackageDetails = vnfdPackageDetails;
          this.generateVDU(vnfdPackageDetails);
          this.generateCPPoint(vnfdPackageDetails);
          this.generateInternalVLD(vnfdPackageDetails);
          this.generateInternalCP(vnfdPackageDetails);
          this.generateIntVLCPLinks(vnfdPackageDetails);
          this.generateVDUCPLinks(vnfdPackageDetails);
          this.createNode(this.nodes);
          this.generateVNFInfo(vnfdPackageDetails);
        } catch (e) {
          this.notifierService.notify('error', this.translateService.instant('ERROR'));
        }
        this.isLoadingResults = false;
      }, (error: ERRORDATA): void => {
        error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error;
        if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
          this.router.navigateByUrl('404', { skipLocationChange: true }).catch((): void => {
            // Catch Navigation Error
        });
        } else {
          this.restService.handleError(error, 'get');
        }
        this.isLoadingResults = false;
        this.showRightSideInfo = '';
      });
  }
  /** Generate the VNF Package Information */
  public generateVNFInfo(vnfdPackageDetails: VNFD): void {
    this.vnfdInfo['product-name'] = vnfdPackageDetails['product-name'];
    this.vnfdInfo.description = vnfdPackageDetails.description;
    this.vnfdInfo.version = vnfdPackageDetails.version;
    this.vnfdInfo.id = vnfdPackageDetails.id;
    this.vnfdInfo.provider = vnfdPackageDetails.provider;
  }
  /** Events handles at drag on D3 region @public */
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
  public drag(ev: any): void {
    ev.dataTransfer.setData('text', ev.target.id);
  }
  /** Events handles drop at D3 region @public */
  public drop(ev: DragEvent): void {
    ev.preventDefault();
    const getDropedName: string = ev.dataTransfer.getData('text');
    if (getDropedName === 'vdu') {
      this.svg.selectAll('*').remove();
      this.vduDropCompose();
    } else if (getDropedName === 'cp') {
      this.svg.selectAll('*').remove();
      this.cpDropCompose();
    } else if (getDropedName === 'intvl') {
      this.svg.selectAll('*').remove();
      this.intvlDropCompose();
    }
  }
  /** Events handles allow drop on D3 region @public */
  public allowDrop(ev: DragEvent): void {
    ev.preventDefault();
  }
  /** Generate and list VDU @public */
  public generateVDU(vnfdPackageDetails: VNFD): void {
    if (vnfdPackageDetails.vdu !== undefined) {
      vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
        this.nodes.push({
          id: vdu.id,
          name: vdu.name,
          reflexive: false,
          type: 'vdu'
        });
      });
    }
  }
  /** Generate and list CP points @public */
  public generateCPPoint(vnfdPackageDetails: VNFD): void {
    if (vnfdPackageDetails['ext-cpd'] !== undefined) {
      vnfdPackageDetails['ext-cpd'].forEach((cp: EXTCPD): void => {
        this.nodes.push({
          id: cp['int-cpd'].cpd !== undefined ? cp['int-cpd'].cpd : cp.id,
          name: cp.id,
          reflexive: false,
          type: 'cp'
        });
      });
    }
  }
  /** Generate and list Internal VLD @public */
  public generateInternalVLD(vnfdPackageDetails: VNFD): void {
    if (vnfdPackageDetails['int-virtual-link-desc'] !== undefined) {
      vnfdPackageDetails['int-virtual-link-desc'].forEach((ivld: IVLD): void => {
        this.nodes.push({
          id: ivld.id,
          name: ivld.id,
          reflexive: false,
          type: 'intvl'
        });
      });
    }
  }
  /** Generate and list Internal CP @public */
  public generateInternalCP(vnfdPackageDetails: VNFD): void {
    if (vnfdPackageDetails.vdu !== undefined) {
      vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
        if (vdu['int-cpd'] !== undefined) {
          vdu['int-cpd'].forEach((intcpd: VDUINTCPD): void => {
            if (intcpd['int-virtual-link-desc'] !== undefined) {
              intcpd['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
                this.nodes.push({
                  id: intcpd.id,
                  name: vnir.name,
                  reflexive: false,
                  type: 'intcp'
                });
              });
            }
          });
        }
      });
    }
  }
  /** Generate VDU External and Internal CP Links @public */
  public generateVDUCPLinks(vnfdPackageDetails: VNFD): void {
    if (vnfdPackageDetails.vdu !== undefined) {
      vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
        const vduLink: string = vdu.id;
        if (vdu['int-cpd'] !== undefined) {
          vdu['int-cpd'].forEach((intCPD: VDUINTCPD): void => {
            if (intCPD['int-virtual-link-desc'] !== undefined) {
              intCPD['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
                this.links.push({ source: vduLink, target: intCPD.id });
              });
            } else {
              this.links.push({ source: vduLink, target: intCPD.id });
            }
          });
        }
      });
    }
  }
  /** Generate Network/VLD/Internal VirtualLink, CP Links @public */
  public generateIntVLCPLinks(vnfdPackageDetails: VNFD): void {
    if (vnfdPackageDetails.vdu !== undefined) {
      vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
        if (vdu['int-cpd'] !== undefined) {
          vdu['int-cpd'].forEach((intCPD: VDUINTCPD): void => {
            const vldName: string = intCPD['int-virtual-link-desc'];
            if (intCPD['int-virtual-link-desc'] !== undefined) {
              intCPD['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
                this.links.push({ source: vldName, target: intCPD.id });
              });
            }
          });
        }
      });
    }
  }
  /** VNFD details can be saved on users inputs @public */
  public saveVNFD(): void {
    this.vnfdPackageDetails['product-name'] = this.vnfdInfo['product-name'];
    this.vnfdPackageDetails.description = this.vnfdInfo.description;
    this.vnfdPackageDetails.version = this.vnfdInfo.version;
    this.vnfdPackageDetails.id = this.vnfdInfo.id;
    this.vnfdPackageDetails.provider = this.vnfdInfo.provider;
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
  }
  /** VDU details can be saved on users inputs @public */
  public saveVDU(getVDUID: string): void {
    const getOLDVDUID: string = this.oldVDUID;
    this.vnfdPackageDetails.vdu.forEach((ref: VDU): void => {
      if (ref.id === getVDUID) {
        ref.id = this.vduInfo.id;
        ref.name = this.vduInfo.name;
        ref.description = this.vduInfo.description !== undefined ? this.vduInfo.description : '';
        ref['sw-image-desc'] = this.vduInfo['sw-image-desc'];
      }
    });
    this.vnfdPackageDetails['ext-cpd'].forEach((extCPD: EXTCPD): void => {
      if (extCPD['int-cpd'] !== undefined) {
        if (extCPD['int-cpd']['vdu-id'] === getOLDVDUID) {
          extCPD['int-cpd']['vdu-id'] = this.vduInfo.id;
        }
      }
    });
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
  }
  /** IntVL details can be saved on users inputs @public */
  public saveIntVL(intVLID: string): void {
    const getOldID: string = this.oldintVLID;
    this.vnfdPackageDetails['int-virtual-link-desc'].forEach((ivldDetails: IVLD): void => {
      if (ivldDetails.id === intVLID) {
        ivldDetails.id = this.intvlInfo.id;
      }
    });
    this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU): void => {
      if (vduDetails['int-cpd'] !== undefined) {
        vduDetails['int-cpd'].forEach((intCPDDetails: VDUINTCPD): void => {
          if (intCPDDetails['int-virtual-link-desc'] !== undefined) {
            if (intCPDDetails['int-virtual-link-desc'] === getOldID) {
              intCPDDetails['int-virtual-link-desc'] = this.intvlInfo.id;
            }
          }
        });
      }
    });
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
  }
  /** IntVL details can be saved on users inputs @public */
  public saveCP(cpID: string): void {
    const getOldCP: string = this.oldCPID;
    this.vnfdPackageDetails['ext-cpd'].forEach((ref: EXTCPD): void => {
      if (ref.id === cpID) {
        ref.id = this.cpInfo.id;
      }
    });
    if (this.vnfdPackageDetails['mgmt-cp'] === getOldCP) {
      this.vnfdPackageDetails['mgmt-cp'] = this.cpInfo.id;
    }
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
  }
  /** Edit topology @public */
  public onEdit(): void {
    this.router.navigate(['/packages/vnf/edit/', this.identifier]).catch((): void => {
      // Catch Navigation Error
  });
  }
  /** Show Info @public */
  public showInfo(): void {
    // eslint-disable-next-line security/detect-non-literal-fs-filename
    const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
    modalRef.componentInstance.topologyType = 'Info';
    modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
    modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
      if (result) {
        // empty
      }
    }).catch((): void => {
      // Catch Navigation Error
  });
  }
  /** Event to freeze the animation @public */
  public onFreeze(): void {
    this.classApplied = !this.classApplied;
    const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
    d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
    if (alreadyFixedIsActive) {
      this.force.stop();
    }
    this.forceSimulationActive = alreadyFixedIsActive;
    this.nodes.forEach((d: COMPOSERNODES): void => {
      d.fx = (alreadyFixedIsActive) ? null : d.x;
      d.fy = (alreadyFixedIsActive) ? null : d.y;
    });
    if (alreadyFixedIsActive) {
      this.force.restart();
    }
  }
  /** Events handles when dragended @public */
  public toggleSidebar(): void {
    this.sideBarOpened = !this.sideBarOpened;
    this.deselectAllNodes();
    this.showRightSideInfo = 'vnfdInfo';
  }
  /** Get the default Configuration of containers @private */
  private getGraphContainerAttr(): GRAPHDETAILS {
    return {
      width: 700,
      height: 400,
      nodeHeight: 50,
      nodeWidth: 35,
      textX: -35,
      textY: 30,
      radius: 5,
      distance: 50,
      strength: -500,
      forcex: 2,
      forcey: 2,
      sourcePaddingYes: 17,
      sourcePaddingNo: 12,
      targetPaddingYes: 4,
      targetPaddingNo: 3,
      alphaTarget: 0.3,
      imageX: -25,
      imageY: -25,
      shiftKeyCode: 17
    };
  }
  /** Node is created and render at D3 region @private */
  private createNode(nodes: VNFD[]): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    d3.selectAll('svg#graphContainer > *').remove();
    d3.select(window).on('keydown', (): void => { this.keyDown(); });
    d3.select(window).on('keyup', (): void => { this.keyUp(); });
    this.svg = d3.select('#graphContainer')
      .attr('oncontextmenu', 'return false;')
      .attr('viewBox', `0 0 ${graphContainerAttr.width} ${graphContainerAttr.height}`)
      .on('mousemove', (): void => { this.mousemove(); });
    this.force = d3.forceSimulation()
      .force('link', d3.forceLink().id((d: TickPath): string => d.id).distance(graphContainerAttr.distance))
      .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
      .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
      .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
      .on('tick', (): void => { this.tick(); });
    this.path = this.svg.append('svg:g').selectAll('path');
    this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
    this.network = this.svg.append('svg:g').selectAll('network');
    this.virutualDeploymentUnit = this.svg.append('svg:g').selectAll('virutualDeploymentUnit');
    this.connectionPoint = this.svg.append('svg:g').selectAll('connectionPoint');
    this.intConnectionPoint = this.svg.append('svg:g').selectAll('intConnectionPoint');
    this.restart(nodes);
  }
  /** Update force layout (called automatically each iteration) @private */
  private tick(): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    this.path.attr('d', (d: Tick): string => {
      const deltaX: number = d.target.x - d.source.x; const deltaY: number = d.target.y - d.source.y;
      const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
      const normX: number = deltaX / dist; const normY: number = deltaY / dist;
      const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
      const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
      const sourceX: number = d.source.x + (sourcePadding * normX); const sourceY: number = d.source.y + (sourcePadding * normY);
      const targetX: number = d.target.x - (targetPadding * normX); const targetY: number = d.target.y - (targetPadding * normY);
      return `M${sourceX},${sourceY}L${targetX},${targetY}`;
    }).on('dblclick', (d: Tick): void => { this.getDeleteLinkConfirmation(d); });
    this.network.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
    this.virutualDeploymentUnit.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
    this.connectionPoint.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
    this.intConnectionPoint.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
  }
  /** Update graph (called when needed) @private */
  private restart(nodes: VNFD[]): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    this.path = this.path.data(this.links);
    const cpNodes: {}[] = []; const vduNodes: {}[] = []; const vlNodes: {}[] = []; const intcpNodes: {}[] = []; //Nodes are known by id
    nodes.forEach((nodeList: COMPOSERNODES): void => {
      if (nodeList.type === 'cp') { cpNodes.push(nodeList); }
      else if (nodeList.type === 'vdu') { vduNodes.push(nodeList); }
      else if (nodeList.type === 'intvl') { vlNodes.push(nodeList); }
      else if (nodeList.type === 'intcp') { intcpNodes.push(nodeList); }
    });
    this.network = this.network.data(vlNodes, (d: VNFD): string => d.id);
    this.virutualDeploymentUnit = this.virutualDeploymentUnit.data(vduNodes, (d: VNFD): string => d.id);
    this.connectionPoint = this.connectionPoint.data(cpNodes, (d: VNFD): string => d.id);
    this.intConnectionPoint = this.intConnectionPoint.data(intcpNodes, (d: VNFD): string => d.id);
    this.resetAndCreateNodes();
    this.force.nodes(nodes).force('link').links(this.links); //Set the graph in motion
    this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
  }
  /** Rest and create nodes @private */
  private resetAndCreateNodes(): void {
    this.path.exit().remove();
    this.network.exit().remove();
    this.virutualDeploymentUnit.exit().remove();
    this.connectionPoint.exit().remove();
    this.intConnectionPoint.exit().remove();
    this.getPathNodes();
    this.getgNetwork();
    this.getgVirutualDeploymentUnit();
    this.getgConnectionPoint();
    this.getgIntConnectionPoint();
    this.network = this.gNetwork.merge(this.network);
    this.virutualDeploymentUnit = this.gVirutualDeploymentUnit.merge(this.virutualDeploymentUnit);
    this.connectionPoint = this.gConnectionPoint.merge(this.connectionPoint);
    this.intConnectionPoint = this.gIntConnectionPoint.merge(this.intConnectionPoint);
    this.path.merge(this.path);
  }
  /** Setting the Path @private */
  private getPathNodes(): void {
    this.path = this.path.enter().append('svg:path').attr('class', 'link');
  }
  /** Settings all the network attributes of nodes @private */
  private getgNetwork(): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    this.gNetwork = this.network.enter().append('svg:g');
    this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
    this.gNetwork.append('svg:image')
      .style('opacity', 1)
      .attr('x', graphContainerAttr.imageX)
      .attr('y', graphContainerAttr.imageY)
      .call(this.onDragDrop())
      .attr('id', (d: COMPOSERNODES): string => d.id)
      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
      .attr('xlink:href', 'assets/images/INTVL.svg')
      .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
      .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
      .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.network, d); this.onNodeClickToggleSidebar(); })
      .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
    this.gNetwork.append('svg:text')
      .attr('class', 'node_text')
      .attr('y', graphContainerAttr.textY)
      .text((d: COMPOSERNODES): string => d.id);
  }
  /** Settings all the connection point attributes of nodes @private */
  private getgVirutualDeploymentUnit(): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    this.gVirutualDeploymentUnit = this.virutualDeploymentUnit.enter().append('svg:g');
    this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
    this.gVirutualDeploymentUnit.append('svg:image')
      .style('opacity', 1)
      .attr('x', graphContainerAttr.imageX)
      .attr('y', graphContainerAttr.imageY)
      .call(this.onDragDrop())
      .attr('id', (d: COMPOSERNODES): string => d.id)
      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
      .attr('xlink:href', 'assets/images/VDU.svg')
      .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
      .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
      .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.virutualDeploymentUnit, d); this.onNodeClickToggleSidebar(); })
      .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
    this.gVirutualDeploymentUnit.append('svg:text')
      .attr('class', 'node_text')
      .attr('y', graphContainerAttr.textY)
      .text((d: COMPOSERNODES): string => d.id);
  }
  /** Settings all the connection point attributes of nodes @private */
  private getgConnectionPoint(): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    this.gConnectionPoint = this.connectionPoint.enter().append('svg:g');
    this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
    this.gConnectionPoint.append('svg:image')
      .style('opacity', 1)
      .attr('x', graphContainerAttr.imageX)
      .attr('y', graphContainerAttr.imageY)
      .call(this.onDragDrop())
      .attr('id', (d: COMPOSERNODES): string => d.id)
      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
      .attr('xlink:href', 'assets/images/CP-VNF.svg')
      .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
      .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
      .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.connectionPoint, d); this.onNodeClickToggleSidebar(); })
      .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
    this.gConnectionPoint.append('svg:text')
      .attr('class', 'node_text')
      .attr('y', graphContainerAttr.textY)
      .text((d: COMPOSERNODES): string => d.name);
  }
  /** Settings all the internal connection point attributes of nodes @private */
  private getgIntConnectionPoint(): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    this.gIntConnectionPoint = this.intConnectionPoint.enter().append('svg:g');
    this.gIntConnectionPoint.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
    this.gIntConnectionPoint.append('svg:image')
      .style('opacity', 1)
      .attr('x', graphContainerAttr.imageX)
      .attr('y', graphContainerAttr.imageY)
      .call(this.onDragDrop())
      .attr('id', (d: COMPOSERNODES): string => d.id)
      .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
      .attr('xlink:href', 'assets/images/INTCP.svg')
      .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
      .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
      .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.intConnectionPoint, d); this.onNodeClickToggleSidebar(); })
      .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
    this.gIntConnectionPoint.append('svg:text')
      .attr('class', 'node_text')
      .attr('y', graphContainerAttr.textY)
      .text((d: COMPOSERNODES): string => d.name);
  }
  /** Drop VDU Composer Data @private */
  private vduDropCompose(): void {
    const randomID: string = this.sharedService.randomString();
    if (this.vnfdPackageDetails['mgmt-cp'] === undefined) {
      this.notifierService.notify('error', this.translateService.instant('PAGE.TOPOLOGY.ADDCPBEFOREVDU'));
    } else {
      if (this.vnfdPackageDetails.vdu === undefined) {
        this.vnfdPackageDetails.vdu = [];
      }
      this.vnfdPackageDetails.vdu.push({
        id: 'vdu_' + randomID,
        name: 'vdu_' + randomID,
        description: '',
        'sw-image-desc': 'ubuntu',
        'int-cpd': [],
        'monitoring-parameter': [],
        'virtual-compute-desc': '',
        'virtual-storage-desc': []
      });
      this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
    }
  }
  /** Drop CP Composer Data @private */
  private cpDropCompose(): void {
    const randomID: string = this.sharedService.randomString();
    if (this.vnfdPackageDetails['ext-cpd'] === undefined) {
      this.vnfdPackageDetails['ext-cpd'] = [];
    }
    this.vnfdPackageDetails['ext-cpd'].push({
      id: 'cp_' + randomID,
      'int-cpd': {}
    });
    if (this.vnfdPackageDetails['mgmt-cp'] === undefined) {
      this.vnfdPackageDetails['mgmt-cp'] = 'cp_' + randomID;
    }
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
  }
  /** Drop IntVL Composer Data @private */
  private intvlDropCompose(): void {
    const randomID: string = this.sharedService.randomString();
    if (this.vnfdPackageDetails['int-virtual-link-desc'] === undefined) {
      this.vnfdPackageDetails['int-virtual-link-desc'] = [];
    }
    this.vnfdPackageDetails['int-virtual-link-desc'].push({
      id: 'vnf_vl_' + randomID
    });
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
  }
  /** Add the Add Nodes Data @private */
  private addNodes(apiURL: string, identifier: string, data: VNFD): void {
    this.isLoadingResults = true;
    const apiURLHeader: APIURLHEADER = {
      url: apiURL + '/' + identifier + '/package_content',
      httpOptions: { headers: this.headers }
    };
    const vnfData: VNFDATA = {};
    vnfData.vnfd = data;
    const descriptorInfo: string = jsyaml.dump(vnfData, { sortKeys: true });
    this.sharedService.targzFile({ packageType: 'vnfd', id: this.identifier, descriptor: descriptorInfo })
      .then((content: ArrayBuffer): void => {
        this.restService.putResource(apiURLHeader, content).subscribe((res: {}): void => {
          this.generateData();
          this.notifierService.notify('success', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.UPDATEDSUCCESSFULLY'));
          this.isLoadingResults = false;
        }, (error: ERRORDATA): void => {
          this.generateData();
          this.restService.handleError(error, 'put');
          this.isLoadingResults = false;
        });
      }).catch((): void => {
        this.notifierService.notify('error', this.translateService.instant('ERROR'));
        this.isLoadingResults = false;
      });
  }
  /** Events handles when mousedown click it will capture the selected node data @private */
  private mouseDown(d: COMPOSERNODES): void {
    // eslint-disable-next-line deprecation/deprecation
    event.preventDefault();
    if (d3.event.ctrlKey) { return; }
    if (d3.event.shiftKey) {
      this.mousedownNode = d;
      this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
      this.dragLine.classed('hidden', false)
        .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
    }
  }
  /** Event handles when mouseup event occures @private */
  private mouseUp(d: COMPOSERNODES): void {
    if (!this.mousedownNode) { return; }
    this.dragLine.classed('hidden', true);
    this.mouseupNode = d;
    if (this.mousedownNode.type === 'vdu') {
      this.vduMouseDownNode();
    } else if (this.mousedownNode.type === 'cp') {
      this.cpMouseDownNode();
    } else if (this.mousedownNode.type === 'intvl') {
      this.intVLMouseDownNode();
    } else if (this.mousedownNode.type === 'intcp') {
      this.intCPMouseDownNode();
    } else {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
      this.deselectPath();
    }
    this.resetMouseActions();
    this.currentSelectedNode = null;
  }
  /** Establish a connection point between vdu and other nodes @private */
  private vduMouseDownNode(): void {
    if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'cp') {
      this.vduCPConnection(this.mousedownNode.id, this.mouseupNode.id);
    } else if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'intcp') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDINTCP'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'vdu') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDVDU'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'intvl') {
      this.vduIntvlConnection(this.mousedownNode.id, this.mouseupNode.id);
    }
  }
  /** Establish a connection point between cp and other nodes @private */
  private cpMouseDownNode(): void {
    if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'vdu') {
      this.vduCPConnection(this.mouseupNode.id, this.mousedownNode.id);
    } else if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'intvl') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDVNFVL'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'intcp') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDINTCP'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'cp') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDCP'));
      this.deselectPath();
    }
  }
  /** Establish a connection piont between intvl and other nodes @private */
  private intVLMouseDownNode(): void {
    if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'cp') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDCP'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'vdu') {
      this.vduIntvlConnection(this.mouseupNode.id, this.mousedownNode.id);
    } else if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'intvl') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDVNFVL'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'intcp') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDONTCP'));
      this.deselectPath();
    }
  }
  /** Establish a connection point between intcp and other nodes @private */
  private intCPMouseDownNode(): void {
    if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'vdu') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVDU'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'cp') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDCP'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'intvl') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVNFVL'));
      this.deselectPath();
    } else if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'intcp') {
      this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDINTCP'));
      this.deselectPath();
    }
  }
  /** Establish a connection between VDU & CP vice versa @private */
  private vduCPConnection(nodeA: string, nodeB: string): void {
    const vduExternalID: string = nodeA + '-eth_' + this.sharedService.randomString();
    if (this.vnfdPackageDetails.vdu !== undefined) {
      this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
        const vduID: string = vdu.id;
        if (vdu.id === nodeA) {
          if (this.vnfdPackageDetails['ext-cpd'] !== undefined) {
            this.vnfdPackageDetails['ext-cpd'].forEach((extcpd: EXTCPD, index: number): void => {
              if (extcpd.id === nodeB) {
                if (vdu['int-cpd'] === undefined) {
                  vdu['int-cpd'] = [];
                }
                vdu['int-cpd'].push({
                  id: vduExternalID,
                  'virtual-network-interface-requirement': [
                    {
                      name: vduExternalID,
                      position: 1,
                      'virtual-interface': { type: 'PARAVIRT' }
                    }
                  ]
                });
                // eslint-disable-next-line security/detect-object-injection
                this.vnfdPackageDetails['ext-cpd'][index] = {
                  id: extcpd.id,
                  'int-cpd': {
                    cpd: vduExternalID,
                    'vdu-id': vduID
                  }
                };
              }
            });
          }
        }
      });
    }
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
    this.deselectPath();
  }
  /** Establish a connection between vdu & intvl and vice versa @private */
  private vduIntvlConnection(nodeA: string, nodeB: string): void {
    const vduInternalID: string = nodeA + '-eth_' + this.sharedService.randomString();
    if (this.vnfdPackageDetails.vdu !== undefined) {
      this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
        if (vdu.id === nodeA) {
          if (vdu['int-cpd'] === undefined) {
            vdu['int-cpd'] = [];
          }
          vdu['int-cpd'].push({
            id: vduInternalID,
            'int-virtual-link-desc': nodeB,
            'virtual-network-interface-requirement': [
              {
                name: vduInternalID,
                position: 1,
                'virtual-interface': { type: 'PARAVIRT' }
              }
            ]
          });
        }
      });
    }
    this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
    this.deselectPath();
  }
  /** Events handles when mousemove it will capture the selected node data @private */
  private mousemove(): void {
    if (!this.mousedownNode) { return; }
    this.dragLine.attr('d',
      `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
  }
  /** reset Mouse varaibles @private */
  private resetMouseActions(): void {
    this.mousedownNode = null;
    this.mouseupNode = null;
  }
  /** drag event @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private onDragDrop(): any {
    return d3.drag().filter(this.dragFilter)
      .on('start', this.dragstarted)
      .on('drag', this.dragged)
      .on('end', this.dragended);
  }
  /** Key press event @private */
  private keyDown(): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    if (this.lastKeyDown !== -1) { return; }
    this.lastKeyDown = d3.event.keyCode;
    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
      this.svg.classed('ctrl', true);
    }
  }
  /** Key realse event @private */
  private keyUp(): void {
    const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
    this.lastKeyDown = -1;
    if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
      this.gNetwork.on('.drag', null);
      this.gVirutualDeploymentUnit.on('.drag', null);
      this.gConnectionPoint.on('.drag', null);
      this.gIntConnectionPoint.on('.drag', null);
      this.svg.classed('ctrl', false);
    }
  }
  /** Mosue Drag Line false if it is not satisfied @private */
  private deselectPath(): void {
    this.dragLine.classed('hidden', true).attr('d', 'M0,0L0,0');
  }
  /** Events handles when Shift Click to perform create cp @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
    this.selectedNode(nodeSelected, d);
  }
  /** Get confirmation Before Deleting the Node in Topology @private */
  private getDeleteNodeConfirmation(d: COMPOSERNODES): void {
    // eslint-disable-next-line security/detect-non-literal-fs-filename
    const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
    modalRef.componentInstance.topologyType = 'Delete';
    modalRef.componentInstance.topologyname = d.name;
    if (d.type === 'vdu') {
      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VDU';
    } else if (d.type === 'intvl') {
      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTVL';
    } else if (d.type === 'cp') {
      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
    } else if (d.type === 'intcp') {
      modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTCP';
    }
    modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
      if (result) {
        this.deleteNode(d);
      }
    }).catch((): void => {
      // Catch Navigation Error
  });
  }
  /** Delete nodes @private */
  private deleteNode(d: COMPOSERNODES): void {
    this.nodes.forEach((node: VNFD): void => {
      if (node.id === d.id) {
        if (d.type === 'cp') {
          if (this.vnfdPackageDetails['ext-cpd'] !== undefined) {
            let getRelatedVDUCPD: string; let getRelatedVDUID: string;
            const posExtCPD: number = this.vnfdPackageDetails['ext-cpd'].findIndex((e: EXTCPD): boolean => {
              if (e.id === d.name) {
                if (e['int-cpd'] !== undefined) {
                  getRelatedVDUCPD = e['int-cpd'].cpd; getRelatedVDUID = e['int-cpd']['vdu-id'];
                }
                return true;
              } else {
                return false;
              }
            });
            if (posExtCPD !== -1) {
              this.vnfdPackageDetails['ext-cpd'].splice(posExtCPD, 1);
            }
            if (getRelatedVDUCPD !== undefined && getRelatedVDUID !== undefined) {
              this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
                if (vdu.id === getRelatedVDUID) {
                  const posINTCPD: number = vdu['int-cpd'].findIndex((intCPD: VDUINTCPD): boolean => intCPD.id === getRelatedVDUCPD);
                  if (posINTCPD !== -1) {
                    vdu['int-cpd'].splice(posINTCPD, 1);
                  }
                }
              });
            }
          }
        } else if (d.type === 'intcp') {
          this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
            const posINTCPD: number = vdu['int-cpd'].findIndex((intCPD: VDUINTCPD): boolean => intCPD.id === d.id);
            if (posINTCPD !== -1) {
              vdu['int-cpd'].splice(posINTCPD, 1);
            }
          });
        } else if (d.type === 'intvl') {
          const posINTVLD: number = this.vnfdPackageDetails['int-virtual-link-desc'].findIndex((intVLD: IVLD): boolean => intVLD.id === d.id);
          if (posINTVLD !== -1) {
            this.vnfdPackageDetails['int-virtual-link-desc'].splice(posINTVLD, 1);
          }
          if (this.vnfdPackageDetails.vdu !== undefined) {
            this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU): void => {
              if (vduDetails['int-cpd'] !== undefined) {
                const newVDUintCPDArray: VDUINTCPD[] = vduDetails['int-cpd'].filter((item: VDUINTCPD): boolean => item['int-virtual-link-desc'] !== undefined ? item['int-virtual-link-desc'] !== d.id ? true : false : true);
                vduDetails['int-cpd'] = newVDUintCPDArray;
              }
            });
          }
        } else if (d.type === 'vdu') {
          const getRelatedExtCPD: string[] = [];
          const posVDU: number = this.vnfdPackageDetails.vdu.findIndex((vduDetails: VDU): boolean => {
            if (vduDetails.id === d.id) {
              if (vduDetails['int-cpd'] !== undefined) {
                vduDetails['int-cpd'].forEach((intCPDDetails: VDUINTCPD): void => {
                  if (intCPDDetails['int-virtual-link-desc'] === undefined) {
                    getRelatedExtCPD.push(intCPDDetails.id);
                  }
                });
              }
              return true;
            } else {
              return false;
            }
          });
          if (posVDU !== -1) {
            this.vnfdPackageDetails.vdu.splice(posVDU, 1);
          }
          getRelatedExtCPD.forEach((CPDID: string, index: number): void => {
            this.vnfdPackageDetails['ext-cpd'].forEach((extCPD: EXTCPD): void => {
              if (extCPD['int-cpd'] !== undefined) {
                if (extCPD['int-cpd'].cpd === CPDID) {
                  extCPD['int-cpd'] = {};
                }
              }
            });
          });
        } else {
          this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
        }
        this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
      }
    });
  }
  /** Get confirmation before deleting the ink in Topology @private */
  private getDeleteLinkConfirmation(d: Tick): void {
    this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.YOUCANNOTDELETELINK'));
  }
  /** Selected nodes @private */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private selectedNode(nodeSeleced: any, d: COMPOSERNODES): void {
    const alreadyIsActive: boolean = nodeSeleced.select('#' + d.id).classed(this.activeNode);
    this.deselectAllNodes();
    nodeSeleced.select('#' + d.id).classed(this.activeNode, !alreadyIsActive);
    if (d.type === 'vdu' && !alreadyIsActive) {
      this.vnfdPackageDetails.vdu.forEach((res: VDU): void => {
        if (res.id === d.id) {
          this.showRightSideInfo = 'vduInfo';
          this.vduInfo = res;
          this.oldVDUID = res.id;
        }
      });
    } else if (d.type === 'cp' && !alreadyIsActive) {
      this.vnfdPackageDetails['ext-cpd'].forEach((cp: EXTCPD): void => {
        const getCPDID: string = cp['int-cpd'] !== undefined ? cp['int-cpd'].cpd : cp.id;
        if (getCPDID === d.id) {
          this.showRightSideInfo = 'cpInfo';
          this.cpInfo = cp;
          this.oldCPID = cp.id;
        }
      });
    } else if (d.type === 'intvl' && !alreadyIsActive) {
      this.vnfdPackageDetails['int-virtual-link-desc'].forEach((ivld: IVLD): void => {
        if (ivld.id === d.id) {
          this.showRightSideInfo = 'intvlInfo';
          this.intvlInfo = ivld;
          this.oldintVLID = ivld.id;
        }
      });
    } else if (d.type === 'intcp' && !alreadyIsActive) {
      this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
        vdu['int-cpd'].forEach((intcpd: VDUINTCPD): void => {
          if (intcpd.id === d.id) {
            if (intcpd['int-virtual-link-desc'] !== undefined) {
              intcpd['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
                this.intcpInfo = vnir;
                this.showRightSideInfo = 'intcpInfo';
              });
            }
          }
        });
      });
    } else {
      this.showRightSideInfo = 'vnfdInfo';
    }
  }
  /** De-select all the selected nodes @private */
  private deselectAllNodes(): void {
    this.network.select('image').classed(this.activeNode, false);
    this.virutualDeploymentUnit.select('image').classed(this.activeNode, false);
    this.connectionPoint.select('image').classed(this.activeNode, false);
    this.intConnectionPoint.select('image').classed(this.activeNode, false);
  }
  /** Events handles when to drag using filter for the keys @private */
  private dragFilter(): boolean {
    return d3.event.ctrlKey && !d3.event.button;
  }
  /** Events handles when dragstarted @private */
  private dragstarted(d: COMPOSERNODES): void {
    d.fx = d.x;
    d.fy = d.y;
  }
  /** Events handles when dragged @private */
  private dragged(d: COMPOSERNODES): void {
    d.fx = d.x = d3.event.x;
    d.fy = d.y = d3.event.y;
  }
  /** Events handles when dragended @private */
  private dragended(d: COMPOSERNODES): void {
    if (this.forceSimulationActive) {
      d.fx = null;
      d.fy = null;
    } else {
      d.fx = d.x;
      d.fy = d.y;
      this.forceSimulationActive = false;
    }
  }
  /** Events handles when node double click   @private */
  private onNodedblClickToggleSidebar(): void {
    this.sideBarOpened = false;
  }
  /** Events handles when node single click   @private */
  private onNodeClickToggleSidebar(): void {
    this.sideBarOpened = true;
  }
}
