Catalog alignment
[sdc.git] / catalog-ui / src / app / ng2 / pages / 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 import { Injectable } from '@angular/core';
21 import {
22     CapabilitiesGroup, Capability, ComponentInstance, CompositionCiLinkBase,
23     CompositionCiNodeBase, Match, Requirement, RequirementsGroup
24 } from 'app/models';
25 import * as _ from 'lodash';
26
27 /**
28  * Created by obarda on 1/1/2017.
29  */
30 @Injectable()
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             const 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         const 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     public getMatchedRequirementsCapabilities(fromComponentInstance: ComponentInstance,
77                                               toComponentInstance: ComponentInstance,
78                                               links: CompositionCiLinkBase[]): Match[] {
79         const fromToMatches: Match[] = this.getMatches(fromComponentInstance.requirements,
80             toComponentInstance.capabilities,
81             links,
82             fromComponentInstance.uniqueId,
83             toComponentInstance.uniqueId, true);
84         const toFromMatches: Match[] = this.getMatches(toComponentInstance.requirements,
85             fromComponentInstance.capabilities,
86             links,
87             toComponentInstance.uniqueId,
88             fromComponentInstance.uniqueId, false);
89
90         return fromToMatches.concat(toFromMatches);
91     }
92
93     /***** REFACTORED FUNCTIONS START HERE *****/
94
95     public getMatches(requirements: RequirementsGroup, capabilities: CapabilitiesGroup, links: CompositionCiLinkBase[],
96                       fromId: string, toId: string, isFromTo: boolean): Match[] {
97         const matches: Match[] = [];
98         const unfulfilledReqs = this.getUnfulfilledRequirements(fromId, requirements, links);
99         _.forEach(unfulfilledReqs, (req) => {
100             _.forEach(_.flatten(_.values(capabilities)), (capability: Capability) => {
101                 if (this.isMatch(req, capability)) {
102                     if (isFromTo) {
103                         matches.push(new Match(req, capability, isFromTo, fromId, toId));
104                     } else {
105                         matches.push(new Match(req, capability, isFromTo, toId, fromId));
106                     }
107                 }
108             });
109         });
110         return matches;
111     }
112
113     public getUnfulfilledRequirements = (fromNodeId: string, requirements: RequirementsGroup, links: CompositionCiLinkBase[]): Requirement[] => {
114         const requirementArray: Requirement[] = [];
115         _.forEach(_.flatten(_.values(requirements)), (requirement: Requirement) => {
116             const reqFulfilled = this.isRequirementFulfilled(fromNodeId, requirement, links);
117             if (requirement.name !== 'dependency' && requirement.parentName !== 'dependency' && !reqFulfilled) {
118                 requirementArray.push(requirement);
119             }
120         });
121         return requirementArray;
122     }
123
124     /**
125      * Returns true if there is a match between the capabilities and requirements that are passed in
126      * @param requirements
127      * @param capabilities
128      * @returns {boolean}
129      */
130     public containsMatch = (requirements: Requirement[], capabilities: CapabilitiesGroup): boolean => {
131         return _.some(requirements, (req: Requirement) => {
132             return _.some(_.flatten(_.values(capabilities)), (capability: Capability) => {
133                 return this.isMatch(req, capability);
134             });
135         });
136     }
137
138     public hasUnfulfilledRequirementContainingMatch = (node: CompositionCiNodeBase, componentRequirements: Requirement[], capabilities: CapabilitiesGroup, links: CompositionCiLinkBase[]) => {
139         if (node && node.componentInstance) {
140             // Check if node has unfulfilled requirement that can be filled by component (#2)
141             const nodeRequirements: Requirement[] = this.getUnfulfilledRequirements(node.componentInstance.uniqueId, node.componentInstance.requirements, links);
142             if (!nodeRequirements.length) {
143                 return false;
144             }
145             if (this.containsMatch(nodeRequirements, capabilities)) {
146                 return true;
147             }
148         }
149     }
150
151     /**
152      * Returns array of nodes that can connect to the component.
153      * In order to connect, one of the following conditions must be met:
154      * 1. component has an unfulfilled requirement that matches a node's capabilities
155      * 2. node has an unfulfilled requirement that matches the component's capabilities
156      * 3. vl is passed in which has the capability to fulfill requirement from component and requirement on node.
157      */
158     public findMatchingNodesToComponentInstance(componentInstance: ComponentInstance, nodeDataArray: CompositionCiNodeBase[], links: CompositionCiLinkBase[]): any[] {
159         return _.filter(nodeDataArray, (node: CompositionCiNodeBase) => {
160             const matchedRequirementsCapabilities = this.getMatchedRequirementsCapabilities(node.componentInstance, componentInstance, links);
161             return matchedRequirementsCapabilities && matchedRequirementsCapabilities.length > 0;
162         });
163     }
164
165     public isMatch(requirement: Requirement, capability: Capability): boolean {
166         if (capability.type === requirement.capability) {
167             if (requirement.node) {
168                 if (_.includes(capability.capabilitySources, requirement.node)) {
169                     return true;
170                 }
171             } else {
172                 return true;
173             }
174         }
175         return false;
176     }
177
178     private isRequirementFulfilled(fromNodeId: string, requirement: any, links: CompositionCiLinkBase[]): boolean {
179         return _.some(links, {
180             relation: {
181                 fromNode: fromNodeId,
182                 relationships: [{
183                     relation: {
184                         requirementOwnerId: requirement.ownerId,
185                         requirement: requirement.name,
186                         relationship: {
187                             type: requirement.relationship
188                         }
189
190                     }
191                 }]
192             }
193         });
194     }
195
196 }