/**
 *
 */
package com.cloudera.director.vsphere.vm.service.impl;

import com.cloudera.director.vsphere.resources.VcNetwork;
import com.cloudera.director.vsphere.vm.service.intf.IVmNicOperationService;
import com.vmware.vim25.*;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.Network;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VirtualMachine;

public class VmNicOperationService implements IVmNicOperationService{


   private final VirtualMachine vm;
   private final String operation;
   private final String netName;
   private final String newNetname;
   private final VcNetwork vcNetwork;

   public VmNicOperationService(VirtualMachine vm, String operation, VcNetwork vcNet, String netName, String newNetname) {
      this.vm = vm;
      this.operation = operation;
      this.netName = netName;
      this.newNetname = newNetname;
      this.vcNetwork = vcNet;
   }

   @Override
   public void run() throws Exception {

      VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();

      VirtualDeviceConfigSpec nicSpec = getNICDeviceConfigSpec();

      String result = null;
      if(nicSpec!=null) {
         vmConfigSpec.setDeviceChange(new VirtualDeviceConfigSpec []{nicSpec});
         Task task = vm.reconfigVM_Task(vmConfigSpec);
         result = task.waitForMe();
      }

      if(result==Task.SUCCESS) {
         System.out.println("Done with NIC for VM:" + this.vm.getName());
      } else {
         System.out.println("Failed with NIC for VM:" + this.vm.getName());
      }
   }

   private VirtualDeviceConfigSpec getNICDeviceConfigSpec() throws Exception {
      VirtualDeviceConfigSpec nicSpec = new VirtualDeviceConfigSpec();
      VirtualMachineConfigInfo vmConfigInfo = vm.getConfig();

      if("add".equalsIgnoreCase(this.operation) && doesNetworkNameExist()) {
         nicSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
         VirtualEthernetCard nic =  new VirtualVmxnet3();
         VirtualDeviceBackingInfo nicBacking;

         VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
         connectInfo.setConnected(true);
         connectInfo.setStartConnected(true);

         if(vcNetwork.isDvPortGroup())
            nicBacking = (VirtualEthernetCardDistributedVirtualPortBackingInfo)vcNetwork.getBackingInfo();
         else
            nicBacking = new VirtualEthernetCardNetworkBackingInfo();

         Description tmp = new Description();
         tmp.setSummary(this.newNetname);
         tmp.setLabel(this.newNetname);

         nic.setAddressType("generated");
         nic.setBacking(nicBacking);
         nic.setKey(4);
         nic.setConnectable(connectInfo);
         nic.setDeviceInfo(tmp);
         nicSpec.setDevice(nic);
         return nicSpec;
      } else if("remove".equalsIgnoreCase(this.operation)) {
         VirtualDevice[] vds = vmConfigInfo.getHardware().getDevice();
         nicSpec.setOperation(VirtualDeviceConfigSpecOperation.remove);
         for (int i = 0; i < vds.length; i++) {
            if ((vds[i] instanceof VirtualEthernetCard) && (vds[i].getKey() == 4000)) {
               nicSpec.setDevice(vds[i]);
               return nicSpec;
            }
         }
      }else if("edit".equalsIgnoreCase(this.operation)){
         VirtualDevice [] vds = vmConfigInfo.getHardware().getDevice();
         nicSpec.setOperation(VirtualDeviceConfigSpecOperation.edit);
         VirtualDeviceBackingInfo nicBacking;
         for(int i=0; i<vds.length; i++) {
            //if ((vds[i].getDeviceInfo().getLabel().equalsIgnoreCase(this.netName))) {
            if((vds[i].getKey() == 4000)){
               VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
               connectInfo.setConnected(true);
               connectInfo.setStartConnected(true);

               if(vcNetwork.isDvPortGroup())
                  nicBacking = (VirtualEthernetCardDistributedVirtualPortBackingInfo)vcNetwork.getBackingInfo();
               else
                  nicBacking = (VirtualEthernetCardNetworkBackingInfo)vds[i].getBacking();

               Description tmp = vds[i].getDeviceInfo();
               tmp.setSummary(this.newNetname);

               vds[i].setBacking(nicBacking);
               vds[i].setConnectable(connectInfo);
               vds[i].setDeviceInfo(tmp);

               nicSpec.setDevice(vds[i]);
               return nicSpec;
            }
         }
      }
      return nicSpec;
   }

   private boolean doesNetworkNameExist() throws Exception {
      VirtualMachineRuntimeInfo vmRuntimeInfo = vm.getRuntime();
      ManagedObjectReference hmor = vmRuntimeInfo.getHost();
      HostSystem host = new HostSystem(vm.getServerConnection(), hmor);

      Network[] networks = host.getNetworks();
      for (Network network : networks) {
         if (network.getSummary().isAccessible() && network.getName().equalsIgnoreCase(this.netName)) {
            return true;
         }
      }

      return false;
   }

}

@@ -2012,16 +2012,83 @@
 Backing;
+%0A         VirtualEthernetCardNetworkBackingInfo standardNicBacking;
 %0A%0A      
@@ -2279,32 +2279,34 @@
 isDvPortGroup())
+ %7B
 %0A            nic
@@ -2361,32 +2361,33 @@
 PortBackingInfo)
+ 
 vcNetwork.getBac
@@ -2399,36 +2399,78 @@
 nfo();%0A         
+   nic.setBacking(nicBacking);%0A         %7D
 else
+%7B
 %0A            nic
@@ -2458,33 +2458,41 @@
 se%7B%0A            
-n
+standardN
 icBacking = new 
@@ -2531,16 +2531,138 @@
 gInfo();
+%0A            standardNicBacking.setDeviceName(this.newNetname);%0A            nic.setBacking(standardNicBacking);%0A         %7D
 %0A%0A      
@@ -2830,45 +2830,8 @@
 %22);%0A
-         nic.setBacking(nicBacking);%0A
     
@@ -3658,32 +3658,99 @@
 nfo nicBacking;%0A
+         VirtualEthernetCardNetworkBackingInfo standardNicBacking;%0A
          for(int
@@ -4137,16 +4137,18 @@
 Group())
+ %7B
 %0A       
@@ -4225,16 +4225,17 @@
 ingInfo)
+ 
 vcNetwor
@@ -4246,32 +4246,98 @@
 tBackingInfo();%0A
+                  vds%5Bi%5D.setBacking(nicBacking);%0A               %7D%0A
                e
@@ -4339,16 +4339,18 @@
     else
+ %7B
 %0A       
@@ -4352,33 +4352,41 @@
                 
-n
+standardN
 icBacking = (Vir
@@ -4436,24 +4436,167 @@
 etBacking();
+%0A                  standardNicBacking.setDeviceName(this.newNetname);%0A                  vds%5Bi%5D.setBacking(standardNicBacking);%0A               %7D
 %0A%0A          
@@ -4695,54 +4695,8 @@
 );%0A%0A
-               vds%5Bi%5D.setBacking(nicBacking);%0A
     

fix the problem that can't edit starndard portgroup problem