#!/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 os
import sys
import socket
import select

# Our imports
from winswitch.util.file_io import get_local_client_socket_path
from winswitch.util.simple_logger import Logger
from winswitch.util.common import no_newlines, delete_if_exists
from winswitch.net.local_common import RESPONSE_OK, RESPONSE_NACK, RESPONSE_BUSY, TIMEOUT, COMMAND_PING
from winswitch.net.local_common import CLIENT_SUCCESS, CLIENT_ERROR_CONNECTION_FAILED, CLIENT_ERROR_TIMEOUT, CLIENT_ERROR_NACK, CLIENT_ERROR_UNKNOWN_RESPONSE

class LocalSocketClient:
	"""
	This class uses raw sockets rather than twisted because it will be used by the client before the mainloop starts.
	"""

	def __init__(self):
		Logger(self, log_colour=Logger.YELLOW)
		self.debug()
		self.timeout = 10
		self.socket_filename = get_local_client_socket_path()
		self.exit_code = None
		self.responses = []
		self.messages = None
		self.testing = False

	def clear(self):
		self.exit_code = None
		self.responses = []
		self.messages = None
		self.testing = False

	def test_socket_exists(self):
		return	os.path.exists(self.socket_filename)

	def test_socket(self, message=COMMAND_PING):
		sock_exists = self.test_socket_exists()
		self.sdebug("socket '%s' exists=%s" % (self.socket_filename, sock_exists), message)
		if not sock_exists:
			return	False
		try:
			self.testing = True
			code = self.send([message])
		except socket.error, e:
			self.serror(str(e), message)
		except Exception, e:
			self.serr(None, e)
		self.testing = False
		self.sdebug("exit code after sending message to '%s': %s" % (self.socket_filename, code), message)
		if code==CLIENT_SUCCESS:
			return	True
		else:
			self.serror("socket '%s' seems dead, removing it" % (self.socket_filename), message)
			delete_if_exists(self.socket_filename)
			return	False

	def send(self, msgs):
		self.exit_code = None
		self.exit_code = self.do_send(msgs)
		return	self.exit_code

	def do_send(self, msgs):
		if not os.path.exists(self.socket_filename):
			msg = "Socket '%s' does not exist, is winswitch_applet running?" % self.socket_filename
			self.serror(msg, msgs)
			raise Exception(msg)

		self.slog(None, msgs)
		self.messages = msgs
		try:
			sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
			sock.settimeout(self.timeout)
			try:
				sock.connect(self.socket_filename)
			except socket.error, e:
				self.serror(str(e), msgs)
				return	CLIENT_ERROR_CONNECTION_FAILED
			for message in self.messages:
				msg = "%s\n" % message
				self.sdebug("sending %s" % message, msgs)
				#send message
				written = 0
				loops = 0
				while written < len(msg) and loops<3:
					(_, wlist, _) = select.select([], [sock], [], TIMEOUT)
					if sock in wlist:
						written += sock.send(msg[written:])
						loops += 1
					else:
						self.serror("timeout sending message %s" % message, msgs)
						return	CLIENT_ERROR_TIMEOUT
				#read response
				read = 0
				loops = 0
				response = ""
				while response.find("\n")<0 and read<1024 and loops<3:
					(rlist, _, _) = select.select([sock], [], [], TIMEOUT)
					if sock in rlist:
						data = sock.recv(1024)
						read += len(data)
						response += data
						loops += 1
					else:
						self.serror("timeout waiting for response", msgs)
						return	CLIENT_ERROR_TIMEOUT
				self.sdebug("response(%s)=%s" % (message, no_newlines(response)), msgs)
				trimmed = no_newlines(response)
				self.responses.append(trimmed)
				if trimmed.startswith(RESPONSE_OK):
					continue

				if trimmed.startswith(RESPONSE_NACK):
					return	CLIENT_ERROR_NACK
				elif trimmed.startswith(RESPONSE_BUSY):
					return	CLIENT_ERROR_TIMEOUT
				return	CLIENT_ERROR_UNKNOWN_RESPONSE
		finally:
			sock.close()
		return	CLIENT_SUCCESS


def send_message(msg):
	return send_messages([msg])

def send_messages(msgs):
	client = LocalSocketClient()
	exit_code = client.send(msgs)
	return exit_code

def get_responses(msgs):
	client = LocalSocketClient()
	if client.send(msgs)==CLIENT_SUCCESS:
		return	client.responses
	return None


if __name__ == '__main__':
	exit_code = send_messages(sys.argv[1:])
	if exit_code:
		sys.exit(exit_code)
