#!/usr/bin/env python

# This file is part of Window-Switch.
# Copyright (c) 2009-2013 Antoine Martin <antoine@nagafix.co.uk>
# Window-Switch is released under the terms of the GNU GPL v3


from winswitch.util.simple_logger import Logger
logger = Logger("server_config")
debug_import = logger.get_debug_import()


debug_import("server_base")
from winswitch.objects.server_base import ServerBase
debug_import("stateful_object")
from winswitch.objects.stateful_object import StatefulObject
debug_import("session")
from winswitch.objects.session import ALLOW_SSH_DESKTOP_MODE, do_get_available_session_types
debug_import("global_settings")
from winswitch.objects.global_settings import get_settings
debug_import("globals")
from winswitch.globals import USERNAME, WIN32
debug_import("consts")
from winswitch.consts import SSH_TYPE
debug_import("crypt_util")
from winswitch.util.crypt_util import encrypt_hex
debug_import("all done")


class ServerConfig(ServerBase, StatefulObject):
	STATUS_NOT_CONNECTED = "not_connected"
	STATUS_CONNECTING = "connecting"
	STATUS_CONNECTED = "connected"
	STATUS_SHUTTING_DOWN = "shutting_down"
	STATUS_DISCONNECTED = "disconnected"

	ALL_STATUS = [STATUS_NOT_CONNECTED, STATUS_CONNECTING, STATUS_CONNECTED, STATUS_SHUTTING_DOWN, STATUS_DISCONNECTED]
	FINAL_STATUS = []
	"""
	Represents the information about a server as seen by a client.
	"""
	PERSIST = ServerBase.PERSIST_COMMON + [
			"# Connection details:",
			"host", "port",
			"username", "encrypted_password",
			"administrator_login",
			"default_command_port",
			"command_port_auto",
			"line_speed", "timeout",
			"# SSH Authentication keyfile to use:",
			"ssh_keyfile", "ssh_pub_keyfile", "encrypted_ssh_keyfile_passphrase", "ssh_hostkey_fingerprint",
			"# Flags and session type settings:",
			"enabled", "auto_connect", "auto_start",
			"preload_tunnels",
			"preferred_session_type", "preferred_desktop_type",
			"local_shortcuts",
			"auto_resume", "dynamic", "local",
			"locale"]
	DEFAULT_NAME = "New Server"

	def __init__(self, skip_detection=False):
		ServerBase.__init__(self)
		StatefulObject.__init__(self, ServerConfig.ALL_STATUS, ServerConfig.FINAL_STATUS)
		settings = get_settings()
		self.name = ServerConfig.DEFAULT_NAME
		self.username = USERNAME				#login username
		self.administrator_login = ""			#for logging in via root/Administrator accounts
		self.password = ""
		self.encrypted_password = ""
		self.default_command_port = 0

		self.host = "127.0.0.1"
		self.port = 22
		self.timeout = 20
		self.ssh_keyfile = settings.ssh_keyfile
		self.ssh_pub_keyfile = settings.ssh_pub_keyfile
		self.ssh_keyfile_passphrase = ""
		self.encrypted_ssh_keyfile_passphrase = ""
		self.ssh_hostkey_fingerprint = ""
		self.command_port_auto = True
		self.command_port = 0
		self.command_host = None

		self.enabled = True
		self.auto_connect = True
		self.auto_resume = False
		self.auto_start = False
		self.preload_tunnels = True
		#self.ssh_command = SSH_COMMAND
		self.dynamic = False					#for hosts found via mDNS
		self.local = False						#for hosts found via local file
		self.embedded_server = None				#for servers embedded in the client (running in the same process, via fake connection)

		self.preferred_session_type = settings.preferred_session_type
		self.preferred_desktop_type = settings.preferred_desktop_type
		self.line_speed = settings.default_internet_speed

		self.tunnel_fs = settings.tunnel_fs
		self.tunnel_sink = settings.tunnel_sink
		self.tunnel_source = settings.tunnel_source
		self.tunnel_printer = settings.tunnel_printer
		#Tunnel ports: ports assigned by the server (we must setup a tunnel from there to a local service)
		self.remote_samba_tunnel_port = -1				#forward our local smb server
		self.remote_ipp_tunnel_port = -1				#forward our local ipp server

		self.xnest_command = ""
		self.local_shortcuts = []			#list of commands we bookmarked

		self.locale = ""

		#whether we verify the server's identity - windows user's won't by default as they are easily confused and just click OK anyway:
		self.verify_identity = not WIN32
		self.link = None					#instance of ServerLink used to connect/communicate with this server
		self.invalid_login = False
		self.app_version = None
		self.version_info = None

		self.xmodmap_sent = False
		self.is_new = False
		self.last_sync_sent = 0

	def is_connected(self):
		return	self.status==ServerConfig.STATUS_CONNECTED
	def is_connecting(self):
		return	self.status==ServerConfig.STATUS_CONNECTING

	def get_display_name(self):
		if self.name:
			return	self.name
		return	"%s:%s" % (self.host, self.port)

	def __str__(self):
		return	"ServerConfig(%s:%s)" % (self.name, self.ID)

	def get_available_session_types(self, desktop_only=False, hide_suboptimal=False):
		#we override so we can remove SSH for local servers
		types = ServerBase.get_available_session_types(self, desktop_only, hide_suboptimal)
		if hide_suboptimal and SSH_TYPE in types:
			types.remove(SSH_TYPE)
		return types


	def validate_default_session_types(self):
		"""
		Ensures that the default session types chosen are available.
		"""
		settings = get_settings()
		xpra	= self.supports_xpra and settings.supports_xpra
		nx	= self.supports_nx and settings.supports_nx
		vnc	= self.supports_vnc and settings.supports_vnc
		ssh = self.supports_ssh and settings.supports_ssh
		xpra_desktop	= self.supports_xpra_desktop and settings.supports_xpra
		ssh_desktop = self.supports_ssh_desktop and settings.supports_ssh
		rdp = self.supports_rdp and settings.supports_rdp
		rdp_seamless = self.supports_rdp_seamless and settings.supports_rdp
		libvirt = False		#self.supports_libvirt - not used for defaults
		virtualbox = False	#self.supports_virtualbox - not used for defaults
		#Ensure the preferred seamless type is valid:
		avail_seamless = do_get_available_session_types(xpra, xpra_desktop, nx, ssh, ssh_desktop, vnc, libvirt, virtualbox, rdp_seamless, rdp, False, False)
		if not self.preferred_session_type or self.preferred_session_type not in avail_seamless:
			if len(avail_seamless)>0:
				self.preferred_session_type = avail_seamless[0]
			else:
				self.preferred_session_type = None
			self.slog("preferred_session_type set to %s for %s" % (self.preferred_session_type, self.get_display_name()))
		#Ensure the preferred desktop type is valid:
		avail_desktop = do_get_available_session_types(xpra, xpra_desktop, nx, ssh, ssh_desktop, vnc, libvirt, virtualbox, rdp_seamless, rdp, True, False)
		if not self.preferred_desktop_type or self.preferred_desktop_type not in avail_desktop:
			if len(avail_desktop)>0:
				self.preferred_desktop_type = avail_desktop[0]
			else:
				self.preferred_desktop_type = None
			self.slog("preferred_desktop_type set to %s for %s" % (self.preferred_desktop_type, self.get_display_name()))


	def has_desktop_protocol(self):
		return (self.supports_vnc and get_settings().supports_vnc) or \
				(self.supports_nx and get_settings().supports_nx) or \
				self.supports_rdp

	def has_seamless_protocol(self):
		return self.has_desktop_protocol() or \
				(self.supports_xpra	and get_settings().supports_xpra) or \
				(self.supports_nx	and get_settings().supports_nx) or \
				(self.supports_ssh	and get_settings().supports_ssh) or \
				self.supports_rdp_seamless


	#These settings use global defaults: we only enable on the server config, the modes which are allowed by the global settings
	def test_supports_xpra_desktop(self):
		return	get_settings().supports_xpra
	def test_supports_xpra(self):
		return	get_settings().supports_xpra
	def test_supports_xprashadow(self):
		return	get_settings().supports_xpra
	def test_supports_nx(self):
		return	get_settings().supports_nx
	def test_supports_vnc(self):
		return	get_settings().supports_vnc
	def test_supports_vncshadow(self):
		return	get_settings().supports_vnc
	def test_supports_gstvideo(self):
		return	get_settings().supports_gstvideo
	def test_supports_rdp(self):
		return	get_settings().supports_rdp
	def test_supports_rdp_seamless(self):
		return	get_settings().supports_rdp
	def test_supports_ssh(self):
		return	get_settings().supports_ssh
	def test_supports_ssh_desktop(self):
		return	ALLOW_SSH_DESKTOP_MODE and get_settings().supports_ssh
	def test_supports_screen(self):
		return	get_settings().supports_screen
	def test_supports_libvirt(self):
		return	get_settings().supports_vnc
	def test_supports_virtualbox(self):
		return	get_settings().supports_vnc


	def set_password(self, password):
		self.password = password
		key = get_settings().get_key()
		self.encrypted_password = "%s:%s" % (get_settings().get_key_fingerprint(), encrypt_hex(key, password))

	def set_ssh_keyfile_passphrase(self, passphrase):
		self.ssh_keyfile_passphrase = passphrase
		key = get_settings().get_key()
		self.encrypted_ssh_keyfile_passphrase = "%s:%s" % (get_settings().get_key_fingerprint(), encrypt_hex(key, passphrase))
