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

COMMAND_AWAY = "away"
COMMAND_BACK = "back"
COMMAND_OPEN = "open"
COMMAND_LIST_SERVERS = "list_servers"
COMMAND_LIST_ALL_SERVERS = "list_all_servers"
COMMAND_PING = "ping"
COMMAND_EXIT = "exit"
COMMAND_START_SESSION = "start_session"
COMMAND_WRAPPER_START_SESSION = "wrapper_start_session"
COMMAND_WAKEUP = "wakeup"
COMMAND_OPEN_SERVER_CONFIG = "open_server_config"

RESPONSE_OK = "OK"
RESPONSE_NACK = "NACK"
RESPONSE_BUSY = "BUSY"

TIMEOUT = 10

""" This is the pipe location on win32 """
PIPE_NAME = "\\\\.\\pipe\\WindowsShifter"

CLIENT_SUCCESS = 0
CLIENT_ERROR_CONNECTION_FAILED = -1
CLIENT_ERROR_TIMEOUT = -2
CLIENT_ERROR_NACK = -3
CLIENT_ERROR_UNKNOWN_RESPONSE = -4
CLIENT_UNKNOWN_ERROR = -5


from winswitch.util.simple_logger import Logger
from winswitch.util.common import visible_command, no_newlines
from winswitch.util.format_util import parse_message_string, format_message
from winswitch.consts import APPLICATION_NAME, NOTIFY_INFO
from winswitch.globals import WIN32

def make_local_listener(client):
	def make_line_handler(send_method, stop_cb=None):
		return	LocalCommandHandler(client, send_method, stop_cb)

	if not WIN32:
		from winswitch.net.local_socket_listener import LocalSocketListener
		return LocalSocketListener(make_line_handler)
	else:
		from winswitch.net.local_namedpipe_listener import NamedPipeListener
		return NamedPipeListener(make_line_handler)

def make_local_client():
	if not WIN32:
		from winswitch.net.local_socket_client import LocalSocketClient
		return LocalSocketClient()
	else:
		from winswitch.net.local_namedpipe_client import LocalNamedPipeClient
		return LocalNamedPipeClient()




class LocalCommandHandler:
	def __init__(self, client, send_method, stop_cb=None):
		Logger(self, log_colour=Logger.YELLOW)
		self.client = client
		self.send_method = send_method
		self.stop_callback = stop_cb

	def handle(self, line):
		self.debug("(%s)" % visible_command(line))
		self.handle_command(no_newlines(line))

	def send(self, command, *args):
		self.sdebug(None, command, *args)
		msg = format_message(command, *args)
		self.send_method(msg)

	def handle_command(self, raw_cmd):
		self.slog(None, visible_command(raw_cmd))
		parsed = parse_message_string(raw_cmd)
		self.sdebug("parsed=%s" % str(parsed), visible_command(raw_cmd))
		if not parsed:
			self.send(RESPONSE_NACK)
		(command, args) = parsed
		if command == COMMAND_AWAY:
			if self.client:
				self.client.do_idle_connected_sessions()
				return	self.ok()
		elif command == COMMAND_BACK:
			if self.client:
				self.client.do_resume_idle_sessions()
				return	self.ok()
		elif command == COMMAND_PING:
			if self.client:
				return	self.ok()
		elif command == COMMAND_WAKEUP:
			if self.client:
				self.client.notify(APPLICATION_NAME+" is already running", "", notification_type=NOTIFY_INFO)
				return	self.ok()
		elif command == COMMAND_LIST_SERVERS or command == COMMAND_LIST_ALL_SERVERS:
			if self.client:
				available = []
				if command==COMMAND_LIST_SERVERS:
					servers = [x for x in self.client.servers if (x.enabled and x.is_connected())]
				else:
					from winswitch.util.config import load_server_configs
					servers = load_server_configs(include_dynamic=True)
				for server in servers:
					available.append("%s:%s:%s" % (server.name, server.type, server.ID))
				msg = format_message(RESPONSE_OK, available)
				self.slog("message=%s" % msg, visible_command(raw_cmd))
				self.send(msg)
				return
		elif command == COMMAND_OPEN:
			server_id = args[0]
			files = args[1:]
			self.slog("server=%s, files=%s" % (server_id, str(files)), visible_command(raw_cmd))
			if self.client:
				self.client.open_on_server(server_id, files)
				return	self.ok()
		elif command == COMMAND_OPEN_SERVER_CONFIG:
			filename = args[0]
			self.slog("filename=%s" % filename, visible_command(raw_cmd))
			if self.client:
				self.client.do_open_server_config(filename)
				return	self.ok()
		elif command == COMMAND_START_SESSION:
			server_id = args[0]
			command_uuid = args[1]
			if self.start_command(server_id, command_uuid):
				return	self.ok()
		elif command == COMMAND_WRAPPER_START_SESSION:
			if self.wrapper_start_command(args):
				return	self.ok()
		elif command == COMMAND_EXIT:
			self.slog("server=%s, files=%s" % (server_id, str(files)), visible_command(raw_cmd))
			self.client.exit()
			return	self.ok()
		else:
			self.serror("unknown command!", visible_command(raw_cmd))
		self.nok()

	def nok(self, *details):
		self.send(RESPONSE_NACK, *details)
		return	RESPONSE_NACK

	def ok(self):
		self.send(RESPONSE_OK)
		return	RESPONSE_OK

	def wrapper_start_command(self, args):
		self.slog(None, args)
		if not args:
			return	False
		#find the local server:
		def find_local_server():
			for server in self.client.servers:
				if server.local:
					return server
			return	None
		server = find_local_server()
		self.slog("server=%s" % server, args)
		if not server:
			return	False
		#id, name, command, comment, icon_filename, names={}, comments={}, categories=[]):
		real_cmd = " ".join(args)
		command = server.get_server_command_by_command(real_cmd)
		if not command:
			""" Use a custom command using the magic prefix """
			from winswitch.objects.server_command import ServerCommand
			cmduri = "%s%s" %(ServerCommand.CUSTOM_UUID_PREFIX, real_cmd)
			command = ServerCommand(cmduri, "Custom Command", args[0], "Shortcut Wrapper", "custom_command")
		return	self.client.default_start_session(server, command)

	def start_command(self, server_id, command_uuid):
		try:
			self.do_start_command(server_id, command_uuid)
		except Exception, e:
			self.exc(e)
			#FIXME: report to user?

	def do_start_command(self, server_id, command_uuid):
		self.sdebug(None, server_id, command_uuid)
		if not self.client:
			return	False
		for server in self.client.servers:
			#self.debug("(%s,%s) testing server=%s, ID=%s" % (server_id, command_uuid, server, server.ID))
			if server.ID == server_id:
				self.sdebug("found server=%s" % server, server_id, command_uuid)
				command = server.get_command_by_uuid(command_uuid)
				if command:
					self.sdebug("found command=%s" % command, server_id, command_uuid)
					self.client.default_start_session(server, command)
					return	True
				self.serror("command not found in server %s!" % server, server_id, command_uuid)
				return	False
		self.serror("server not found!", server_id, command_uuid)
		return	False
