#!/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

import gtk
import gobject

from winswitch.ui.config_common import new_config_window, table_init, add_tableline, MIN_WIDTH
from winswitch.objects.server_command import ServerCommand
from winswitch.util.config import get_settings
from winswitch.util.common import csv_list
from winswitch.ui.session_start_options_base import SessionStartOptionsBase
from winswitch.virt.options_common import SCREEN_SIZE

CELL_WIDTH = int(MIN_WIDTH/2-20)
SHOW_SOUND_OPTIONS = False				#not fully implemented yet

class SessionStartOptions(SessionStartOptionsBase):
	"""
	This dialog allows the user to select some options when starting a session:
	* the session type (xpra, nx, vnc..)
	* session type specific options (ie: jpeg compression for xpra, ..)
	* sound options (on, off, quality..)

	Note: this class is extended by SessionStartDialog to provide more options (which server to run on, etc)
	"""

	def __init__(self, server, client_utils, server_command, command_type, current_session_type, callback, opts=None, can_bookmark=True):
		SessionStartOptionsBase.__init__(self, command_type, None, opts)
		self.form_init(server, client_utils, server_command, current_session_type, callback, can_bookmark)
		self.show()
		self.add_update_notification_callbacks()

	def form_init(self, server, client_utils, server_command, current_session_type, callback, can_bookmark):
		self.server = server
		self.client_utils = client_utils
		self.server_command = server_command
		self.desktop_mode = self.command_type==ServerCommand.DESKTOP
		self.session_types = []
		self.current_session_type = current_session_type
		self.assign_session_types()
		self.callback = callback
		self.can_bookmark = can_bookmark
		self.local_init()

	def local_init(self):
		pass

	def get_session_types_for_command_type(self, command_type):
		"""
		Returns a pair: the list of session types for the command type given,
		and the the current default value.
		"""
		def get_session_types_for_command_type(hide_suboptimal):
			session_type = None
			session_types = None
			if command_type == ServerCommand.DESKTOP:
				session_types = self.get_filtered_session_types(True, hide_suboptimal)
				session_type = self.server.preferred_desktop_type
			elif command_type == ServerCommand.COMMAND:
				session_types = self.get_filtered_session_types(False, hide_suboptimal)
				session_type = self.server.preferred_session_type
			elif command_type == ServerCommand.ACTION:
				session_types = self.get_filtered_session_types(True, hide_suboptimal)
				session_type = self.server.preferred_session_type
			return	(session_types, session_type)
		hide_suboptimal = get_settings().hide_suboptimal_protocols
		if hide_suboptimal is True:
			(session_types, session_type) = get_session_types_for_command_type(True)
			if len(session_types)>0:
				return	(session_types, session_type)
		return	get_session_types_for_command_type(False)

	def get_filtered_session_types(self, desktop_only, hide_suboptimal):
		"""
		Returns the list of session types supported by this server for starting new sessions.
		"""
		from_list = get_settings().get_available_session_types(desktop_only, hide_suboptimal)
		return self.server.get_filtered_session_types(from_list, desktop_only, hide_suboptimal)

	def assign_session_types(self):
		if self.server:
			(self.session_types, self.current_session_type) = self.get_session_types_for_command_type(self.command_type)
		else:
			self.session_types = []
			self.current_session_type = None

	def add_update_notification_callbacks(self):
		"""
		Ensures we call test_reset_session_types()
		whenever the server or settings have been modified.
		"""
		self.server.add_modified_callback(self.server_modified)
		get_settings().add_modified_callback(self.settings_modified)

	def server_modified(self):
		self.check_server()
		return	self.test_reset_session_types()
	def settings_modified(self):
		return	self.test_reset_session_types()

	def test_reset_session_types(self):
		if not self.window:
			return	False
		(new_types, _) = self.get_session_types_for_command_type(self.command_type)
		mod = len(new_types) != len(self.session_types)
		if not mod:
			for session_type in self.session_types:
				if session_type not in new_types:
					mod = True
					break
		self.sdebug("old session types=%s, new=%s, mod=%s" % (csv_list(self.session_types), csv_list(new_types), mod))
		if mod:
			self.session_types = new_types
			gobject.idle_add(self.populate_session_types)
		return	True

	def check_server(self, *args):
		text = self.get_server_warning_text() or ""
		#we might be called by another thread via server_modified() or settings_modified() so use idle_add to change UI
		gobject.idle_add(self.set_server_warning, text)

	def set_server_warning(self, text):
		self.warning_label.set_text(text)
		self.start_button.set_sensitive(self.server.is_connected() and not text)
		if self.can_bookmark:
			self.bookmark.set_sensitive(self.server.is_connected() and not text)
			self.bookmark_label.set_sensitive(self.server.is_connected() and not text)

	def get_server_warning_text(self):
		if not self.server.is_connected():
			return	"Not connected to server!"
		#check server can handle this command_type via one of its supported protocols
		if self.command_type==ServerCommand.DESKTOP:
			protocols = self.get_filtered_session_types(True, False)
		elif self.command_type==ServerCommand.COMMAND:
			protocols = self.get_filtered_session_types(False, False)
		else:
			protocols = []
		if len(protocols)==0:
			return	"No compatible protocols found for starting a %s on %s" % (self.command_type, self.server.get_display_name())
		return	None


	def get_title(self):
		return	"Start %s" % self.server_command.name

	def create_window(self):
		window = new_config_window(self.get_title())
		#Contents
		self.box = self.create_form_box()
		self.box.show_all()

		#window.set_size_request(MIN_WIDTH, MIN_HEIGHT)
		window.set_border_width(15)
		window.add(self.box)
		window.connect('delete_event', self.close_window)
		self.ui_util.add_close_accel(window, self.close_window)
		return	window

	def create_form_box(self):
		box = gtk.VBox(False, 0)
		box.set_spacing(15)
		hbox = gtk.HBox(False, 0)
		# icon
		icon = self.server_command.get_icon()
		if icon:
			hbox.pack_start(self.ui_util.scaled_image(icon, 48))
		# title
		title = self.ui_util.make_label("%s" % self.server_command.name, "sans 16")
		title.set_tooltip_text("%s" % self.server_command.command)
		hbox.pack_start(title)
		box.pack_start(hbox)

		table = table_init(self)
		self.add_start_options(table)
		box.pack_start(table)

		box.pack_start(self.create_button_box())
		return	box

	def add_start_options(self, table):
		# session_type_box contains the type drop down and the help link
		self.session_type_combo = gtk.OptionMenu()
		session_type_box = gtk.HBox(False, 0)
		session_type_box.add(self.session_type_combo)
		align = gtk.Alignment(0.0, 0.5, 0.0, 0.0)
		align.add(self.ui_util.session_type_info_help_button())
		session_type_box.add(align)
		add_tableline(self, table, "Session Type", session_type_box, "The type of session service used", homogeneous=CELL_WIDTH)

		# type options box: will be populated by the protocol specific callback (see show_session_type_options)
		self.type_options_box = gtk.VBox(False, 0)
		add_tableline(self, table, None, self.type_options_box)

		self.warning_label = self.ui_util.make_label("", "sans 12", True, True)
		color_obj = gtk.gdk.color_parse("red")
		if color_obj:
			self.warning_label.modify_fg(gtk.STATE_NORMAL, color_obj)
		add_tableline(self, table, None, self.warning_label)
		self.session_type_combo.connect("changed", self.session_type_changed)
		if SHOW_SOUND_OPTIONS:
			if get_settings().supports_sound:
				(_, self.soundin_combo) = add_tableline(self, table, "Receive Session Sound", gtk.combo_box_new_text(), "How the sound from this session will be forwarded")
				(_, self.soundout_combo) = add_tableline(self, table, "Send Sound to Session", gtk.combo_box_new_text(), "How the local sound will be forwarded to this session")
				self.populate_sound_options(self.server_command)
			else:
				self.soundin_combo = None
				self.soundout_combo = None
		#bookmark
		if self.can_bookmark:
			(self.bookmark_label, self.bookmark) = add_tableline(self, table, "Bookmark", gtk.CheckButton(), "Create a bookmark for quick access to this %s" % self.command_type, homogeneous=CELL_WIDTH)

	def create_button_box(self):
		button_box = gtk.HBox(True, 10)
		button_box.pack_start(self.ui_util.make_imagebutton("Cancel", "close", None, self.close_window))
		self.start_button = self.ui_util.make_imagebutton("Start", "play", None, self.start_session)
		button_box.pack_start(self.start_button)
		return	button_box


	def get_selected_session_type(self):
		active = self.session_type_combo.get_history()
		#self.sdebug("active=%s" % active)
		if active<0 or active>=len(self.session_types):
			return	None
		return self.session_types[active]

	def get_selected_client_util(self):
		session_type = self.get_selected_session_type()
		if not session_type:
			return	None
		return	self.client_utils.get(session_type)


	def start_session(self, *args):
		session_type = self.get_selected_session_type()
		if session_type:
			#get the values before closing the window (resets values in widgets)
			screen_size = self.session_start_options.get(SCREEN_SIZE)
			bookmark = self.can_bookmark and self.bookmark.get_active()
			self.close_window()
			gobject.idle_add(self.callback, session_type, screen_size, self.session_start_options, bookmark)

	def populate_sound_options(self, server_command):
		if self.soundin_combo:
			self.soundin_combo.get_model().clear()
			self.soundin_combo.append_text("Off")
			self.soundin_combo.append_text("Mono Low Quality")
			self.soundin_combo.append_text("Stereo Medium Quality")
			self.soundin_combo.append_text("Stereo High Quality")
			if server_command and server_command.uses_sound_out:
				self.soundin_combo.set_active(1)
			else:
				self.soundin_combo.set_active(0)
		if self.soundout_combo:
			self.soundout_combo.get_model().clear()
			self.soundout_combo.append_text("Off")
			self.soundout_combo.append_text("Mono Low Quality")
			self.soundout_combo.append_text("Stereo Medium Quality")
			self.soundout_combo.append_text("Stereo High Quality")
			if server_command and server_command.uses_sound_in:
				self.soundout_combo.set_active(1)
			else:
				self.soundout_combo.set_active(0)

	def populate_session_types(self):
		self.ui_util.populate_type_menu(self.session_type_combo, self.session_types, self.current_session_type)
		self.session_type_combo.show_all()


	def do_populate_form(self):
		self.populate_session_types()
		#warning:
		self.check_server()
		self.show_session_type_options()

	def	session_type_changed(self, *args):
		if not self.populating:
			old = self.current_session_type
			self.current_session_type = self.get_selected_session_type()
			if old!=self.current_session_type:
				self.show_session_type_options()

	def show_session_type_options(self):
		for w in self.type_options_box.get_children():
			self.type_options_box.remove(w)
		client_util = self.client_utils.get(self.get_selected_session_type())
		if client_util:
			def option_changed(key, value):
				self.sdebug("current options=%s" % self.session_start_options, key, value)
				self.session_start_options[key] = value
			option_widgets = client_util.get_options_widgets(self.server, self.server_command, self.shadowed_session, self.session_start_options, client_util.get_default_options(), option_changed)
			self.sdebug("option_widgets=%s" % str(option_widgets))
			if len(option_widgets)>0:
				table = table_init(self.type_options_box)
				table.set_homogeneous(True)
				for label,widget in option_widgets:
					add_tableline(self.type_options_box, table, label, widget)
				self.type_options_box.add(table)
			self.type_options_box.show_all()


	def show(self):
		SessionStartOptionsBase.show(self)
		self.show_session_type_options()
