from contextlib import contextmanager

from parallels.core import messages
from parallels.core.connections.ssh.connection_pool import SSHConnectionPool
from parallels.core.migrator_config import PhysicalUnixServerConfig, PhysicalWindowsServerConfig
from parallels.core.runners.windows.agent import WindowsAgentRunner
from parallels.core.utils.session_dir import WindowsSessionDir, UnixSessionDir
from parallels.core.utils.common import cached


class PhysicalServer(object):
    @property
    def node_id(self):
        """For compatibility with old code.

        Switch to server_id property instead"""
        return self.settings().server_id

    @contextmanager
    def runner(self):
        raise NotImplementedError()

    def is_windows(self):
        """
        :rtype: bool
        """
        raise NotImplementedError()

    def settings(self):
        """
        :rtype: parallels.core.migrator_config.PhysicalServerConfig
        """
        raise NotImplementedError()

    def ip(self):
        """
        :rtype: str
        """
        return self.settings().ip

    def description(self):
        """
        :rtype: unicode
        """
        return messages.PHYSICAL_SERVER_DESCRIPTION % self.ip()

    def get_session_file_path(self, filename):
        return self.session_dir.get_file_path(filename)

    def get_session_dir_path(self):
        return self.session_dir.get_session_dir_path()

    @property
    @cached
    def session_dir(self):
        if self.is_windows():
            return WindowsSessionDir(self.runner, self.settings().session_dir)
        else:
            return UnixSessionDir(self.runner, self.settings().session_dir)


class PhysicalWindowsServer(PhysicalServer):
    def __init__(self, settings):
        """
        :type settings: parallels.core.migrator_config.PhysicalWindowsServerConfig
        """
        self._settings = settings

    def settings(self):
        """
        :rtype: parallels.core.migrator_config.PhysicalWindowsServerConfig
        """
        return self._settings

    def is_windows(self):
        """
        :rtype: bool
        """
        return True

    @contextmanager
    def runner(self):
        yield WindowsAgentRunner(self._settings)


class PhysicalUnixServer(PhysicalServer):
    def __init__(self, settings):
        """
        :type settings: parallels.core.migrator_config.PhysicalUnixServerConfig
        """
        self._settings = settings

    def settings(self):
        """
        :rtype: parallels.core.migrator_config.PhysicalUnixServerConfig
        """
        return self._settings

    def is_windows(self):
        """
        :rtype: bool
        """
        return False

    @contextmanager
    def runner(self):
        yield SSHConnectionPool.get_instance().get(self._settings, self)


def create_physical_server(settings):
    """
    :rtype: parallels.core.connections.physical_server.PhysicalServer
    """
    if isinstance(settings, PhysicalUnixServerConfig):
        return PhysicalUnixServer(settings)
    elif isinstance(settings, PhysicalWindowsServerConfig):
        return PhysicalWindowsServer(settings)
    else:
        assert False
