
from __future__ import absolute_import
from __future__ import division

from vdsm.common import exception
from vdsm.common import response
from vdsm import utils


class VmPowerDown(object):
    returnMsg = 'Machine power down'

    def __init__(self, vm, delay, message, timeout, force, event):
        self.vm = vm
        self.chain = utils.CallbackChain()
        self.delay = delay
        self.message = message
        self.timeout = timeout
        self.event = event

        self.chain.addCallback(self.qemuGuestAgentCallback)

        if vm.guestAgent.isResponsive():
            self.chain.addCallback(self.ovirtGuestAgentCallback)

        if vm.acpi_enabled():
            self.chain.addCallback(self.acpiCallback)

        if force:
            self.chain.addCallback(self.forceCallback)

    def start(self):
        self.vm.log.info("Starting powerdown")
        if self.chain.callbacks:
            self.event.clear()

            self.chain.start()
            return response.success(message=self.returnMsg)
        else:
            return response.error(
                'exist',
                message='VM without ACPI or active oVirt guest agent. '
                        'Try Forced Shutdown.')


    def qemuGuestAgentCallback(self):
        return False

    def ovirtGuestAgentCallback(self):
        return False

    def acpiCallback(self):
        return False

    def forceCallback(self):
        return False


class VmShutdown(VmPowerDown):
    returnMsg = 'Machine shutting down'

    def qemuGuestAgentCallback(self):
        self.vm.log.debug("Shutting down with guest agent")
        try:
            self.vm.qemuGuestAgentShutdown()
        except exception.VdsmException:
            self.vm.log.warning("Shutting down with guest agent FAILED")
            return False

        return utils.log_success(
            self.event.wait(self.timeout),
            self.vm.log,
            "Shutting down with guest agent succeeded",
            "Shutting down with guest agent timeout out"
        )

    def ovirtGuestAgentCallback(self):
        self.vm.log.debug("Shutting down with oVirt agent")
        self.vm.guestAgent.desktopShutdown(self.delay, self.message, False)
        return utils.log_success(
            self.event.wait(self.delay + self.timeout),
            self.vm.log,
            "Shutting down with oVirt agent succeeded",
            "Shutting down with oVirt agent timed out"
        )

    def acpiCallback(self):
        self.vm.log.debug("Shutting down with ACPI")
        if response.is_error(self.vm.acpiShutdown()):
            self.vm.log.warning("Shutting down with ACPI FAILED")
            return False

        return utils.log_success(
            self.event.wait(self.timeout),
            self.vm.log,
            "Shutting down with ACPI succeeded",
            "Shutting down with ACPI timed out"
        )

    def forceCallback(self):
        self.vm.log.debug("Shutting down with FORCE")
        self.vm.doDestroy()

        return utils.log_success(
            self.event.wait(self.timeout),
            self.vm.log,
            "Shutting down with FORCE succeeded",
            "Shutting down with FORCE timed out"
        )


class VmReboot(VmPowerDown):
    returnMsg = 'Machine rebooting'

    def qemuGuestAgentCallback(self):
        self.vm.log.debug("Rebooting with guest agent")
        try:
            self.vm.qemuGuestAgentReboot()
        except exception.VdsmException:
            self.vm.log.warning("Rebooting with guest agent FAILED")
            return False

        return utils.log_success(
            self.event.wait(self.timeout),
            self.vm.log,
            "Shutting down with FORCE succeeded",
            "Shutting down with FORCE timed out"
        )

    def ovirtGuestAgentCallback(self):
        self.vm.log.debug("Rebooting with oVirt agent")
        self.vm.guestAgent.desktopShutdown(self.delay, self.message, True)

        return utils.log_success(
            self.event.wait(self.delay + self.timeout),
            self.vm.log,
            "Rebooting with oVirt agent succeeded",
            "Rebooting with oVirt agent timed out",
        )

    def acpiCallback(self):
        self.vm.log.debug("Rebooting with ACPI")
        if response.is_error(self.vm.acpiReboot()):
            self.vm.log.warning("Rebooting with ACPI FAILED")
            return False

        return utils.log_success(
            self.event.wait(self.timeout),
            self.vm.log,
            "Rebooting with ACPI succeeded",
            "Rebooting with ACPI timed out"
        )

    def forceCallback(self):
        self.vm.log.debug("Rebooting with force")
        self.vm._dom.reset(0)

        return utils.log_success(
            self.event.wait(self.timeout),
            self.vm.log,
            "Rebooting with force succeeded",
            "Rebooting with force timed out",
        )
