2 * Created by obarda on 6/28/2016.
4 /// <reference path="../../../../references"/>
5 module Sdc.Graph.Utils {
7 import ImageCreatorService = Sdc.Utils.ImageCreatorService;
8 import Module = Sdc.Models.Module;
9 export class CompositionGraphLinkUtils {
11 private p2pVL:Models.Components.Component;
12 private mp2mpVL:Models.Components.Component;
14 constructor(private linksFactory:Sdc.Utils.LinksFactory,
15 private loaderService:Services.LoaderService,
16 private generalGraphUtils:Sdc.Graph.Utils.CompositionGraphGeneralUtils,
17 private leftPaletteLoaderService:Services.Components.LeftPaletteLoaderService,
18 private componentInstanceFactory:Sdc.Utils.ComponentInstanceFactory,
19 private nodesFactory:Sdc.Utils.NodesFactory,
20 private commonGraphUtils: Sdc.Graph.Utils.CommonGraphUtils,
21 private matchCapabilitiesRequirementsUtils: Graph.Utils.MatchCapabilitiesRequirementsUtils) {
29 * Delete the link on server and then remove it from graph
31 * @param releaseLoading - true/false release the loader when finished
32 * @param link - the link to delete
34 public deleteLink = (cy:Cy.Instance, component:Models.Components.Component, releaseLoading:boolean, link:Cy.CollectionEdges) => {
36 this.loaderService.showLoader('composition-graph');
37 let onSuccessDeleteRelation = (response) => {
41 if (!releaseLoading) {
42 this.generalGraphUtils.getGraphUtilsServerUpdateQueue().addBlockingUIAction(
43 () => component.deleteRelation(link.data().relation).then(onSuccessDeleteRelation)
46 this.generalGraphUtils.getGraphUtilsServerUpdateQueue().addBlockingUIActionWithReleaseCallback(
47 () => component.deleteRelation(link.data().relation).then(onSuccessDeleteRelation),
48 () => this.loaderService.hideLoader('composition-graph'));
53 * create the link on server and than draw it on graph
54 * @param link - the link to create
58 public createLink = (link:Models.CompositionCiLinkBase, cy:Cy.Instance, component:Models.Components.Component):void => {
60 this.loaderService.showLoader('composition-graph');
62 let onSuccess:(response:Models.RelationshipModel) => void = (relation:Models.RelationshipModel) => {
63 link.setRelation(relation);
64 this.commonGraphUtils.insertLinkToGraph(cy, link);
67 link.updateLinkDirection();
69 this.generalGraphUtils.getGraphUtilsServerUpdateQueue().addBlockingUIActionWithReleaseCallback(
70 () => component.createRelation(link.relation).then(onSuccess),
71 () => this.loaderService.hideLoader('composition-graph')
76 public initScopeVls = ():void => {
78 let vls = this.leftPaletteLoaderService.getFullDataComponentList(Sdc.Utils.Constants.ResourceType.VL);
79 vls.forEach((item) => {
80 let key = _.find(Object.keys(item.capabilities), (key) => {
81 return _.includes(key.toLowerCase(), 'linkable');
83 let linkable = item.capabilities[key];
85 if (linkable[0].maxOccurrences == '2') {
86 this.p2pVL = _.find(vls, (component:Models.Components.Component) => {
87 return component.uniqueId === item.uniqueId;
90 } else {//assuming unbounded occurrences
91 this.mp2mpVL = _.find(vls, (component:Models.Components.Component) => {
92 return component.uniqueId === item.uniqueId;
99 private setVLlinks = (match:Models.MatchReqToReq, vl:Models.ComponentsInstances.ComponentInstance):Array<Models.RelationshipModel> => {
101 let relationship1 = new Models.Relationship();
102 let relationship2 = new Models.Relationship();
103 let newRelationshipModel1 = new Models.RelationshipModel();
104 let newRelationshipModel2 = new Models.RelationshipModel();
106 let capability:Models.Capability = vl.capabilities.findValueByKey('linkable')[0];
107 relationship1.setRelationProperties(capability, match.requirement);
108 relationship2.setRelationProperties(capability, match.secondRequirement);
110 newRelationshipModel1.setRelationshipModelParams(match.fromNode, vl.uniqueId, [relationship1]);
111 newRelationshipModel2.setRelationshipModelParams(match.toNode, vl.uniqueId, [relationship2]);
113 return [newRelationshipModel1, newRelationshipModel2];
116 private createVlinks = (cy:Cy.Instance, component:Models.Components.Component, matchReqToReq:Models.MatchReqToReq, vl:Models.Components.Component):void => {
118 let componentInstance:Models.ComponentsInstances.ComponentInstance = this.componentInstanceFactory.createComponentInstanceFromComponent(vl);
119 let fromNodePosition:Cy.Position = cy.getElementById(matchReqToReq.fromNode).relativePosition();
120 let toNodePosition:Cy.Position = cy.getElementById(matchReqToReq.toNode).relativePosition();
121 let location:Cy.Position = {
122 x: 0.5 * (fromNodePosition.x + toNodePosition.x),
123 y: 0.5 * (fromNodePosition.y + toNodePosition.y)
126 componentInstance.posX = location.x;
127 componentInstance.posY = location.y;
129 let onFailed:(error:any) => void = (error:any) => {
130 this.loaderService.hideLoader('composition-graph');
131 console.info('onFailed', error);
134 let onSuccess = (response:Models.ComponentsInstances.ComponentInstance):void => {
136 console.info('onSuccses', response);
137 response.requirements = new Models.RequirementsGroup(vl.requirements);
138 response.capabilities = new Models.CapabilitiesGroup(vl.capabilities);
139 response.componentVersion = vl.version;
140 response.setInstanceRC();
142 let newLinks = this.setVLlinks(matchReqToReq, response);
143 let newNode = this.nodesFactory.createNode(response);
145 this.commonGraphUtils.addComponentInstanceNodeToGraph(cy, newNode);
147 _.forEach(newLinks, (link) => {
148 let linkObg:Models.CompositionCiLinkBase = this.linksFactory.createGraphLink(cy, link, link.relationships[0]);
149 this.createLink(linkObg, cy, component);
152 component.createComponentInstance(componentInstance).then(onSuccess, onFailed);
155 private createSimpleLink = (match:Models.MatchReqToCapability, cy:Cy.Instance, component:Models.Components.Component):void => {
156 let newRelation:Models.RelationshipModel = match.matchToRelationModel();
157 let linkObg:Models.CompositionCiLinkBase = this.linksFactory.createGraphLink(cy,newRelation, newRelation.relationships[0]);
158 this.createLink(linkObg, cy, component);
161 public createLinkFromMenu = (cy:Cy.Instance, chosenMatch:Models.MatchBase, vl:Models.Components.Component, component:Models.Components.Component):void => {
164 if (chosenMatch && chosenMatch instanceof Models.MatchReqToReq) {
165 this.createVlinks(cy, component, chosenMatch, vl); //TODO orit implement
167 if (chosenMatch && chosenMatch instanceof Models.MatchReqToCapability) {
168 this.createSimpleLink(chosenMatch, cy, component);
175 * Filters the matches for UCPE links so that shown requirements and capabilites are only related to the selected ucpe-cp
178 * @param matchesArray
179 * @returns {Array<Models.MatchBase>}
181 public filterUcpeLinks(fromNode: Models.Graph.CompositionCiNodeBase, toNode: Models.Graph.CompositionCiNodeBase, matchesArray: Array<Models.MatchBase>): any {
183 let matchLink: Array<Models.MatchBase>;
185 if (fromNode.isUcpePart) {
186 matchLink = _.filter(matchesArray, (match: Models.MatchBase) => {
187 return match.isOwner(fromNode.id);
191 if (toNode.isUcpePart) {
192 matchLink = _.filter(matchesArray, (match: Models.MatchBase) => {
193 return match.isOwner(toNode.id);
196 return matchLink ? matchLink : matchesArray;
201 * open the connect link menu if the link drawn is valid - match requirements & capabilities
207 public onLinkDrawn(cy:Cy.Instance, fromNode:Cy.CollectionFirstNode, toNode:Cy.CollectionFirstNode):Models.RelationMenuDirectiveObj {
209 if(!this.commonGraphUtils.nodeLocationsCompatible(cy, fromNode, toNode)){ return null; }
210 let linkModel:Array<Models.CompositionCiLinkBase> = this.generalGraphUtils.getAllCompositionCiLinks(cy);
212 let possibleRelations:Array<Models.MatchBase> = this.matchCapabilitiesRequirementsUtils.getMatchedRequirementsCapabilities(fromNode.data().componentInstance,
213 toNode.data().componentInstance, linkModel, this.mp2mpVL); //TODO orit - add p2p and mp2mp
215 //filter relations found to limit to specific ucpe-cp
216 possibleRelations = this.filterUcpeLinks(fromNode.data(), toNode.data(), possibleRelations);
218 //if found possibleRelations between the nodes we create relation menu directive and open the link menu
219 if (possibleRelations.length) {
220 let menuPosition = this.generalGraphUtils.getLinkMenuPosition(cy, toNode.renderedPoint());
221 return new Models.RelationMenuDirectiveObj(fromNode.data(), toNode.data(), this.mp2mpVL, this.p2pVL, menuPosition, possibleRelations);
228 * when we drag instance in to UCPE or out of UCPE - get all links we need to delete - one node in ucpe and one node outside of ucpe
229 * @param node - the node we dragged into or out of the ucpe
231 public deleteLinksWhenNodeMovedFromOrToUCPE(component:Models.Components.Component, cy:Cy.Instance, nodeMoved:Cy.CollectionNodes, vlsPendingDeletion?:Cy.CollectionNodes):void {
234 let linksToDelete:Cy.CollectionElements = cy.collection();
235 _.forEach(nodeMoved.neighborhood('node'), (neighborNode)=>{
237 if(neighborNode.data().isUcpePart){ //existing connections to ucpe or ucpe-cp - we want to delete even though nodeLocationsCompatible will technically return true
238 linksToDelete = linksToDelete.add(nodeMoved.edgesWith(neighborNode)); // This will delete the ucpe-host-link, or the vl-ucpe-link if nodeMoved is vl
239 } else if(!this.commonGraphUtils.nodeLocationsCompatible(cy, nodeMoved, neighborNode)){ //connection to regular node or vl - check if locations are compatible
240 if(!vlsPendingDeletion || !vlsPendingDeletion.intersect(neighborNode).length){ //Check if this is a link to a VL pending deletion, to prevent double deletion of between the node moved and vl
241 linksToDelete = linksToDelete.add(nodeMoved.edgesWith(neighborNode));
248 linksToDelete.each((i, link)=>{
249 this.deleteLink(cy, component, false, link);
256 * Creates a hostedOn link between a VF and UCPE
262 public createVfToUcpeLink = (component: Models.Components.Component, cy:Cy.Instance, ucpeNode:Models.Graph.NodeUcpe, vfNode:Models.Graph.CompositionCiNodeVf):void => {
263 let hostedOnMatch:Models.MatchReqToCapability = this.generalGraphUtils.canBeHostedOn(cy, ucpeNode.componentInstance, vfNode.componentInstance);
264 /* create relation */
265 let newRelation = new Models.RelationshipModel();
266 newRelation.fromNode = ucpeNode.id;
267 newRelation.toNode = vfNode.id;
269 let link:Models.CompositionCiLinkBase = this.linksFactory.createUcpeHostLink(newRelation);
270 link.relation = hostedOnMatch.matchToRelationModel();
271 this.createLink(link, cy, component);
276 * Handles click event on links.
277 * If one edge selected: do nothing.
278 /*Two edges selected - always select all
279 /* Three or more edges: first click - select all, secondary click - select single.
283 public handleLinkClick(cy:Cy.Instance, event : Cy.EventObject) {
284 if(cy.$('edge:selected').length > 2 && event.cyTarget[0].selected()) {
285 cy.$(':selected').unselect();
288 let vl: Cy.CollectionNodes = event.cyTarget[0].target('.vl-node');
289 let connectedEdges:Cy.CollectionEdges = vl.connectedEdges();
290 if (vl.length && connectedEdges.length > 1) {
294 connectedEdges.select();
303 * Calculates the position for the menu that modifies an existing link
305 * @param elementWidth
306 * @param elementHeight
307 * @returns {Sdc.Models.Graph.Point}
309 public calculateLinkMenuPosition(event, elementWidth, elementHeight): Sdc.Models.Graph.Point {
310 let point: Sdc.Models.Graph.Point = new Sdc.Models.Graph.Point(event.originalEvent.x,event.originalEvent.y);
311 if(event.originalEvent.view.screen.height-elementHeight<point.y){
312 point.y = event.originalEvent.view.screen.height-elementHeight;
314 if(event.originalEvent.view.screen.width-elementWidth<point.x){
315 point.x = event.originalEvent.view.screen.width-elementWidth;
322 * Gets the menu that is displayed when you click an existing link.
325 * @returns {Models.LinkMenu}
327 public getModifyLinkMenu(link:Cy.CollectionFirstEdge, event:Cy.EventObject):Models.LinkMenu{
328 let point:Sdc.Models.Graph.Point = this.calculateLinkMenuPosition(event,Sdc.Utils.Constants.GraphUIObjects.MENU_LINK_VL_WIDTH_OFFSET,Sdc.Utils.Constants.GraphUIObjects.MENU_LINK_VL_HEIGHT_OFFSET);
329 let menu:Models.LinkMenu = new Models.LinkMenu(point, true, link);
337 CompositionGraphLinkUtils.$inject = [
340 'CompositionGraphGeneralUtils',
341 'LeftPaletteLoaderService',
342 'ComponentInstanceFactory',
345 'MatchCapabilitiesRequirementsUtils'