6a02381902fb0cda86718293afb3d9ca04d45fde
[sdc.git] /
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 {
22     Requirement, CompositionCiLinkBase, CapabilitiesGroup, RequirementsGroup, Match,
23     CompositionCiNodeBase, Component, Capability
24 } from "app/models";
25 import {ComponentInstance} from "../../../../models/componentsInstances/componentInstance";
26 /**
27  * Created by obarda on 1/1/2017.
28  */
29
30 export class MatchCapabilitiesRequirementsUtils {
31
32     /**
33      * Shows + icon in corner of each node passed in
34      * @param filteredNodesData
35      * @param cy
36      */
37     public highlightMatchingComponents(filteredNodesData, cy:Cy.Instance) {
38         _.each(filteredNodesData, (data:any) => {
39             let node = cy.getElementById(data.id);
40             cy.emit('showhandle', [node]);
41         });
42     }
43
44     /**
45      * Adds opacity to each node that cannot be linked to hovered node
46      * @param filteredNodesData
47      * @param nodesData
48      * @param cy
49      * @param hoveredNodeData
50      */
51     public fadeNonMachingComponents(filteredNodesData, nodesData, cy:Cy.Instance, hoveredNodeData?) {
52         let fadeNodes = _.xorWith(nodesData, filteredNodesData, (node1, node2) => {
53             return node1.id === node2.id;
54         });
55         if (hoveredNodeData) {
56             _.remove(fadeNodes, hoveredNodeData);
57         }
58         cy.batch(()=> {
59             _.each(fadeNodes, (node) => {
60                 cy.getElementById(node.id).style({'background-image-opacity': 0.4});
61             });
62         })
63     }
64
65     /**
66      * Resets all nodes to regular opacity
67      * @param cy
68      */
69     public resetFadedNodes(cy:Cy.Instance) {
70         cy.batch(()=> {
71             cy.nodes().style({'background-image-opacity': 1});
72         })
73     }
74
75     private static isRequirementFulfilled(fromNodeId:string, requirement:any, links:Array<CompositionCiLinkBase>):boolean {
76         return _.some(links, {
77             'relation': {
78                 'fromNode': fromNodeId,
79                 'relationships': [{
80                     'requirementOwnerId': requirement.ownerId,
81                     'requirement': requirement.name,
82                     'relationship': {
83                         'type': requirement.relationship
84                     }
85                 }
86                 ]
87             }
88         });
89     };
90
91     private static isMatch(requirement:Requirement, capability:Capability):boolean {
92         if (capability.type === requirement.capability) {
93             if (requirement.node) {
94                 if (_.includes(capability.capabilitySources, requirement.node)) {
95                     return true;
96                 }
97             } else {
98                 return true;
99             }
100         }
101         return false;
102     };
103
104     public getMatchedRequirementsCapabilities(fromComponentInstance:ComponentInstance,
105                                               toComponentInstance:ComponentInstance,
106                                               links:Array<CompositionCiLinkBase>):Array<Match> {
107         let fromToMatches:Array<Match> = this.getMatches(fromComponentInstance.requirements,
108             toComponentInstance.capabilities,
109             links,
110             fromComponentInstance.uniqueId,
111             toComponentInstance.uniqueId, true);
112         let toFromMatches:Array<Match> = this.getMatches(toComponentInstance.requirements,
113             fromComponentInstance.capabilities,
114             links,
115             fromComponentInstance.uniqueId,
116             toComponentInstance.uniqueId, false);
117
118         return fromToMatches.concat(toFromMatches);
119     }
120
121     /***** REFACTORED FUNCTIONS START HERE *****/
122
123     public getMatches(requirements:RequirementsGroup, capabilities:CapabilitiesGroup, links:Array<CompositionCiLinkBase>,
124                       fromId:string, toId:string, isFromTo: boolean):Array<Match> {
125         let matches:Array<Match> = [];
126         let unfulfilledReqs = this.getUnfulfilledRequirements(fromId, requirements, links);
127         _.forEach(unfulfilledReqs, (req)=> {
128             _.forEach(_.flatten(_.values(capabilities)), (capability:Capability)=> {
129                 if (MatchCapabilitiesRequirementsUtils.isMatch(req, capability)) {
130                     if(isFromTo) {
131                         matches.push(new Match(req, capability, isFromTo, fromId, toId));
132                     } else{
133                         matches.push(new Match(req, capability, isFromTo, toId, fromId));
134                     }
135                 }
136             });
137         });
138         return matches;
139     }
140
141     public getUnfulfilledRequirements = (fromNodeId:string, requirements:RequirementsGroup, links:Array<CompositionCiLinkBase>):Array<Requirement>=> {
142
143         let requirementArray:Array<Requirement> = [];
144         _.forEach(_.flatten(_.values(requirements)), (requirement:Requirement)=> {
145             if (requirement.name !== "dependency" && !MatchCapabilitiesRequirementsUtils.isRequirementFulfilled(fromNodeId, requirement, links)) {
146                 requirementArray.push(requirement);
147             }
148         });
149         return requirementArray;
150     };
151
152
153     /**
154      * Returns true if there is a match between the capabilities and requirements that are passed in
155      * @param requirements
156      * @param capabilities
157      * @returns {boolean}
158      */
159     public containsMatch = (requirements:Array<Requirement>, capabilities:CapabilitiesGroup):boolean => {
160         return _.some(requirements, (req:Requirement)=> {
161             return _.some(_.flatten(_.values(capabilities)), (capability:Capability) => {
162                 return MatchCapabilitiesRequirementsUtils.isMatch(req, capability);
163             });
164         });
165     };
166
167     /**
168      * Returns array of nodes that can connect to the component.
169      * In order to connect, one of the following conditions must be met:
170      * 1. component has an unfulfilled requirement that matches a node's capabilities
171      * 2. node has an unfulfilled requirement that matches the component's capabilities
172      * 3. vl is passed in which has the capability to fulfill requirement from component and requirement on node.
173      */
174     public findMatchingNodes(component:Component, nodeDataArray:Array<CompositionCiNodeBase>,
175                              links:Array<CompositionCiLinkBase>):Array<any> //TODO allow for VL array and TEST
176     {
177         let componentRequirements:Array<Requirement> = this.getUnfulfilledRequirements(component.uniqueId, component.requirements, links);
178         return _.filter(nodeDataArray, (node:any)=> {
179             if (node && node.componentInstance) {
180
181                 //Check if component has an unfulfilled requirement that can be met by one of nodes's capabilities (#1)
182                 if (componentRequirements.length && node.category !== 'groupCp' && this.containsMatch(componentRequirements, node.componentInstance.capabilities)) {
183                     return true;
184
185                 } else { //Check if node has unfulfilled requirement that can be filled by component (#2)
186                     let nodeRequirements:Array<Requirement> = this.getUnfulfilledRequirements(node.componentInstance.uniqueId, node.componentInstance.requirements, links);
187                     if (!nodeRequirements.length) return false;
188                     if (this.containsMatch(nodeRequirements, component.capabilities)) {
189                         return true;
190                     }
191                 }
192             }
193         });
194     }
195 }
196
197 MatchCapabilitiesRequirementsUtils.$inject = [];