text: /*
   * 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';
  
    /**
     * Controller used to edit an existing Ironic node
     */
    angular
      .module('horizon.dashboard.admin.ironic')
      .controller('EditNodeController', EditNodeController);
  
    EditNodeController.$inject = [
      '$rootScope',
      '$controller',
      '$uibModalInstance',
      'horizon.framework.widgets.toast.service',
      'horizon.app.core.openstack-service-api.ironic',
      'horizon.dashboard.admin.ironic.events',
      'horizon.dashboard.admin.ironic.driverInterfaces',
      'horizon.dashboard.admin.ironic.edit-node.service',
      'horizon.dashboard.admin.ironic.update-patch.service',
      '$log',
      'node'
    ];
  
    function EditNodeController($rootScope,
                                $controller,
                                $uibModalInstance,
                                toastService,
                                ironic,
                                ironicEvents,
                                driverInterfaces,
                                editNodeService,
                                updatePatchService,
                                $log,
                                node) {
      var ctrl = this;
  
      $controller('BaseNodeController',
                  {ctrl: ctrl,
                   $uibModalInstance: $uibModalInstance});
  
      ctrl.modalTitle = gettext("Edit Node");
      ctrl.submitButtonTitle = gettext("Update Node");
  
      ctrl.baseNode = null;
  
      var instanceInfoId = "instance_info";
      ctrl.propertyCollections.push(
        {id: instanceInfoId,
         formId: "instance_info_form",
         title: gettext("Instance Info"),
         addPrompt: gettext("Add Instance Property"),
         placeholder: gettext("Instance Property Name")});
  
      ctrl.node[instanceInfoId] = {};
  
      init(node);
  
      function init(node) {
        ctrl._loadDrivers().then(function() {
          _loadNodeData(node.uuid);
        });
        ctrl._getImages();
      }
  
      function _loadNodeData(nodeId) {
        ironic.getNode(nodeId).then(function(node) {
          ctrl.baseNode = angular.copy(node);
          ctrl.node.name = node.name;
          ctrl.node.resource_class = node.resource_class;
          for (var i = 0; i < ctrl.drivers.length; i++) {
            if (ctrl.drivers[i].name === node.driver) {
              ctrl.selectedDriver = ctrl.drivers[i];
              break;
            }
          }
  
          ctrl.loadDriver(node.driver).then(function() {
            angular.forEach(node.driver_info, function(value, property) {
              if (angular.isDefined(ctrl.driverProperties[property])) {
                ctrl.driverProperties[property].inputValue = value;
              }
            });
  
            if (ctrl.driverType === 'classic') {
              ctrl.node.network_interface = node.network_interface;
              ctrl.node.storage_interface = node.storage_interface;
            } else {
              angular.forEach(
                ctrl.driverInterfaceFields,
                function(field, interfaceName) {
                  field.value = ctrl.baseNode[interfaceName + '_interface'];
                });
            }
          });
  
          ctrl.node.properties = angular.copy(node.properties);
          ctrl.node.extra = angular.copy(node.extra);
          ctrl.node.instance_info = angular.copy(node.instance_info);
          ctrl.node.uuid = node.uuid;
        });
      }
  
      /**
       * @description Construct a patch that converts source node into
       * target node
       *
       * @param {object} sourceNode - Source node
       * @param {object} targetNode - Target node
       * @return {object[]} Array of patch instructions
       */
      ctrl.buildPatch = function(sourceNode, targetNode) {
        var patcher = new updatePatchService.UpdatePatch();
        var PatchItem = function PatchItem(id, path) {
          this.id = id;
          this.path = path;
        };
  
        angular.forEach([new PatchItem("name", "/name"),
                         new PatchItem("resource_class", "/resource_class"),
                         new PatchItem("driver", "/driver"),
                         new PatchItem("properties", "/properties"),
                         new PatchItem("extra", "/extra"),
                         new PatchItem("driver_info", "/driver_info"),
                         new PatchItem("instance_info", "/instance_info")],
                        function(item) {
                          patcher.buildPatch(sourceNode[item.id],
                                             targetNode[item.id],
                                             item.path);
                        });
  
        angular.forEach(driverInterfaces, function(interfaceName) {
          var propName = interfaceName + '_interface';
          if (angular.isDefined(sourceNode[propName])) {
            patcher.buildPatch(sourceNode[propName],
                               targetNode[propName],
                               '/' + propName);
          }
        });
  
        return patcher.getPatch();
      };
  
      ctrl.submit = function() {
        angular.forEach(ctrl.driverProperties, function(property, name) {
          $log.debug(name +
                     ", required = " + property.isRequired() +
                     ", active = " + property.isActive() +
                     ", input-value = " + property.getInputValue() +
                     ", default-value = " + property.getDefaultValue());
          if (property.isActive() &&
              property.getInputValue() &&
              property.getInputValue() !== property.getDefaultValue()) {
            $log.debug("Setting driver property " + name + " to " +
                       property.inputValue);
            ctrl.node.driver_info[name] = property.inputValue;
          }
        });
  
        angular.forEach(ctrl.driverInterfaceFields, function(field, interfaceName) {
          ctrl.node[interfaceName + '_interface'] = field.value;
        });
  
        $log.info("Updating node " + JSON.stringify(ctrl.baseNode));
        $log.info("to " + JSON.stringify(ctrl.node));
  
        var patch = ctrl.buildPatch(ctrl.baseNode, ctrl.node);
        $log.info("patch = " + JSON.stringify(patch.patch));
        if (patch.status === updatePatchService.UpdatePatch.status.OK) {
          ironic.updateNode(ctrl.baseNode.uuid, patch.patch).then(function(node) {
            $rootScope.$emit(ironicEvents.EDIT_NODE_SUCCESS);
            $uibModalInstance.close(node);
          });
        } else {
          toastService.add('error',
                           gettext('Unable to create node update patch.'));
        }
      };
    }
  })();
  