/* * Copyright 2017 Cray Inc. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.admin.ironic') .factory('horizon.dashboard.admin.ironic.graph.service', graphService); graphService.$inject = []; function graphService() { var service = { Graph: Graph }; /** * @description Class for representing and manipulating undirected * graphs * * @property {object} vertices - Associative array of vertex objects * indexed by property name * @return {object} Graph */ function Graph() { this.vertices = {}; } Graph.prototype.getVertex = function(vertexName) { var vertex = null; if (this.vertices.hasOwnProperty(vertexName)) { vertex = this.vertices[vertexName]; } return vertex; }; /** * @description Add a vertex to this graph * * @param {string} name - Vertex name * @param {object} data - Vertex data * @returns {object} - Newly created vertex */ Graph.prototype.addVertex = function(name, data) { var vertex = {name: name, data: data, adjacents: []}; this.vertices[name] = vertex; return vertex; }; /** * @description Add an undirected edge between two vertices * * @param {string} vertexName1 - Name of first vertex * @param {string} vertexName2 - Name of second vertex * @returns {void} */ Graph.prototype.addEdge = function(vertexName1, vertexName2) { this.vertices[vertexName1].adjacents.push(vertexName2); this.vertices[vertexName2].adjacents.push(vertexName1); }; /** * @description Depth-first-search graph traversal utility function * * @param {object} vertex - Root vertex from which traversal will begin. * It is assumed that this vertex has not already been visited as part * of this traversal. * @param {object} visited - Associative array. Each named property * corresponds to a vertex with the same name, and has boolean value * indicating whether the vertex has been already visited. * @param {object[]} component - Array of vertices that define a strongly * connected component. * @returns {void} */ Graph.prototype._dfsTraverse = function(vertex, visited, component) { var graph = this; visited[vertex.name] = true; component.push(vertex); /* eslint-disable no-unused-vars */ angular.forEach(vertex.adjacents, function(vertexName) { if (!visited[vertexName]) { graph._dfsTraverse(graph.vertices[vertexName], visited, component); } }); /* eslint-enable no-unused-vars */ }; /** * @description Perform a depth-first-search on a specified graph to * find strongly connected components. A user provided function will * be called to process each component. * * @param {function} componentFunc - Function called on each strongly * connected component. Accepts arguments: array of vertex objects, and * user-provided extra data that can be used in processing the component. * @param {object} extra - Extra data that is passed into the component * processing function. * @returns {void} */ Graph.prototype.dfs = function(componentFunc, extra) { var graph = this; var visited = {}; angular.forEach( graph.vertices, function(unused, name) { visited[name] = false; }); angular.forEach(this.vertices, function(vertex, vertexName) { if (!visited[vertexName]) { var component = []; graph._dfsTraverse(vertex, visited, component); componentFunc(component, extra); } }); }; return service; } })();