#!/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 gobject
import gtk
import webbrowser
import socket
import thread

from winswitch.util.simple_logger import Logger
from winswitch.globals import USERNAME
from winswitch.consts import QUICK_CONNECT_HELP_URL
from winswitch.objects.global_settings import get_settings
from winswitch.objects.server_config import ServerConfig
from winswitch.ui.config_common import new_config_window, table_init, add_tableline
from winswitch.ui.ui_util import get_ui_util
from winswitch.util.config import save_server_config, modify_server_config


quick_connect_windows = {}
def show_quick_connect(client, server, save_callback, title):
	global quick_connect_windows
	quick_connect = None
	if server and server.ID:
		quick_connect = quick_connect_windows.get(server.ID)
	if not quick_connect:
		quick_connect = QuickConnectWindow(client, server, title, save_callback)
		if server and server.ID:
			quick_connect_windows[server.ID] = quick_connect
	else:
		quick_connect.client = client
		quick_connect.server = server
		quick_connect.title = title
		quick_connect.save_callback = save_callback
	if server:
		server.add_modified_callback(quick_connect.server_modified)
	quick_connect.save_callback = save_callback
	quick_connect.populate_form()
	quick_connect.unhide()

class QuickConnectWindow:

	def __init__(self, client, server, title, save_callback):
		Logger(self, log_colour=Logger.CRIMSON)
		self.settings = get_settings()
		self.client = client
		self.server = server			#the new config (or an existing config when asking for password)
		self.ui_util = get_ui_util()
		self.save_callback = save_callback
		self.title = title

		self.window = self.create_window()
		#from winswitch.util.common import schedule
		#callLater(10*60, self.close_window)			#close the window after 10 minutes


	def session_type_info_help_button(self):
		return self.make_imagebutton(None, "information", "Help page about session types", self.session_type_help, 24)

	def show_help(self, *args):
		webbrowser.open_new_tab(QUICK_CONNECT_HELP_URL)

	def create_window(self):
		window = new_config_window(self.title)

		#Contents
		vbox = gtk.VBox(False, 0)
		vbox.set_spacing(15)
		self.title_label = self.ui_util.make_label(self.title, "sans 16")
		hbox = gtk.HBox(False, 10)
		hbox.add(self.title_label)
		hbox.add(self.ui_util.make_imagebutton(None, "information", "Help page about setting up a new connection", self.show_help, 24))
		vbox.pack_start(hbox)

		table = table_init(self)
		(_, self.host_entry) = add_tableline(self, table, "Host", gtk.Entry(max=64), "The IP address or hostname to connect to")
		(_, self.username_entry) = add_tableline(self, table, "Username", gtk.Entry(max=64), "The username used to login to the server")
		self.username_entry.set_width_chars(12)
		(self.password_label, self.password_entry) = add_tableline(self, table, "Password", gtk.Entry(max=64), "The password used to login to the server")
		self.password_entry.connect("activate", self.connect_to_server)
		self.password_entry.set_width_chars(12)
		self.password_entry.set_visibility(False)
		#Mode box for SSH vs direct
		mode_box = gtk.HBox()
		self.mode_combo = gtk.combo_box_new_text()
		self.mode_combo.connect("changed", self.mode_changed)
		mode_box.add(self.mode_combo)
		mode_box.add(gtk.Label("on port"))
		self.port_entry = gtk.Entry(max=5)
		self.port_entry.set_width_chars(5)
		mode_box.add(self.port_entry)
		add_tableline(self, table, "Via", mode_box, "The protocol and port to use")
		#verify identity box:
		tooltip = "Display a confirmation dialog where the server's identification can be verified"
		self.verify_identity = gtk.CheckButton("Verify Identification")
		self.verify_identity.set_tooltip_text(tooltip)
		add_tableline(self, table, "", self.verify_identity, "Display the server's identity key and verify it before sending sensitive information")
		#end of table:
		vbox.pack_start(table)

		self.warning_label = gtk.Label("")
		vbox.pack_start(self.warning_label)

		#buttons:
		button_box = gtk.HBox()
		button_box.pack_start(self.ui_util.make_imagebutton("Cancel", "close", None, self.cancel))
		if self.server:
			button_box.pack_start(self.ui_util.make_imagebutton("Ignore", "minus", "Mark this server as disabled, this dialog will not be shown again", self.ignore))
		self.connect_button = self.ui_util.make_imagebutton("Connect", "connect", "Try to connect to this server", self.connect_to_server)
		button_box.pack_start(self.connect_button)
		vbox.pack_start(button_box)

		vbox.set_size_request(380, 280)
		window.add(vbox)
		window.show_all()
		window.connect('delete_event', self.close_window)
		self.ui_util.add_close_accel(window, self.close_window)
		return window

	def populate_form(self):
		self.sdebug()
		self.title_label.set_text(self.title)
		#Username
		if self.server:
			self.username_entry.set_text(self.server.username)
		else:
			self.username_entry.set_text(USERNAME)
		#Mode: SSH / Direct
		set_mode = None
		if self.mode_combo.get_model():
			self.mode_combo.get_model().clear()
			set_mode = 0
		if self.server:
			if not self.server.ssh_tunnel:
				set_mode = 1
			else:
				set_mode = 0
		self.mode_combo.append_text("SSH")
		self.mode_combo.append_text("Direct")
		if set_mode is not None:
			self.mode_combo.set_active(set_mode)
		#Password:
		if self.server and self.server.password:
			self.password_entry.set_text(self.server.password)
		#host:
		if self.server and self.server.host:
			self.host_entry.set_text(self.server.host)
		#port is populated in mode_changed() below
		self.password_entry.grab_focus()
		#verify:
		self.verify_identity.set_active(set_mode!=0 and (self.server is None or self.server.verify_identity))

	def mode_changed(self, *args):
		direct_port = ""
		ssh_port = "22"
		if self.server:
			if self.server.port>0:
				ssh_port = "%s" % self.server.port
			if self.server.command_port>0:
				direct_port = "%s" % self.server.command_port
		if self.mode_combo.get_active_text()=="SSH":
			port = ssh_port
		else:
			port = direct_port
		self.port_entry.set_text(port)

	def _raise(self):
		if self.window and self.window.window:
			self.window.window.show()
			return	True
		return	False

	def connect_to_server(self, *args):
		thread.start_new_thread(self.validate, ())

	def validate(self):
		try:
			self.do_validate()
		except Exception, e:
			self.serr(None, e)

	def do_validate(self):
		self._set_warning("validating..", "black")
		warning = ""
		host = self.host_entry.get_text()
		username = self.username_entry.get_text()
		password = self.password_entry.get_text()
		ssh_tunnel = self.mode_combo.get_active_text()=="SSH"
		try:
			port = int(self.port_entry.get_text())
		except:
			port = None

		if not port or port<=0 or port>65535:
			warning = "You must supply a valid port"
		elif not host or len(host)<4:
			warning = "You must supply a valid host name"
		else:
			#try to validate it better:
			try:
				socket.getaddrinfo(host, port)
			except Exception , e1:
				warning = "Invalid host name: %s" % e1
		if not warning:
			if not username:
				warning = "You must supply a valid username"
			elif not port or port<=0 or port>65535:
				warning = "You must supply a valid port"

		self._set_warning(warning)
		if not warning:
			if self.server:
				self.server.verify_identity = self.verify_identity.get_active()
			gobject.idle_add(self.do_connect_to_server, host, port, ssh_tunnel, username, password)

	def cancel(self, *args):
		self.cancel_connection()
		self.close_window()

	def ignore(self, *args):
		self.slog("server=%s" % self.server)
		assert self.server
		self.server.enabled = False
		modify_server_config(self.server, ["enabled"])
		self.cancel_connection()
		self.close_window()

	def cancel_connection(self, *args):
		if self.server and self.server.link:
			self.server.link.stop()		#stop existing attempt

	def do_connect_to_server(self, host, port, ssh_tunnel, username, password):
		self.slog(None, host, port, ssh_tunnel, username, "[...]")
		self._set_warning("connecting..", "green")
		if self.server:
			self.cancel_connection()
		else:
			self.server = ServerConfig()
			self.server.add_modified_callback(self.server_modified)
		self.server.username = username
		self.server.set_password(password)
		self.server.name = ""
		self.server.is_new = True
		self.server.host = host
		self.server.ssh_tunnel = ssh_tunnel
		self.server.auto_start = ssh_tunnel			#auto-start it if using ssh
		if not ssh_tunnel:
			self.server.command_port = port
			self.server.command_host = host
		else:
			self.server.port = port
		self.connect_button.set_sensitive(False)
		self.client.add_server(self.server)
		self.client.create_link(self.server, self.save_callback)


	def server_modified(self, *args):
		if not self.window:
			return	False
		if self.server.is_connected():
			save_server_config(self.server)
			self.close_window()
			return	False
		if self.server.is_connecting():
			self._set_warning("connecting..")
			return	True
		if self.server.invalid_login:
			self._set_warning("invalid login!")
		else:
			self._set_warning("failed")
		gobject.idle_add(self.connect_button.set_sensitive, True)
		return True

	def _set_warning(self, txt, color="red"):
		gobject.idle_add(self.warning_label.set_text, txt)
		color_obj = gtk.gdk.color_parse(color)
		if color_obj:
			gobject.idle_add(self.warning_label.modify_fg, gtk.STATE_NORMAL, color_obj)

	def show(self):
		if not self.window:
			self.window = self.create_window()
			self.populate_form()
		self.window.show()

	def close_window(self, *args):
		self.destroy_window()
		return True

	def destroy_window(self, *args):
		if self.window:
			self.window.destroy()
			self.window = None

	def unhide(self):
		self.show()
		self.window.present()
