package org.ovirt.engine.core.bll;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.job.ExecutionHandler;
import org.ovirt.engine.core.bll.utils.EngineSSHClient;
import org.ovirt.engine.core.common.action.FenceVdsActionParameters;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdsPowerDownParameters;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;

/**
 * Tries to shutdown a host using SSH connection. The host has to be in maintenance mode.
 */
@NonTransactiveCommandAttribute
public class VdsPowerDownCommand<T extends VdsPowerDownParameters> extends VdsCommand<T> {
    public VdsPowerDownCommand(T parameters) {
        this(parameters, null);
    }

    public VdsPowerDownCommand(T parameters, CommandContext commandContext) {
        super(parameters, commandContext);
    }

    @Override
    protected boolean canDoAction() {
        return getVds().getStatus() == VDSStatus.Maintenance && super.canDoAction();
    }

    /**
     * Try to shut down the host using a clean ssh poweroff method
     */
    @Override
    protected void executeCommand() {
        setVds(null);
        if (getVds() == null) {
            handleError("SSH power down will not be executed on host {} ({}) since it doesn't exist anymore.");
            return;
        }

        /* Try this only when the Host is in maintenance state */
        if (getVds().getStatus() != VDSStatus.Maintenance) {
            handleError("SSH power down will not be executed on host {} ({}) since it is not in Maintenance.");
            return;
        }

        boolean result = executeSshPowerdown(getVds().getVdsGroupCompatibilityVersion().toString());
        if (result) {
            // SSH powerdown executed without errors set the status to down
            getVds().setStatus(VDSStatus.Down);

            // clear the automatic PM flag unless instructed otherwise
            if (!getParameters().getKeepPolicyPMEnabled()) {
                getVds().setPowerManagementControlledByPolicy(false);
                getDbFacade().getVdsDynamicDao().updateVdsDynamicPowerManagementPolicyFlag(
                        getVdsId(),
                        getVds().getDynamicData().isPowerManagementControlledByPolicy());
            }

        } else if (getParameters().getFallbackToPowerManagement() && getVds().isPmEnabled()) {
            FenceVdsActionParameters parameters = new FenceVdsActionParameters(getVds().getId());
            parameters.setKeepPolicyPMEnabled(getParameters().getKeepPolicyPMEnabled());
            runInternalAction(VdcActionType.StopVds,
                    parameters,
                    ExecutionHandler.createInternalJobContext());
        }

        getReturnValue().setSucceeded(result);
    }

    private void handleError(final String errorMessage) {
        setCommandShouldBeLogged(false);
        log.info(errorMessage,
                getVdsName(),
                getVdsId());
        getReturnValue().setSucceeded(false);
    }

    /**
     * Executes SSH shutdown command
     *
     * @returns {@code true} if command has been executed successfully, {@code false} otherwise
     */
    private boolean executeSshPowerdown(String version) {
        boolean ret = false;
        try (
                final EngineSSHClient sshClient = new EngineSSHClient();
                final ByteArrayOutputStream cmdOut = new ByteArrayOutputStream();
                final ByteArrayOutputStream cmdErr = new ByteArrayOutputStream();
        ) {
            try {
                log.info("Opening SSH power down session on host {}", getVds().getHostName());
                sshClient.setVds(getVds());
                sshClient.useDefaultKeyPair();
                sshClient.connect();
                sshClient.authenticate();

                log.info("Executing SSH power down command on host {}", getVds().getHostName());
                sshClient.executeCommand(
                        Config.<String> getValue(ConfigValues.SshVdsPowerdownCommand, version),
                        null,
                        cmdOut,
                        cmdErr
                );
                ret = true;
            } catch (Exception ex) {
                log.error("SSH power down command failed on host '{}': {}\nStdout: {}\nStderr: {}",
                        getVds().getHostName(),
                        ex.getMessage(),
                        cmdOut,
                        cmdErr);
                log.debug("Exception", ex);
            }
        }
        catch(IOException e) {
            log.error("IOException", e);
        }
        return ret;
    }
}

@@ -264,16 +264,66 @@
 Client;%0A
+import org.ovirt.engine.core.common.AuditLogType;%0A
 import o
@@ -1898,25 +1898,25 @@
 cuteSshPower
-d
+D
 own(getVds()
@@ -2073,28 +2073,22 @@
         
-getVds().
 set
+Vds
 Status(V
@@ -2986,54 +2986,202 @@
   %7D%0A
+        setSucceeded(result);
 %0A    
+%7D%0A%0A
     
-getReturnValue().setSucceeded(result)
+@Override%0A    public AuditLogType getAuditLogTypeValue() %7B%0A        return getSucceeded() ? AuditLogType.USER_VDS_STOP : AuditLogType.USER_FAILED_VDS_STOP
 ;%0A  
@@ -3493,17 +3493,16 @@
  @return
-s
  %7B@code 
@@ -3617,17 +3617,17 @@
 SshPower
-d
+D
 own(Stri
@@ -3910,33 +3910,32 @@
 ayOutputStream()
-;
 %0A        ) %7B%0A   

Set VDS status to down after ssh shutdown