[CORD-2719] Consider previous position of existing nodes in the graph

Change-Id: I1c814604391be3653d0515dfa3daf88cd780ed4a
diff --git a/src/app/service-graph/components/graph/graph.component.html b/src/app/service-graph/components/graph/graph.component.html
index ad3d0da..1db00fc 100644
--- a/src/app/service-graph/components/graph/graph.component.html
+++ b/src/app/service-graph/components/graph/graph.component.html
@@ -22,7 +22,7 @@
   </div>
   <a ng-click="vm.closeFullscreen()" class="close-btn"><i class="fa fa-times"></i></a>
   <svg></svg>
-  <div class="row">
+  <div class="row" ng-if="!vm.loader">
     <div class="col-md-3">
       <a ng-click="vm.toggleModel('services')" ng-class="{active: vm.currentState >= 0}" class="btn btn-block btn-accent">
         <span>Services</span>
diff --git a/src/app/service-graph/components/graph/graph.component.ts b/src/app/service-graph/components/graph/graph.component.ts
index b0cabb9..ae5c2f1 100644
--- a/src/app/service-graph/components/graph/graph.component.ts
+++ b/src/app/service-graph/components/graph/graph.component.ts
@@ -18,6 +18,7 @@
 
 import * as d3 from 'd3';
 import * as $ from 'jquery';
+import * as _ from 'lodash';
 
 import {IXosGraphStore} from '../../services/graph.store';
 import {Subscription} from 'rxjs/Subscription';
@@ -189,6 +190,24 @@
       .then((nodes: IXosSgNode[]) => {
         this.loader = false;
 
+        // NOTE keep the position for the nodes that already in the graph
+        nodes = _.map(nodes, (n: IXosSgNode) => {
+
+          if (n.id === 'undefined') {
+            // FIXME why the fabric ONOS app is not displayed and the VTN ONOS app is???
+            console.warn(n);
+          }
+
+          const previousVal = _.find(this.forceLayout.nodes(), {id: n.id});
+
+          if (previousVal) {
+            n.x = previousVal.x;
+            n.y = previousVal.y;
+            n.fixed = previousVal.fixed;
+          }
+          return n;
+        });
+
         this.forceLayout
           .nodes(nodes)
           .links(links)
diff --git a/src/app/service-graph/services/graph.store.ts b/src/app/service-graph/services/graph.store.ts
index cf438e6..0dd6653 100644
--- a/src/app/service-graph/services/graph.store.ts
+++ b/src/app/service-graph/services/graph.store.ts
@@ -195,6 +195,7 @@
   // graph operations
   private addNode(node: IXosBaseModel) {
     const nodeId = this.getNodeId(node);
+
     this.serviceGraph.setNode(nodeId, node);
 
     const nodeType = this.getModelType(node);
@@ -261,10 +262,33 @@
 
   // helpers
   private getModelType(node: IXosBaseModel): string {
+    if (!node) {
+      this.$log.warn(`[XosGraphStore] Someone called getModelType with an empty model: ${node}`);
+      return 'missing-node';
+    }
+
     if (node.type) {
       // NOTE handling "ownership" links
       return node.type;
     }
+
+    if (node.class_names.indexOf('ServiceInstance,') > -1 ) {
+      return 'serviceinstance';
+    }
+
+    if (node.class_names.indexOf('Service,') > -1 ) {
+      return 'service';
+    }
+
+    if (node.class_names.indexOf('Instance,') > -1 ) {
+      return 'instance';
+    }
+
+    if (node.class_names.indexOf('Network,') > -1 ) {
+      return 'network';
+    }
+
+    this.$log.warn(`[XosGraphStore] Unkown model type: ${node.class_names}`);
     return node.class_names.split(',')[0].toLowerCase();
   }
 
@@ -287,6 +311,7 @@
   private getNodeId(node: IXosBaseModel): string {
 
     const nodeType = this.getModelType(node);
+
     switch (nodeType) {
       case 'service':
         return this.getServiceId(node.id);
diff --git a/src/app/service-graph/services/node-positioner.service.ts b/src/app/service-graph/services/node-positioner.service.ts
index 17823b7..bfe6c58 100644
--- a/src/app/service-graph/services/node-positioner.service.ts
+++ b/src/app/service-graph/services/node-positioner.service.ts
@@ -73,15 +73,15 @@
           return all;
         }, {});
 
-        // find the nodes that don't have a position defined and put them at the top
-        const allNodes = _.reduce(nodes, (all: string[], n: IXosSgNode) => {
+        // find the nodes that don't have a position defined and put them at the bottom
+        const allServiceNodes = _.reduce(nodes, (all: string[], n: IXosSgNode) => {
           if (n.type === 'service') {
             all.push(n.data.name);
           }
           return all;
         }, []);
         const positionedNodes = Object.keys(positionConstraints);
-        const unpositionedNodes = _.difference(allNodes, positionedNodes);
+        const unpositionedNodes = _.difference(allServiceNodes, positionedNodes);
 
         _.forEach(unpositionedNodes, (node: string, i: number) => {
           const hStep = this.getHorizontalStep(svg.width, unpositionedNodes);