Initial import of Angular5 components services and modules

Change-Id: I3953f1fbf7d5697a1c6d432808dd17d816ec285a
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts b/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts
new file mode 100644
index 0000000..8d9d3c6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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.
+ */
+import { Injectable } from '@angular/core';
+import { GlyphService } from './glyph.service';
+import { LogService } from '../../log.service';
+import { SvgUtilService } from './svgutil.service';
+import * as d3 from 'd3';
+
+const vboxSize = 50;
+const cornerSize = vboxSize / 10;
+const viewBox = '0 0 ' + vboxSize + ' ' + vboxSize;
+
+export const glyphMapping = new Map<string, string>([
+    // Maps icon ID to the glyph ID it uses.
+    // NOTE: icon ID maps to a CSS class for styling that icon
+    ['active', 'checkMark'],
+    ['inactive','xMark'],
+
+    ['plus','plus'],
+    ['minus','minus'],
+    ['play','play'],
+    ['stop','stop'],
+
+    ['upload','upload'],
+    ['download','download'],
+    ['delta','delta'],
+    ['nonzero','nonzero'],
+    ['close','xClose'],
+
+    ['topo','topo'],
+
+    ['refresh','refresh'],
+    ['query','query'],
+    ['garbage','garbage'],
+
+
+    ['upArrow','triangleUp'],
+    ['downArrow','triangleDown'],
+
+    ['appInactive','unknown'],
+
+    ['node','node'],
+    ['devIcon_SWITCH','switch'],
+    ['devIcon_ROADM','roadm'],
+    ['devIcon_OTN','otn'],
+
+    ['portIcon_DEFAULT','m_ports'],
+
+    ['meter','meterTable'], // TODO: m_meter icon?
+
+    ['deviceTable','switch'],
+    ['flowTable','flowTable'],
+    ['portTable','portTable'],
+    ['groupTable','groupTable'],
+    ['meterTable','meterTable'],
+    ['pipeconfTable','pipeconfTable'],
+
+    ['hostIcon_endstation','endstation'],
+    ['hostIcon_router','router'],
+    ['hostIcon_bgpSpeaker','bgpSpeaker'],
+
+    // navigation menu icons...
+    ['nav_apps','bird'],
+    ['nav_settings','cog'],
+    ['nav_cluster','node'],
+    ['nav_processors','allTraffic'],
+
+    ['nav_topo','topo'],
+    ['nav_topo2','m_cloud'],
+    ['nav_devs','switch'],
+    ['nav_links','ports'],
+    ['nav_hosts','endstation'],
+    ['nav_intents','relatedIntents'],
+    ['nav_tunnels','ports'], // TODO: use tunnel glyph, when available
+    ['nav_yang','yang'],
+]);
+
+/**
+ * ONOS GUI -- SVG -- Icon Service
+ */
+@Injectable()
+export class IconService {
+
+    constructor(
+        private gs: GlyphService,
+        private log: LogService,
+        private sus: SvgUtilService
+    ) {
+
+        this.log.debug('IconService constructed');
+    }
+
+    ensureIconLibDefs() {
+        let body = d3.select('body');
+        let svg = body.select('svg#IconLibDefs');
+        if (svg.empty()) {
+            svg = body.append('svg').attr('id', 'IconLibDefs');
+            svg.append('defs');
+        }
+        return svg.select('defs');
+    }
+
+    /**
+     * Load an icon
+     *
+     * @param div A D3 selection of the '&lt;div&gt;' element into which icon should load
+     * @param glyphId Identifies the glyph to use
+     * @param size The dimension of icon in pixels. Defaults to 20.
+     * @param installGlyph If truthy, will cause the glyph to be added to
+     *      well-known defs element. Defaults to false.
+     * @param svgClass The CSS class used to identify the SVG layer.
+     *      Defaults to 'embeddedIcon'.
+     */
+    loadIcon(div, glyphId: string = 'unknown', size: number = 20, installGlyph: boolean = true, svgClass: string = 'embeddedIcon') {
+        let dim = size || 20;
+        let svgCls = svgClass || 'embeddedIcon';
+        let gid = glyphId || 'unknown';
+        let g;
+        let svgIcon: any;
+
+        if (installGlyph) {
+            this.gs.loadDefs(this.ensureIconLibDefs(), [gid], true);
+        }
+        this.log.warn('loadEmbeddedIcon. install done');
+
+        svgIcon = div
+            .append('svg')
+            .attr('class', svgCls)
+            .attr('width', dim)
+            .attr('height', dim)
+            .attr('viewBox', viewBox);
+
+        g = svgIcon.append('g')
+            .attr('class', 'icon');
+
+        g.append('rect')
+            .attr('width', vboxSize)
+            .attr('height', vboxSize)
+            .attr('rx', cornerSize);
+
+        g.append('use')
+            .attr('width', vboxSize)
+            .attr('height', vboxSize)
+            .attr('class', 'glyph')
+            .attr('xlink:href', '#' + gid);
+    }
+
+    /**
+     * Load an icon by class.
+     * @param div A D3 selection of the <DIV> element into which icon should load
+     * @param iconCls The CSS class used to identify the icon
+     * @param {number} size The dimension of icon in pixels. Defaults to 20.
+     * @param {boolean} installGlyph If truthy, will cause the glyph to be added to
+     *      well-known defs element. Defaults to false.
+     * @param svgClass The CSS class used to identify the SVG layer.
+     *      Defaults to 'embeddedIcon'.
+     */
+    loadIconByClass(div, iconCls: string, size: number, installGlyph: boolean, svgClass='embeddedIcon') {
+        this.loadIcon(div, glyphMapping.get(iconCls), size, installGlyph, svgClass);
+        div.select('svg g').classed(iconCls, true);
+    }
+
+    /**
+     * Load an embedded icon.
+     */
+    loadEmbeddedIcon(div, iconCls: string, size: number) {
+        this.loadIconByClass(div, iconCls, size, true);
+    }
+
+    /**
+     * Load an icon only to the svg defs collection
+     *
+     * Note: This is added for use with IconComponent, where the icon's
+     * svg element is defined in the component template (and not built
+     * inline using d3 manipulation
+     *
+     * @param iconCls The icon class as a string
+     */
+    loadIconDef(iconCls: string): void {
+        this.gs.loadDefs(this.ensureIconLibDefs(), [glyphMapping.get(iconCls)], true);
+        this.log.debug('icon defintion', iconCls, 'added to defs');
+    }
+
+
+    /**
+     * Add a device icon
+     *
+     * Adds a device glyph to the specified element.
+     * Returns the D3 selection of the glyph (use) element.
+     */
+    addDeviceIcon(elem, glyphId, iconDim) {
+        let gid = this.gs.glyphDefined(glyphId) ? glyphId : 'query';
+        return elem.append('use').attr({
+            'xlink:href': '#' + gid,
+            width: iconDim,
+            height: iconDim,
+        });
+    }
+
+    addHostIcon(elem, radius, glyphId) {
+        let dim = radius * 1.5;
+        let xlate = -dim / 2;
+        let g = elem.append('g')
+                .attr('class', 'svgIcon hostIcon');
+
+        g.append('circle').attr('r', radius);
+
+        g.append('use').attr({
+            'xlink:href': '#' + glyphId,
+            width: dim,
+            height: dim,
+            transform: this.sus.translate(xlate, xlate),
+        });
+        return g;
+    }
+
+    registerIconMapping(iconId, glyphId) {
+        if (glyphMapping[iconId]) {
+            this.log.warn('Icon with id', iconId, 'already mapped. Ignoring.');
+        } else {
+            // map icon-->glyph
+            glyphMapping[iconId] = glyphId;
+            // make sure definition is installed
+            this.gs.loadDefs(this.ensureIconLibDefs(), [glyphId], true);
+        }
+    }
+}