re base code
[sdc.git] / catalog-ui / src / app / directives / graphs-v2 / composition-graph / utils / match-capability-requierment-utils.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 import * as _ from "lodash";
22 import {
23     Requirement, CompositionCiLinkBase, CapabilitiesGroup, RequirementsGroup, Match,
24     CompositionCiNodeBase, Component, Capability
25 } from "app/models";
26 import {ComponentInstance} from "../../../../models/componentsInstances/componentInstance";
27 /**
28  * Created by obarda on 1/1/2017.
29  */
30
31 export class MatchCapabilitiesRequirementsUtils {
32
33     /**
34      * Shows + icon in corner of each node passed in
35      * @param filteredNodesData
36      * @param cy
37      */
38     public highlightMatchingComponents(filteredNodesData, cy:Cy.Instance) {
39         _.each(filteredNodesData, (data:any) => {
40             let node = cy.getElementById(data.id);
41             cy.emit('showhandle', [node]);
42         });
43     }
44
45     /**
46      * Adds opacity to each node that cannot be linked to hovered node
47      * @param filteredNodesData
48      * @param nodesData
49      * @param cy
50      * @param hoveredNodeData
51      */
52     public fadeNonMachingComponents(filteredNodesData, nodesData, cy:Cy.Instance, hoveredNodeData?) {
53         let fadeNodes = _.xorWith(nodesData, filteredNodesData, (node1, node2) => {
54             return node1.id === node2.id;
55         });
56         if (hoveredNodeData) {
57             _.remove(fadeNodes, hoveredNodeData);
58         }
59         cy.batch(()=> {
60             _.each(fadeNodes, (node) => {
61                 cy.getElementById(node.id).style({'background-image-opacity': 0.4});
62             });
63         })
64     }
65
66     /**
67      * Resets all nodes to regular opacity
68      * @param cy
69      */
70     public resetFadedNodes(cy:Cy.Instance) {
71         cy.batch(()=> {
72             cy.nodes().style({'background-image-opacity': 1});
73         })
74     }
75
76     private static isRequirementFulfilled(fromNodeId:string, requirement:any, links:Array<CompositionCiLinkBase>):boolean {
77         if(requirement.maxOccurrences === 'UNBOUNDED'){
78             return false;
79         }
80         let linksWithThisReq:Array<CompositionCiLinkBase> = _.filter(links, {
81             'relation': {
82                 'fromNode': fromNodeId,
83                 'relationships': [{
84                     'relation':{
85                         'requirementOwnerId': requirement.ownerId,
86                         'requirement': requirement.name,
87                         'relationship': {
88                             'type': requirement.capability
89                         }
90
91                     }
92                 }]
93             }
94         });
95         return linksWithThisReq.length == requirement.maxOccurrences;
96     };
97
98     private static isMatch(requirement:Requirement, capability:Capability):boolean {
99         if (capability.type === requirement.capability) {
100             if (requirement.node) {
101                 if (_.includes(capability.capabilitySources, requirement.node)) {
102                     return true;
103                 }
104             } else {
105                 return true;
106             }
107         }
108         return false;
109     };
110
111     public getMatchedRequirementsCapabilities(fromComponentInstance:ComponentInstance,
112                                               toComponentInstance:ComponentInstance,
113                                               links:Array<CompositionCiLinkBase>):Array<Match> {
114         let fromToMatches:Array<Match> = this.getMatches(fromComponentInstance.requirements,
115             toComponentInstance.capabilities,
116             links,
117             fromComponentInstance.uniqueId,
118             toComponentInstance.uniqueId, true);
119         let toFromMatches:Array<Match> = this.getMatches(toComponentInstance.requirements,
120             fromComponentInstance.capabilities,
121             links,
122             fromComponentInstance.uniqueId,
123             toComponentInstance.uniqueId, false);
124
125         return fromToMatches.concat(toFromMatches);
126     }
127
128     /***** REFACTORED FUNCTIONS START HERE *****/
129
130     public getMatches(requirements:RequirementsGroup, capabilities:CapabilitiesGroup, links:Array<CompositionCiLinkBase>,
131                       fromId:string, toId:string, isFromTo: boolean):Array<Match> {
132         let matches:Array<Match> = [];
133         let unfulfilledReqs = this.getUnfulfilledRequirements(fromId, requirements, links);
134         _.forEach(unfulfilledReqs, (req)=> {
135             _.forEach(_.flatten(_.values(capabilities)), (capability:Capability)=> {
136                 if (MatchCapabilitiesRequirementsUtils.isMatch(req, capability)) {
137                     if(isFromTo) {
138                         matches.push(new Match(req, capability, isFromTo, fromId, toId));
139                     } else{
140                         matches.push(new Match(req, capability, isFromTo, toId, fromId));
141                     }
142                 }
143             });
144         });
145         return matches;
146     }
147
148     public getUnfulfilledRequirements = (fromNodeId:string, requirements:RequirementsGroup, links:Array<CompositionCiLinkBase>):Array<Requirement>=> {
149
150         let requirementArray:Array<Requirement> = [];
151         _.forEach(_.flatten(_.values(requirements)), (requirement:Requirement)=> {
152             if (requirement.name !== 'dependency' && requirement.parentName !== 'dependency' && !MatchCapabilitiesRequirementsUtils.isRequirementFulfilled(fromNodeId, requirement, links)) {
153                 requirementArray.push(requirement);
154             }
155         });
156         return requirementArray;
157     };
158
159
160     /**
161      * Returns true if there is a match between the capabilities and requirements that are passed in
162      * @param requirements
163      * @param capabilities
164      * @returns {boolean}
165      */
166     public containsMatch = (requirements:Array<Requirement>, capabilities:CapabilitiesGroup):boolean => {
167         return _.some(requirements, (req:Requirement)=> {
168             return _.some(_.flatten(_.values(capabilities)), (capability:Capability) => {
169                 return MatchCapabilitiesRequirementsUtils.isMatch(req, capability);
170             });
171         });
172     };
173
174     /**
175      * Returns array of nodes that can connect to the component.
176      * In order to connect, one of the following conditions must be met:
177      * 1. component has an unfulfilled requirement that matches a node's capabilities
178      * 2. node has an unfulfilled requirement that matches the component's capabilities
179      * 3. vl is passed in which has the capability to fulfill requirement from component and requirement on node.
180      */
181     public findMatchingNodes(component:Component, nodeDataArray:Array<CompositionCiNodeBase>,
182                              links:Array<CompositionCiLinkBase>):Array<any> //TODO allow for VL array and TEST
183     {
184         let componentRequirements:Array<Requirement> = this.getUnfulfilledRequirements(component.uniqueId, component.requirements, links);
185         return _.filter(nodeDataArray, (node:any)=> {
186             if (node && node.componentInstance) {
187
188                 //Check if component has an unfulfilled requirement that can be met by one of nodes's capabilities (#1)
189                 if (componentRequirements.length && node.category !== 'groupCp' && this.containsMatch(componentRequirements, node.componentInstance.capabilities)) {
190                     return true;
191
192                 } else { //Check if node has unfulfilled requirement that can be filled by component (#2)
193                     let nodeRequirements:Array<Requirement> = this.getUnfulfilledRequirements(node.componentInstance.uniqueId, node.componentInstance.requirements, links);
194                     if (!nodeRequirements.length) return false;
195                     if (this.containsMatch(nodeRequirements, component.capabilities)) {
196                         return true;
197                     }
198                 }
199             }
200         });
201     }
202 }
203
204 MatchCapabilitiesRequirementsUtils.$inject = [];