
from __future__ import absolute_import
from __future__ import division

import libvirt


class NotConnectedError(Exception):
    """
    Raised when trying to talk with a vm that was not started yet or was shut
    down.
    """


class TimeoutError(libvirt.libvirtError):
    pass


class Disconnected(object):

    def __init__(self, vmid):
        self.vmid = vmid

    @property
    def connected(self):
        return False

    def __getattr__(self, name):
        raise NotConnectedError("VM %r was not defined yet or was undefined"
                                % self.vmid)


class Defined(Disconnected):

    def __init__(self, vmid, dom):
        super(Defined, self).__init__(vmid)
        self._dom = dom

    def state(self, *args, **kwargs):
        return self._dom.state(*args, **kwargs)

    def UUIDString(self):
        return self._dom.UUIDString()

    def metadata(self, *args, **kwargs):
        return self._dom.metadata(*args, **kwargs)

    def setMetadata(self, *args, **kwargs):
        self._dom.setMetadata(*args, **kwargs)

    def undefineFlags(self, flags=0):
        self._dom.undefineFlags(flags)


class Notifying(object):

    def __init__(self, dom, tocb):
        self._dom = dom
        self._cb = tocb

    @property
    def connected(self):
        return True

    def __getattr__(self, name):
        attr = getattr(self._dom, name)
        if not callable(attr):
            return attr

        def f(*args, **kwargs):
            try:
                ret = attr(*args, **kwargs)
                self._cb(False)
                return ret
            except libvirt.libvirtError as e:
                if e.get_error_code() == libvirt.VIR_ERR_OPERATION_TIMEOUT:
                    self._cb(True)
                    toe = TimeoutError(e.get_error_message())
                    toe.err = e.err
                    raise toe
                raise
        return f
