#!/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 re
import time

from winswitch.consts import SCREEN_TYPE, LOCALHOST
from winswitch.globals import USERNAME
from winswitch.objects.session import Session
from winswitch.objects.server_session import ServerSession
from winswitch.util.common import csv_list
from winswitch.util.config import load_session
from winswitch.util.file_io import get_screen_socket_dir
from winswitch.util.process_util import get_output
from winswitch.virt.server_util_base import ServerUtilBase
from winswitch.ui.icons import getraw


class	ScreenServerUtil(ServerUtilBase):

	SCREEN_SESSION_RE = re.compile(r"^\t(\d*)\.(\w*)\t\((\w*)\)")

	def	__init__(self, config, add_session, remove_session, update_session_status, session_failed):
		ServerUtilBase.__init__(self, SCREEN_TYPE, -1, config, add_session, remove_session, update_session_status, session_failed)
		self.prelaunch_enabled = False			#meaningless for screen
		self.watched_directory = get_screen_socket_dir()

	def get_config_options(self):
		return ["enabled"]

	def can_capture(self, session):
		""" Screenshots? How would that work anyway? Convert text to picture? """
		return	False

	def do_init(self):
		self.detect_sessions()
		ServerUtilBase.do_init(self)

	def get_test_port(self, session):
		return	-1

	def prepare_display(self, session, user):
		pass

	def	do_prepare_session_for_attach(self, session, user, disconnect, call_when_done):
		pass

	def get_session_command(self, session, server_command, screen_size, filenames):
		return None

	def start_display(self, session, user, is_preload):
		return	False

	def stop_display(self, session, user, display):
		pass

	def detect_existing_sessions(self, reloaded_sessions):
		#delete existing files:
		ServerUtilBase.zap_existing_sessions(self, reloaded_sessions)
		#detect local displays if enabled:
		screen_sessions = self.config.get_sessions_by_type(SCREEN_TYPE)
		try:
			cmd = [self.config.screen_command, "-ls"]
			try:
				code, out, _ = get_output(cmd)
				if code!=0:
					out = ""
			except Exception, e:
				self.serr("failed to run '%s'" % cmd, e, reloaded_sessions)
				out = ""

			for line in out.splitlines():
				match = ScreenServerUtil.SCREEN_SESSION_RE.match(line)
				if match:
					pid = match.group(1)
					name = match.group(2)
					state = match.group(3)
					session = self.detected_session(pid, name, state)
					self.sdebug("session=%s" % session)
					if session in screen_sessions:
						screen_sessions.remove(session)
			if len(screen_sessions)>0:
				self.slog("sessions no longer found (removing them): %s" % csv_list(screen_sessions))
				for session in screen_sessions:
					session.set_status(Session.STATUS_CLOSED)
					if self.update_session_status:
						self.update_session_status(session, session.status)
						self.config.remove_session(session)
					if self.remove_session:
						self.remove_session(session)

		except Exception, e:
			self.serr(None, e, reloaded_sessions)


	def detected_session(self, pid, name, state):
		"""
		"""
		if state=="Attached":
			status = Session.STATUS_CONNECTED
		elif state=="Detached":
			status = Session.STATUS_AVAILABLE
		elif state.startswith("Dead"):
			status = Session.STATUS_CLOSED
		else:
			self.serror("unknown state", pid, name, state)
			return
		self.slog(None, pid, name, state)
		display = ":S-%s" % pid
		session = self.config.get_session_by_display(display)
		if status==Session.STATUS_CLOSED:
			#closed: remove it if present
			if session and self.remove_session:
				self.remove_session(session)
			return	session
		elif not session:
			#not closed and not present, try to load it from disk
			session = load_session(display, False, ServerSession)
			if session:
				self.config.add_session(session)
				if self.add_session:
					self.add_session(session)
			else:
				#create a new one
				session = ServerSession(self.config)
				session.display = display
				session.set_default_icon_data(getraw("screen"))
				session.command_uuid = ""
				session.name = name
				session.host = LOCALHOST
				session.port = -1
				session.ID = self.new_ID()
				#session.requires_tunnel = ?
				session.password = "n/a"
				session.user = USERNAME
				session.status = status
				session.preload = False
				session.screen_size = None
				session.session_type = SCREEN_TYPE
				session.start_time = int(time.time())
				self.config.add_session(session)
				if self.add_session:
					self.add_session(session)
				return	session
		#if we're here, we have an existing session
		session.set_status(status)
		if self.update_session_status:
			self.update_session_status(session, session.status)	#ensures the controller deals with the status
		return	session



def main():
	from winswitch.objects.server_settings import ServerSettings
	from winswitch.util.config import get_local_server_config
	ss = get_local_server_config() or ServerSettings()
	ssu = ScreenServerUtil(ss, None, None, None, None)
	ssu.detect_sessions()

if __name__ == "__main__":
	main()
