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

from winswitch.util.simple_logger import Logger
from winswitch.globals import WIN32, OSX
logger=Logger("tray_util", log_colour=Logger.HIGHLIGHTED_BLUE)

TRAY = None

def setup_tray(prefer_gtk_tray, window_notray, popup_menu, activate_menu, exit_if_unclean, ask_quit, handle_session_event, default_icon_name):
	logger.sdebug(None, prefer_gtk_tray, window_notray, popup_menu, activate_menu, exit_if_unclean, ask_quit, handle_session_event, default_icon_name)
	global TRAY
	if TRAY is not None:
		raise Exception("tray already setup!")
	TRAY = do_setup_tray(prefer_gtk_tray, window_notray, popup_menu, activate_menu, exit_if_unclean, ask_quit, handle_session_event, default_icon_name)
	logger.slog("=%s" % TRAY, prefer_gtk_tray, window_notray, popup_menu, activate_menu, exit_if_unclean, ask_quit, handle_session_event, default_icon_name)
	return	TRAY


def is_ubuntu_11_10_or_later():
	lsb = "/etc/lsb-release"
	if not os.path.exists(lsb):
		return  False
	try:
		try:
			f = open(lsb, mode='rb')
			data = f.read()
		finally:
			f.close()
		props = {}
		for l in data.splitlines():
			parts = l.split("=", 1)
			if len(parts)!=2:
				continue
			props[parts[0].strip()] = parts[1].strip()
		logger.sdebug("found lsb properties: %s", props)
		if props.get("DISTRIB_ID")=="Ubuntu":
			version = [int(x) for x in props.get("DISTRIB_RELEASE", "0").split(".")]
			logger.sdebug("detected Ubuntu release %s" % str(version))
			return version>=[11,10]
	except:
		return False



def do_setup_tray(prefer_gtk_tray, window_notray, popup_menu, activate_menu, exit_if_unclean, ask_quit, handle_session_event, default_icon_name):
	log_args = (prefer_gtk_tray, window_notray, popup_menu, activate_menu, exit_if_unclean, ask_quit, handle_session_event, default_icon_name)
	def window_mode():
		try:
			from winswitch.ui.window_fake_tray import WindowFakeTray
			return	WindowFakeTray(popup_menu, activate_menu, exit_if_unclean, ask_quit, default_icon_name)
		except Exception, e:
			logger.serr("failed to setup fake window tray", e, *log_args)
			return	None
	if window_notray:
		wm = window_mode()
		if wm:
			return wm

	def gtk_tray():
		try:
			from winswitch.ui.statusicon_tray import StatusIconTray
			return	StatusIconTray(popup_menu, activate_menu, exit_if_unclean, ask_quit, default_icon_name)
		except Exception, e:
			logger.serror("failed to load gtk StatusIcon: %s" % e)
			return None
	def appindicator_tray():
		""" appindicator is Ubuntu's 'new' but incompatible, buggy and impractical StatusIcon (..) """
		try:
			from winswitch.ui.appindicator_tray import AppIndicatorTray
			return	AppIndicatorTray(popup_menu, activate_menu, exit_if_unclean, ask_quit, default_icon_name)
		except Exception, e:
			logger.serror("failed to load appindicator: %s" % e)
			return None
	def osx_tray():
		""" try to use the mac dock as a tray equivallent """
		try:
			from winswitch.ui.macdock_tray import MacDockTray
			return	MacDockTray(popup_menu, activate_menu, exit_if_unclean, ask_quit, default_icon_name)
		except Exception, e:
			logger.serr("failed to load native Mac OS X Dock", e)
			return None
	def win32_tray():
		""" MS Windows: aka "bloody annoying platform": we need to use native code to get to the hwnd for creating notifications... """
		try:
			from winswitch.ui.win32_tray import Win32Tray
			return	Win32Tray(popup_menu, activate_menu, exit_if_unclean, ask_quit, handle_session_event, default_icon_name)
		except Exception, e:
			logger.serr("failed to load native Windows NotifyIcon", e)
			return None

	tray_impls = []
	if prefer_gtk_tray:
		tray_impls.append(gtk_tray)
	if OSX:
		tray_impls.append(osx_tray)
	elif WIN32:
		tray_impls.append(win32_tray)
	else:
		#figure out if we want appindicator first
		if is_ubuntu_11_10_or_later():
			tray_impls.append(appindicator_tray)
			tray_impls.append(gtk_tray)
		else:
			tray_impls.append(gtk_tray)
			tray_impls.append(appindicator_tray)

	logger.sdebug("will tray tray implementations: %s" % str(tray_impls), *log_args)
	for impl in tray_impls:
		tray = impl()
		if tray:
			logger.slog("successfully created tray %s using %s" % (tray, impl), *log_args)
			return tray
	#use window mode as fallback:
	return	window_mode()



class BaseTray:
	""" The common superclass for all Tray implementations """

	def __init__(self, popup_menu, activate_menu, exit_cb, ask_quit, default_icon_name):
		Logger(self, log_colour=Logger.HIGHLIGHTED_BLUE)
		# callbacks to caller:
		self.popup_menu = popup_menu
		self.activate_menu = activate_menu
		self.exit = exit_cb
		self.ask_quit = ask_quit

		self.default_icon_name = default_icon_name

		self.tray_widget = None					# used by most platforms in the panel

		#only used by StatusIcon at the moment for doing animations:
		self.tray_widget_notify_counter = 0		# increment after use
		self.tray_widget_notify_images = None	# store the animation images
		self.tray_widget_animate_until = 0		# until when do we animate the tray icon

		self.setup_widget()

	def setup_widget(self):
		raise Exception("must be overriden!")

	def close(self):
		pass

	def ready(self):
		pass

	def getStatusIcon(self):
		""" used for positionning the popup menu, only implemeted in StatusIconTray """
		return	None

	def getMacDock(self):
		""" to get hold of the gtkosx_application.OSXApplication, only implemented on OSX """
		return	None

	def getHWND(self):
		""" used for returning the hwnd on win32, only implemented in win32_NotifyIcon """
		return	None

	def set_menu(self, menu):
		pass

	def set_icon(self, icon_name):
		pass

	def request_attention(self, message, delay):
		pass

	def get_size(self):
		return None

	def get_geometry(self):
		return None

	def position_menu(self, menu, tray_widget):
		return None

	def validate_position(self, menu, position):
		""" ensures that the position given is valid and returns it (modified if needed) """
		import pygtk
		pygtk.require("2.0")
		import gtk.gdk
		size = menu.size_request()
		sw = gtk.gdk.screen_width()
		sh = gtk.gdk.screen_height()
		w,h = size
		#self.sdebug("type(menu)=%s, platform=%s, screen=%sx%s, position=%s, size_request=%s" % (type(menu), sys.platform, sw, sh, str(position), str(size)), menu, tray_widget)
		if position:
			x,y,_ = position
		if not position or x>=(sw-10) or x<10 or y>=sh or y<0:
			x = sw-w-80
			if WIN32:
				""" assume that the bar is at the bottom... """
				y = sh-20
			else:
				""" assume that the bar is at the top... """
				y = 20
		if x+w>sw and x<sw:
			x = sw-w
		if y+h>sh and h<sh:
			y = sh-h
		self.sdebug("new position=%s x %s" % (x,y), menu, position)
		position = (x,y,True)
		return position

def main():
	import pygtk
	pygtk.require("2.0")
	from winswitch.util.main_loop import loop_init, loop_run, loop_exit
	loop_init(True)
	def popup_menu(*args):
		logger.slog(None, *args)
	def activate_menu(*args):
		logger.slog(None, *args)
	def exit_cb(*args):
		logger.slog(None, *args)
		loop_exit()
	def ask_quit(*args):
		logger.slog(None, *args)
		loop_exit()
	def handle_session_event(*args):
		logger.slog(None, *args)
	setup_tray(False, False, popup_menu, activate_menu, exit_cb, ask_quit, handle_session_event, "winswitch")
	loop_run()


if __name__ == "__main__":
	main()
