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

package com.vmware.samples.drconfig;

import java.net.MalformedURLException;

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.DrConfigFaultServiceBusyFaultMsg;
import com.vmware.drconfig.DrConfigFaultSrmAlreadyRunningFaultMsg;
import com.vmware.drconfig.DrConfigPortType;
import com.vmware.drconfig.InvalidArgumentFaultMsg;

import com.vmware.drconfig.DrConfigConfigurationTaskInfo;
import com.vmware.drconfig.DrConfigServiceInstanceContent;
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;
      }

      if (options._ignoreCert) {
         DrConfigConnectionUtils.ignoreSslCert();
      }

      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);

      // This DrConfig port instance is our communication layer, through which we
      // make our remote API calls.
      final DrConfigPortType drConfigPort = DrConfigConnectionUtils.openDrConfigPort(
         options._vaAddress, options._vaUserName, options._vaPassword);

      try {
         // 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 =
             DrConfigConnectionUtils.getDrConfigServiceInstanceContent(drConfigPort);

          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._lkpUrl);
          DrConfigCertificateInfo certInfo = drConfigPort.probeSsl(sslCertManager, options._lkpUrl);
          connSpec.setThumbprint(certInfo.getThumbprint());

          spec.setConnection(connSpec);

         try {
            ManagedObjectReference configureTask = drConfigPort.configureSrm(configurationManager, spec);
            DrConfigConfigurationTaskInfo taskInfo = drConfigPort.getTaskInfo(configureTask);

            while (!taskInfo.isComplete()) {
               Thread.sleep(1000);
               taskInfo = drConfigPort.getTaskInfo(configureTask);
            }

            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 (InvalidArgumentFaultMsg 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();
      } finally {
         try {
            drConfigPort.logoutDrConfig(DrConfigConnectionUtils._serviceInstanceRef);
         } catch (final RuntimeFaultFaultMsg e) {
            System.err.println(
               "Warning -- unable to log out of DrConfigurator: " + e.getMessage());
         }
      }
   }

   /**
    * 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 port instance is our communication layer, through which we
      // make our remote API calls.
      final DrConfigPortType drConfigPort = DrConfigConnectionUtils.openDrConfigPort(
         options._vaAddress, options._vaUserName, options._vaPassword);

      try {
         // 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 =
             DrConfigConnectionUtils.getDrConfigServiceInstanceContent(drConfigPort);

         final ManagedObjectReference configurationManager = sic.getCfgManager();

         DrConfigConfigurationSpec spec = new DrConfigConfigurationSpec();
         spec.setAdminUser(options._vcUserName);
         spec.setAdminPassword(options._vcPassword);

         try {
            ManagedObjectReference clearTask = drConfigPort.clearSrmConfiguration(configurationManager, spec);
            DrConfigConfigurationTaskInfo taskInfo = drConfigPort.getTaskInfo(clearTask);
            while (!taskInfo.isComplete()) {
               Thread.sleep(1000);
               taskInfo = drConfigPort.getTaskInfo(clearTask);
            }

            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();
         }

      } finally {
         try {
            drConfigPort.logoutDrConfig(DrConfigConnectionUtils._serviceInstanceRef);
         } catch (final RuntimeFaultFaultMsg e) {
            System.err.println(
               "Warning -- unable to log out of SRM: " + e.getMessage());
         }
      }
   }

   /**
    * 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 port instance is our communication layer, through which we
      // make our remote API calls.
      final DrConfigPortType drConfigPort = DrConfigConnectionUtils.openDrConfigPort(
         options._vaAddress, options._vaUserName, options._vaPassword);

      try {
         // 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 =
            DrConfigConnectionUtils.getDrConfigServiceInstanceContent(drConfigPort);

         final ManagedObjectReference configurationManager = sic.getCfgManager();

         try {
            DrConfigConfigurationSpec spec = drConfigPort.readCurrentConfig(configurationManager);

            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);
         }
      } finally {
         try {
            drConfigPort.logoutDrConfig(DrConfigConnectionUtils._serviceInstanceRef);
         } catch (final RuntimeFaultFaultMsg e) {
            System.err.println(
               "Warning -- unable to log out of SRM: " + e.getMessage());
         }
      }
   }

   /**
    * 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.
   }
}
