#!/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 twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import stdio

from winswitch.consts import DELIMITER, MAX_LINE_LENGTH
from winswitch.util.common import visible_command
#don't want to confuse process output with channel:
from winswitch.util.simple_logger import set_log_to_tty
from winswitch.util.process_util import exec_nopipe
set_log_to_tty(False)

winswitch_client = None
stdio_client = None
winswitch_buffer = []

MAX_SERVER_WAIT = 30

ECHO_ALL = False

SERVER_CONNECTION_ESTABLISHED = "server connection established"
SERVER_CONNECTION_FAILED = "server connection failed"
SERVER_CONNECTION_LOST = "server connection lost"
STDIO_CONNECTION_ESTABLISHED = "stdio connection established"

class StdIO(stdio.StandardIO):
	""" This wrapper stops the reactor when a connection is lost """

	def __init__(self, proto, stdin=0, stdout=1):
		stdio.StandardIO.__init__(self, proto, stdin, stdout)
		self.closed = False

	def childConnectionLost(self, fd, reason):
		print("StdIO(%s,%s)" % (fd, reason))
		stdio.StandardIO.childConnectionLost(self, fd, reason)
		if not self.closed:
			self.closed = True
			self.loseConnection()
			from winswitch.util.main_loop import loop_exit, callLater
			callLater(0, loop_exit)


class WinSwitchClient(LineReceiver):
	def connectionMade(self):
		self.MAX_LENGTH = MAX_LINE_LENGTH
		self.delimiter = DELIMITER
		global winswitch_client, winswitch_buffer
		winswitch_client = self
		stdio_client.out("OK 'WinSwitchClient sending %s buffered lines'" % len(winswitch_buffer))
		stdio_client.out("OK 'WinSwitchClient %s'" % SERVER_CONNECTION_ESTABLISHED)
		while len(winswitch_buffer)>0:
			self.out(winswitch_buffer.pop(0))
			#self.sendLine("%s" % winswitch_buffer.pop(0))

	def out(self, line):
		self.transport.write("%s%s" % (line, DELIMITER))

	def lineReceived(self, line):
		stdio_client.out(line)


class StdioClient(LineReceiver):

	def connectionMade(self):
		global stdio_client
		self.MAX_LENGTH = MAX_LINE_LENGTH
		self.delimiter = DELIMITER
		stdio_client = self
		self.out("OK '%s'" % STDIO_CONNECTION_ESTABLISHED)

	def out(self, line):
		self.transport.write("%s%s" % (line, DELIMITER))

	def lineReceived(self, line):
		#self.sendLine('Echo: ' + line+", winswitch_client=%s" % winswitch_client)
		global winswitch_client, winswitch_buffer
		if ECHO_ALL:
			self.out("OK 'StdioClient echo:','%s','%s'" % (visible_command(line), winswitch_client))
		if winswitch_client:
			#winswitch_client.write("%s\n" % line)
			winswitch_client.out(line)
			#winswitch_client.sendLine(line)
		else:
			winswitch_buffer.append(line)
			#NOT_CONNECTED_TO_SERVER = "not connected to server!"
			#self.transport.write("NOK '%s'\n" % NOT_CONNECTED_TO_SERVER)

class WinSwitchClientFactory(ClientFactory):
	protocol = WinSwitchClient

	def __init__(self, stop_cb):
		self.stop_cb = stop_cb
		self.start_server = True
		self.server_start_time = 0

	def clientConnectionFailed(self, connector, reason):
		print("NOK '%s','%s':" % (SERVER_CONNECTION_FAILED, reason.getErrorMessage()))
		import time
		now = time.time()
		if not self.start_server or (self.server_start_time>0 and (self.server_start_time+MAX_SERVER_WAIT<now)):
			self.stop_cb()
			return
		if self.server_start_time==0:
			self.server_start_time = now
			cmd = ["winswitch_server", "--daemon"]
			proc = exec_nopipe(cmd)
			print("OK started server: %s" % proc)
			retry_wait_time = 5
		else:
			print("OK connect failed, trying again")
			retry_wait_time = 1
		#try to connect again in a few seconds:
		from winswitch.util.main_loop import callLater
		callLater(retry_wait_time, connector.connect)

	def clientConnectionLost(self, connector, reason):
		print("NOK '%s','%s'" % (SERVER_CONNECTION_LOST, reason.getErrorMessage()))
		self.stop_cb()
