#!/usr/bin/env python

import sys
import socket
import time

from winswitch.consts import LOCALHOST, X_PORT_BASE
logger = None
SESSION_WAIT = 20


def wait_for_socket(host, port, max_wait):
	"""
	Returns True if the socket becomes available within the max_wait time.
	"""
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
	if host == "0.0.0.0":
		host = LOCALHOST
	start = time.time()
	now = start
	attempt = 1
	try:
		while now<(start + max_wait):
			logger.sdebug("attempt %d after %d seconds" % (attempt, now-start), host, port, max_wait)
			try:
				timeout = 1
				sock.settimeout(timeout)
				logger.sdebug("doing test connect to %s:%d with timeout=%s" % (host, port, timeout), host, port, max_wait)
				sock.connect((host, port))
				logger.sdebug("test connect succeeded!", host, port, max_wait)
				return	True
			except Exception, e:
				logger.serror("attempt %s: connect failed" % attempt, host, port, max_wait)
				time.sleep(0.5)
			attempt += 1
			now = time.time()
	finally:
		if sock:
			try:
				sock.close()
			except Exception, e:
				logger.serror("error trying to close socket '%s': %s" % (sock, e), host, port, max_wait)
	return	False

def start_Xnest(clientID, sessionID, Xnest, cmd):
	from winswitch.util.process_util import subprocess_terminate, exec_nopipe
	from winswitch.net.net_util import get_port_mapper
	from winswitch.server.ssh_session import notify_client
	#start Xnest display
	xnest_display = get_port_mapper().get_free_Xnest_display()
	xnest_cmd = [Xnest, ":%s" % xnest_display]
	logger.slog("starting Xnest: %s" % xnest_cmd)
	xnest_proc = exec_nopipe(xnest_cmd)

	try:
		port = X_PORT_BASE + xnest_display
		if wait_for_socket(LOCALHOST, port, SESSION_WAIT):
			display = "%s:%s" % (LOCALHOST, xnest_display)
			logger.slog("starting real command %s on DISPLAY %s" % (cmd, display))
			proc = exec_nopipe(cmd, wait=True, extra_env={"DISPLAY": display})
			logger.slog("%s terminated" % str(cmd))
			notify_client(clientID, sessionID)
			return proc.returncode
		else:
			return 1
	finally:
		subprocess_terminate(xnest_proc)

def usage():
	print("Usage: %s clientID sessionID Xnest_command command [arguments ...]")
	print("")
	print("  clientID         The owner of the session")
	print("  sessionID        The session identification")
	print("  Xnest_command    The Xnest command to use")
	print("  command          The command to start")
	print("  arguments        Optional arguments for the command")
	print("")
	print("Starts an Xnest server using the command specified.")
	print("Once the Xnest server is ready, it starts the command")
	print("specified and notifies the Window Switch")
	print("server when it terminates.")
	print("This is not meant to be used directly.")

def main():
	if len(sys.argv)<4:
		print("invalid number of arguments")
		usage()
		return	1
	from winswitch.util.simple_logger import Logger
	global logger
	logger = Logger("ssh_Xnest")

	clientID = sys.argv[1]
	sessionID = sys.argv[2]
	Xnest = sys.argv[3]
	cmd = sys.argv[4:]
	start_Xnest(clientID, sessionID, Xnest, cmd)

if __name__ == "__main__":
	sys.exit(main())
