/* **********************************************************
 * Copyright (c) 2020 VMware, Inc.  All rights reserved.
 * -- VMware Confidential
 * **********************************************************/

package com.vmware.samples.drconfig;

import java.net.MalformedURLException;
import java.rmi.RemoteException;

import com.vmware.samples.connection.ApplicationException;
import com.vmware.samples.connection.DrConfigConnectionUtils;

import com.vmware.drconfig.RuntimeFaultFaultMsg;
import com.vmware.drconfig.DrConfigFaultConnectionRefusedFaultFaultMsg;
import com.vmware.drconfig.DrConfigFaultDnsLookupFaultFaultMsg;
import com.vmware.drconfig.DrConfigFaultHostUnreachableFaultFaultMsg;
import com.vmware.drconfig.DrConfigFaultInvalidLocaleFaultMsg;
import com.vmware.drconfig.DrConfigFaultInvalidLoginFaultMsg;
import com.vmware.drconfig.DrConfigFaultNoPermissionFaultMsg;
import com.vmware.drconfig.DrConfigFaultServiceBusyFaultMsg;
import com.vmware.drconfig.DrConfigFaultSrmAlreadyRunningFaultMsg;
import com.vmware.drconfig.DrConfigServiceStub;
import com.vmware.drconfig.GetTaskInfo;
import com.vmware.drconfig.GetTaskInfoRequestType;
import com.vmware.drconfig.InvalidArgumentFaultMsg;
import com.vmware.drconfig.ProbeSsl;
import com.vmware.drconfig.ProbeSslRequestType;
import com.vmware.drconfig.ReadCurrentConfig;
import com.vmware.drconfig.ReadCurrentConfigRequestType;
import com.vmware.drconfig.DrConfigConfigurationTaskInfo;
import com.vmware.drconfig.DrConfigServiceInstanceContent;
import com.vmware.drconfig.ClearSrmConfiguration;
import com.vmware.drconfig.ClearSrmConfigurationRequestType;
import com.vmware.drconfig.ConfigureSrm;
import com.vmware.drconfig.ConfigureSrmRequestType;
import com.vmware.drconfig.DrConfigCertificateInfo;
import com.vmware.drconfig.DrConfigConfigurationSpec;
import com.vmware.drconfig.DrConfigConnectionSpec;

import com.vmware.samples.drconfig.CmdOptions;

import com.vmware.vim25.ManagedObjectReference;

/**
 * Provides a sample application that configures the appliance.
 */
public final class ConfigureAppliance {

   /**
    * Entry point into this sample application.
    * @param args the list of command-line arguments.
    */
   public static void main(final String[] args) {

      final String progName = ConfigureAppliance.class.getSimpleName();
      CmdOptions options = null;
      try {
         options = CmdOptions.parseOptionsConfigure(args);
      } catch (final CmdOptions.ShowHelpThrowable t) {
         System.out.println("Invalid arguments.");
         CmdOptions.printHelp(progName);
         return;
      } catch (final CmdOptions.InvalidCliArgumentException icae) {
         System.err.println(progName + ": " + icae.getMessage());
         CmdOptions.printHelp(progName);
         System.exit(1);
         return; // Not reached...
      } catch (MalformedURLException e) {
         System.err.println(e.getMessage());
         return;
      } catch (Exception e) {
         System.err.println(e.getMessage());
         CmdOptions.printHelp(progName);
         return;
      }

      try {
         if(options._option == "configure") {
            ConfigureAppliance.configureSrm(options);
         } else if (options._option == "clear") {
            ConfigureAppliance.clearSrmConfiguration(options);
         } else if (options._option == "readConfig") {
            ConfigureAppliance.readCurrentConfig(options);
         } else {
            System.err.println("No operation was selected ");
         }
      } catch (final ApplicationException e) {
         System.err.println(progName + ": " + e.getMessage());
         e.printStackTrace();
         System.exit(1);
      }
   }

   /**
    * Configure SRM on the Virtual Appliance
    *
    * @param options The command-line options that configure the execution of
    *    the sample application.
    * @throws ApplicationException if there is a fatal error in the execution of
    *    the application.  This exception should have all the information a user
    *    needs to diagnose the problem in {@code getMessage()}.
    */
   public static void configureSrm(final CmdOptions options)
      throws ApplicationException {

      System.out.println("Starting operation " + options._option);

      DrConfigConnectionUtils connectionUtils = null;
      try {
         // This DrConfig Connection Util instance keeps a connection to the Virtual Appliance - DrConfigurator,
         // through which we make our remote API calls.
         connectionUtils =
            new DrConfigConnectionUtils(options._vaAddress.toString(), options._vaUserName, options._vaPassword, options._ignoreCert);

         // Get the stub holding all the methods
         final DrConfigServiceStub drConfigStub = connectionUtils.getDrConfigServiceStub();
         // Get the ServiceInstanceContent as it is our handle to the other DrConfig
         // subsystems.  In this case, we're interested in the ConfigurationManager interface.
         final DrConfigServiceInstanceContent sic =
            connectionUtils.getDrConfigServiceInstanceContent();

         final ManagedObjectReference configurationManager = sic.getCfgManager();
         final ManagedObjectReference sslCertManager = sic.getSslCertificateManager();
         DrConfigConfigurationSpec spec = new DrConfigConfigurationSpec();
         spec.setSiteName("SampleSite");
         spec.setAdminUser(options._vcUserName);
         spec.setAdminPassword(options._vcPassword);

         DrConfigConnectionSpec connSpec = new DrConfigConnectionSpec();
         connSpec.setUri(options._pscUrl);
         com.vmware.drconfig.ProbeSsl probeSsl =
            new ProbeSsl();
         com.vmware.drconfig.ProbeSslRequestType probeSslRequest =
            new ProbeSslRequestType();
         // We set the object for which the request is meant for.
         // In this example the object called - SslCertificateManager
         // This object has a method called - probeSsl
         // The method takes 1 parameter - String uri
         // So we use our Stub to create a request
         // and we give the necessary information about
         // the method we want to invoke, which is Object, and parameters
         probeSslRequest.set_this(sslCertManager);
         probeSslRequest.setUri(options._pscUrl);
         probeSsl.setProbeSsl(probeSslRequest);
         DrConfigCertificateInfo certInfo = drConfigStub.probeSsl(probeSsl).getReturnval();
         connSpec.setThumbprint(certInfo.getThumbprint());

         spec.setConnection(connSpec);

         try {
            com.vmware.drconfig.ConfigureSrm configureSrm = new ConfigureSrm();
            com.vmware.drconfig.ConfigureSrmRequestType configureSrmRequestType =
               new ConfigureSrmRequestType();
            configureSrmRequestType.set_this(configurationManager);
            configureSrmRequestType.setConfig(spec);
            configureSrm.setConfigureSrm(configureSrmRequestType);

            ManagedObjectReference configureTask = drConfigStub.configureSrm(configureSrm).getReturnval();
            com.vmware.drconfig.GetTaskInfo getTaskInfo = new GetTaskInfo();
            com.vmware.drconfig.GetTaskInfoRequestType taskInfoRequestType =
               new GetTaskInfoRequestType();
            taskInfoRequestType.set_this(configureTask);
            getTaskInfo.setGetTaskInfo(taskInfoRequestType);
            DrConfigConfigurationTaskInfo taskInfo = drConfigStub.getTaskInfo(getTaskInfo).getReturnval();

            while (!taskInfo.getComplete()) {
               Thread.sleep(1000);
               taskInfo = drConfigStub.getTaskInfo(getTaskInfo).getReturnval();
            }

            if (taskInfo.getError() == null) {
               System.out.println("SRM configured successfully");
            } else {
               System.err.println("SRM was not properly configured: " + taskInfo.getError().getLocalizedMessage());
            }
         } catch (final RuntimeFaultFaultMsg e) {
            throw new ApplicationException(
               "Error occured while trying to configure SRM", e);
         } catch (DrConfigFaultServiceBusyFaultMsg e) {
            e.printStackTrace();
         } catch (DrConfigFaultSrmAlreadyRunningFaultMsg e) {
            e.printStackTrace();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      } catch (DrConfigFaultConnectionRefusedFaultFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultDnsLookupFaultFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultHostUnreachableFaultFaultMsg e1) {
         e1.printStackTrace();
      } catch (RuntimeFaultFaultMsg e1) {
         e1.printStackTrace();
      } catch (RemoteException e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultInvalidLocaleFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultInvalidLoginFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultNoPermissionFaultMsg e1) {
         e1.printStackTrace();
      } catch (InvalidArgumentFaultMsg e1) {
         e1.printStackTrace();
      } finally {
         try {
            if(connectionUtils != null && connectionUtils.isLoginSuccessful()) {
               connectionUtils.logout();
            }
         } catch (final RuntimeFaultFaultMsg e) {
            System.err.println(
               "Warning -- unable to log out of DrConfigurator: " + e.getMessage());
         } catch (RemoteException e) {
            e.printStackTrace();
         }
      }
   }

   /**
    * Clear configuration of SRM on the Virtual Appliance
    *
    * @param options The command-line options that configure the execution of
    *    the sample application.
    * @throws ApplicationException if there is a fatal error in the execution of
    *    the application.  This exception should have all the information a user
    *    needs to diagnose the problem in {@code getMessage()}.
    */
   public static void clearSrmConfiguration(final CmdOptions options)
      throws ApplicationException {
      System.out.println("Starting operation " + options._option);

      // This DrConfig Connection Util instance keeps a connection to the Virtual Appliance - DrConfigurator,
      // through which we make our remote API calls.
      DrConfigConnectionUtils connectionUtils = null;
      try {
         connectionUtils =
            new DrConfigConnectionUtils(options._vaAddress.toString(), options._vaUserName, options._vaPassword, options._ignoreCert);
         // Get the stub holding all the methods
         final DrConfigServiceStub drConfigStub = connectionUtils.getDrConfigServiceStub();
         final ManagedObjectReference configurationManager =
            connectionUtils.getDrConfigServiceInstanceContent().getCfgManager();
         DrConfigConfigurationSpec spec = new DrConfigConfigurationSpec();
         spec.setAdminUser(options._vcUserName);
         spec.setAdminPassword(options._vcPassword);

         try {
            com.vmware.drconfig.ClearSrmConfiguration clearSrmConfiguration =
               new ClearSrmConfiguration();
            com.vmware.drconfig.ClearSrmConfigurationRequestType clearSrmConfigRequest =
               new ClearSrmConfigurationRequestType();
            clearSrmConfigRequest.set_this(configurationManager);
            clearSrmConfigRequest.setConfig(spec);
            clearSrmConfiguration.setClearSrmConfiguration(clearSrmConfigRequest);

            ManagedObjectReference clearTask =
               drConfigStub.clearSrmConfiguration(clearSrmConfiguration).getReturnval();
            com.vmware.drconfig.GetTaskInfo getTaskInfo = new GetTaskInfo();
            com.vmware.drconfig.GetTaskInfoRequestType getTaskInfoRequest =
               new GetTaskInfoRequestType();
            getTaskInfoRequest.set_this(clearTask);
            getTaskInfo.setGetTaskInfo(getTaskInfoRequest);

            DrConfigConfigurationTaskInfo taskInfo = drConfigStub.getTaskInfo(getTaskInfo).getReturnval();
            while (!taskInfo.getComplete()) {
               Thread.sleep(1000);
               taskInfo = drConfigStub.getTaskInfo(getTaskInfo).getReturnval();
            }

            if (taskInfo.getError() == null) {
               System.out.println("SRM configuration cleared successfully");
            } else {
               System.err.println("SRM configuration could not be cleared: " + taskInfo.getError().getLocalizedMessage());
            }
         } catch (final RuntimeFaultFaultMsg e) {
            throw new ApplicationException(
               "Cannot clear SRM configuration ", e);
         } catch (DrConfigFaultServiceBusyFaultMsg e) {
            e.printStackTrace();
         } catch (DrConfigFaultSrmAlreadyRunningFaultMsg e) {
            e.printStackTrace();
         } catch (InvalidArgumentFaultMsg e) {
            e.printStackTrace();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      } catch (RemoteException e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultInvalidLocaleFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultInvalidLoginFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultNoPermissionFaultMsg e1) {
         e1.printStackTrace();
      } catch (InvalidArgumentFaultMsg e1) {
         e1.printStackTrace();
      } catch (RuntimeFaultFaultMsg e1) {
         e1.printStackTrace();
      } finally {
         try {
            if(connectionUtils != null && connectionUtils.isLoginSuccessful()) {
               connectionUtils.logout();
            }
         } catch (final RuntimeFaultFaultMsg e) {
            System.err.println(
               "Warning -- unable to log out of DrConfigurator: " + e.getMessage());
         } catch (RemoteException e) {
            e.printStackTrace();
         }
      }
   }

   /**
    * Read SRM configuration of the Virtual Appliance
    *
    * @param options The command-line options that configure the execution of
    *    the sample application.
    * @throws ApplicationException if there is a fatal error in the execution of
    *    the application.  This exception should have all the information a user
    *    needs to diagnose the problem in {@code getMessage()}.
    */
   public static void readCurrentConfig(final CmdOptions options)
      throws ApplicationException {

      // This DrConfig Connection Util instance keeps a connection to the Virtual Appliance - DrConfigurator,
      // through which we make our remote API calls.
      DrConfigConnectionUtils connectionUtils = null;
      try {
         connectionUtils =
            new DrConfigConnectionUtils(options._vaAddress.toString(), options._vaUserName, options._vaPassword, options._ignoreCert);

         // Get the ServiceInstanceContent as it is our handle to the other DrConfig
         // subsystems.  In this case, we're interested in the ConfigurationManager interface.
         final DrConfigServiceInstanceContent sic = connectionUtils.getDrConfigServiceInstanceContent();
         final DrConfigServiceStub drConfigStub = connectionUtils.getDrConfigServiceStub();
         final ManagedObjectReference configurationManager = sic.getCfgManager();

         try {
            com.vmware.drconfig.ReadCurrentConfig readCurrentConfig =
               new ReadCurrentConfig();
            com.vmware.drconfig.ReadCurrentConfigRequestType readConfigRequest =
               new ReadCurrentConfigRequestType();
            readConfigRequest.set_this(configurationManager);
            readCurrentConfig.setReadCurrentConfig(readConfigRequest);
            drConfigStub.readCurrentConfig(readCurrentConfig);
            DrConfigConfigurationSpec spec =
               drConfigStub.readCurrentConfig(readCurrentConfig).getReturnval();

            if (spec != null) {
               if (spec.getConnection() == null) {
                  System.err.println("Connection Spec is null.");
               } else {
                  DrConfigConnectionSpec connSpec = spec.getConnection();
                  System.out.println("Lookup Service Uri: " + connSpec.getUri());
                  System.out.println("Lookup Service Thumbprint: +" + connSpec.getThumbprint());
               }
               System.out.println("SRM Site name: " + spec.getSiteName());
            } else {
               System.err.println("Configuration Spec is null.");
            }
         } catch (final RuntimeFaultFaultMsg e) {
            throw new ApplicationException(
               "Error while trying to read SRM current config", e);
         }
      } catch (RemoteException e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultInvalidLocaleFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultInvalidLoginFaultMsg e1) {
         e1.printStackTrace();
      } catch (DrConfigFaultNoPermissionFaultMsg e1) {
         e1.printStackTrace();
      } catch (InvalidArgumentFaultMsg e1) {
         e1.printStackTrace();
      } catch (RuntimeFaultFaultMsg e1) {
         e1.printStackTrace();
      } finally {
         try {
            if(connectionUtils != null && connectionUtils.isLoginSuccessful()) {
               connectionUtils.logout();
            }
         } catch (final RuntimeFaultFaultMsg e) {
            System.err.println(
               "Warning -- unable to log out of DrConfigurator: " + e.getMessage());
         } catch (RemoteException e) {
            e.printStackTrace();
         }
      }
   }

   /**
    * This class defines a library of functions.  So far there is no need for an
    * instance, so we will hide the CTOR.
    */
   private ConfigureAppliance() {
      // Does nothing.
   }
}
