Add and modify SNMP Managers

This allows the user to add and edit SNMP managers.

Tested: Added SNMP managers on a Witherspoon.
Change-Id: Iab8d6463b03de75928e4989135172d93ab0f28a3
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/app/configuration/controllers/snmp-controller.html b/app/configuration/controllers/snmp-controller.html
index e62c453..2458e3d 100644
--- a/app/configuration/controllers/snmp-controller.html
+++ b/app/configuration/controllers/snmp-controller.html
@@ -4,16 +4,29 @@
     <h1>SNMP settings</h1>
   </div>
   <form class="snmp__form" role="form" action="">
-    <section class="row column">
       <div class="page-header">
-        <h2 class="bold h4">SNMP information</h2>
+        <h2 class="bold h4">Set the Simple Network Management Protocol (SNMP)</h2>
       </div>
       <fieldset>
-        <div class="snmp__managers" ng-repeat="manager in managers track by $index">
-          <label>SNMP Manager {{$index+1}}</label>
-          <field>{{manager.Address}}:{{manager.Port}}</field>
+        <div class="row column snmp__managers-wrap">
+          <div class="snmp__managers" ng-repeat="manager in managers">
+            <div class="inline snmp__manager-field">
+              <label>SNMP Manager Server</label>
+              <input id="snmp-manager{{$index+1}}-address" type="text" ng-model="manager.address" ng-blur="managers[$index].address = manager.address"/>
+            </div>
+            <div class="inline  snmp__manager-field">
+              <label>Port</label>
+              <input id="snmp-manager{{$index+1}}-port" type="text" ng-model="manager.port" ng-blur="managers[$index].port = manager.port"/>
+            </div>
+          </div>
+          <button type="button" class="btn-primary inline" ng-click="addNewSNMPManager()">Add SNMP manager</button>
         </div>
       </fieldset>
-    </section>
+    <div class="snmp__submit-wrapper">
+      <button type="button" class="btn-primary inline" ng-click="setSNMP()">Save settings</button>
+      <button type="button" class="btn-secondary inline" ng-click="refresh()">Cancel</button>
+    </div>
+    <p class="success-msg" ng-show="success" role="alert">Success! SNMP managers updated!</p>
+    <p class="error error-msg" ng-show="error" role="alert">Error setting SNMP Managers!</p>
   </form>
 </div>
diff --git a/app/configuration/controllers/snmp-controller.js b/app/configuration/controllers/snmp-controller.js
index 4b82334..782ee1c 100644
--- a/app/configuration/controllers/snmp-controller.js
+++ b/app/configuration/controllers/snmp-controller.js
@@ -10,14 +10,25 @@
   'use strict';
 
   angular.module('app.configuration').controller('snmpController', [
-    '$scope', '$window', 'APIUtils',
-    function($scope, $window, APIUtils) {
-      $scope.managers = {};
+    '$scope', '$window', 'APIUtils', '$route', '$q',
+    function($scope, $window, APIUtils, $route, $q) {
+      $scope.managers = [];
       $scope.loading = true;
+      $scope.error = false;
+      $scope.success = false;
+      $scope.managers_to_delete = [];
 
       var getSNMPManagers = APIUtils.getSNMPManagers().then(
           function(data) {
-            $scope.managers = data.data;
+            // Convert to array of objects from an object of objects, easier
+            // to manipulate (e.g. add/remove). Convert key to a path property.
+            for (var key in data.data) {
+              $scope.managers.push({
+                path: key,
+                port: data.data[key].Port,
+                address: data.data[key].Address
+              })
+            }
           },
           function(error) {
             console.log(JSON.stringify(error));
@@ -26,6 +37,97 @@
       getSNMPManagers.finally(function() {
         $scope.loading = false;
       });
+
+      $scope.addNewSNMPManager = function() {
+        $scope.managers.push({address: '', port: ''});
+      };
+
+      $scope.removeSNMPManager = function(index) {
+        // If the SNMP Manager has a path it exists on the backend and we
+        // need to make a call to remove it
+        if ($scope.managers[index].path) {
+          $scope.managers_to_delete.push($scope.managers[index].path);
+        }
+        $scope.managers.splice(index, 1);
+      };
+
+      $scope.refresh = function() {
+        $route.reload();
+      };
+
+      $scope.setSNMP = function() {
+        $scope.error = false;
+        $scope.success = false;
+        $scope.loading = true;
+        var promises = [];
+
+        // Interate in reverse so can splice
+        // https://stackoverflow.com/questions/9882284/looping-through-array-and-removing-items-without-breaking-for-loop
+        var i = $scope.managers.length;
+        while (i--) {
+          // Remove any SNMP Manager with an empty address and port
+          if (!$scope.managers[i].address && !$scope.managers[i].port) {
+            $scope.removeSNMPManager(i);
+            continue;
+          }
+
+          // Throw an error if only 1 of the fields is filled out
+          if (!$scope.managers[i].address || !$scope.managers[i].port) {
+            // TODO: Highlight the field that is empty
+            $scope.loading = false;
+            $scope.error = true;
+            return;
+          }
+
+          // If the manager does not have a 'path', it is a new manager
+          // and needs to be created
+          if (!$scope.managers[i].path) {
+            promises.push(addManager(
+                $scope.managers[i].address, $scope.managers[i].port));
+          } else {
+            // TODO: Check if we actually need to update the existing managers
+            promises.push(setManagerAddress(
+                $scope.managers[i].path, $scope.managers[i].address));
+            promises.push(setManagerPort(
+                $scope.managers[i].path, $scope.managers[i].port));
+          }
+        }
+
+        // Add delete promises last since we might be adding to
+        // managers_to_delete above
+        for (var i in $scope.managers_to_delete) {
+          promises.push(deleteManager($scope.managers_to_delete[i]));
+        }
+
+        $q.all(promises)
+            .then(
+                function() {
+                  $scope.success = true;
+                },
+                function(errors) {
+                  console.log(JSON.stringify(errors));
+                  $scope.error = true;
+                })
+            .finally(function() {
+              $scope.loading = false;
+            });
+      };
+
+      function addManager(address, port) {
+        return APIUtils.addSNMPManager(address, port);
+      }
+
+      function deleteManager(path) {
+        return APIUtils.deleteObject(path);
+      }
+
+      function setManagerAddress(path, address) {
+        return APIUtils.setSNMPManagerAddress(path, address);
+      }
+
+      function setManagerPort(path, port) {
+        return APIUtils.setSNMPManagerPort(path, port);
+      }
     }
   ]);
 })(angular);
diff --git a/app/configuration/styles/snmp.scss b/app/configuration/styles/snmp.scss
index 00dd40b..eabfb7a 100644
--- a/app/configuration/styles/snmp.scss
+++ b/app/configuration/styles/snmp.scss
@@ -4,10 +4,36 @@
 
   fieldset {
     padding-left: 1.8em;
-    padding-bottom: 1.8em;
-    border-bottom: 1px solid $medgrey;
   }
    .snmp__managers {
+    padding-bottom: 1.5em;
+  }
+
+   .snmp__manager-field {
+    padding-right: 4em;
+    width: 350px;
+  }
+
+  .snmp__metadata-wrapper {
+    margin: 0;
+    padding: 0;
+  }
+
+  .snmp__managers-wrap{
     padding-bottom: 1em;
+    padding-top: 1em;
+    padding-left: 3em;
+    padding-right: 4em;
+  }
+
+  .snmp__submit-wrapper {
+    width: 100%;
+    margin-top: 3em;
+    padding-top: 1em;
+    border-top: 1px solid $medgrey;
+    button {
+      float: right;
+      margin: .5em;
+    }
   }
 }