#!/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.util.file_io import load_binary_file
from winswitch.globals import WIN32, OSX, LINUX
from winswitch.consts import XPRA_TYPE, NX_TYPE, VNC_TYPE, WINDOWS_TYPE
from winswitch.util.common import csv_list, is_valid_exe
from winswitch.util.which import which
from winswitch.util.paths import BIN_SEARCH_ORDER
from winswitch.util.process_util import twisted_exec
logger = Logger("distro_packaging_util", log_colour=Logger.WHITE)

FORCE_PACKAGEKIT_DBUS = True

def get_app(*options):
	for x in options:
		p = which(x)
		if p and os.path.exists(p):
			return p
	return None
def get_terminal_app():
	return	get_app("xterm", "lxterminal", "uxterm")
def get_sudo_app():
	return	get_app("gksudo", "sudo")

def sv(names):
	return	csv_list(names, sep=' ', before="", after="")


def make_exec_installer(command):
	def err(*args):
		logger.serror(None, args)
	def call(callback):
		logger.slog("commands=%s" % str(command), callback)
		twisted_exec(command, callback, err)
	return call


distro_helper = None
def get_distro_helper():
	global distro_helper
	if not distro_helper:
		package_map = {}
		command_paths = {}
		name = "unknown"
		manager = "unknown"
		if os.name=="posix":
			cmd_name = {XPRA_TYPE:"xpra",
						NX_TYPE:"nxproxy",
						VNC_TYPE:"vncviewer",
						WINDOWS_TYPE:"rdesktop"}
			for st,cmd in cmd_name.items():
				paths = []
				dirs = BIN_SEARCH_ORDER[:]
				if st==NX_TYPE:
					dirs.append("/usr/NX/bin")
				for d in dirs:
					p = os.path.join(d, cmd)
					paths.append(p)
				command_paths[st] = paths
		if WIN32:
			name = "Microsoft Windows"
		elif OSX:
			name = "Mac OS X"
		elif LINUX:
			redhat = load_binary_file("/etc/redhat-release")
			debian = load_binary_file("/etc/debian_version")
			gentoo = load_binary_file("/etc/gentoo-release")
			term = get_terminal_app()
			sudo = get_sudo_app()
			def pkgcmd(name, cmd):
				if os.environ.get("DISPLAY") and term and sudo:
						package_map[name] = make_exec_installer([term, "-e", "%s -A %s; read -p \"Press enter to close\"" % (sudo, cmd)])
			installer = None
			if not installer and os.environ.get("DISPLAY"):
				try:
					import dbus.glib	#old way of making glib the main loop for dbus...
					assert dbus.glib
					from dbus.mainloop.glib import DBusGMainLoop
					DBusGMainLoop(set_as_default=True)
					bus = dbus.SessionBus()
					proxy = bus.get_object('org.freedesktop.PackageKit', '/org/freedesktop/PackageKit')
					iface = dbus.Interface(proxy, 'org.freedesktop.PackageKit.Modify')
					def with_dbus(name, *package_names):
						def call_packagekit(callback):
							logger.slog("using %s" % iface, name, package_names)
							try:
								def error_handler(*args):
									logger.slog(None, args)
								def reply_handler(*args):
									logger.slog(None, args)
									callback()
								result = iface.InstallPackageNames(dbus.UInt32(0), package_names, "show-confirm-search,hide-finished", reply_handler=reply_handler, error_handler=error_handler)
								logger.sdebug("%s.InstallPackageNames(..)=%s" % (iface, result), name, package_names)
							except dbus.DBusException, e:
								logger.slog("%s.InstallPackageNames(..): %s" % (iface, e), name, package_names)
						package_map[name] = call_packagekit
					installer = with_dbus
					manager = "packagekit via dbus"
				except Exception, e:
					logger.serror("failed to load dbus packagekit: %s" % e)
			if not installer:
				gnome_package_kit = get_app("gpk-install-package-name")
				if gnome_package_kit:
					def with_gpkgkit(name, *package_names):
						package_map[name] = make_exec_installer([gnome_package_kit]+list(package_names))
					installer = with_gpkgkit
					manager = "gnome packagekit"
			if not installer:
				apper = get_app("apper")
				if apper:
					def with_apper(name, *package_names):
						package_map[name] = make_exec_installer([gnome_package_kit]+list(package_names))
					installer = with_apper
				manager = "apper"
			if not installer and redhat:
				name = redhat.split(" ")[0]
				manager = "yum"
				def yum(name, *package_names):
					pkgcmd(name, "yum install %s" % sv(package_names))
				installer = yum
			elif not installer and debian:
				name = debian.split("/")[0]
				manager = "apt"
				def apt(name, *package_names):
					pkgcmd(name, "apt-get install %s" % sv(package_names))
				installer = apt
			elif not installer and gentoo:
				name = "Gentoo"
				manager = "emerge"
				def emerge(name, *package_names):
					pkgcmd(name, "emerge -atv %s")
				installer = emerge

			if installer:
				installer(XPRA_TYPE, "xpra")
				installer(VNC_TYPE, "tigervnc")
				installer(NX_TYPE, "nx")
				installer(WINDOWS_TYPE, "rdesktop")
				if debian:
					installer("avahi", "python-avahi")
				elif redhat:
					installer("avahi", "avahi-ui-tools")
				elif gentoo:
					installer("avahi", "avahi")

		distro_helper = DistroHelper(name, manager, package_map, command_paths)
	return	distro_helper


class DistroHelper:

	def __init__(self, name, manager, package_map, command_paths):
		Logger(self)
		self.name = name
		self.manager = manager
		self.package_map = package_map
		self.command_paths = command_paths
		self.slog(None, name, manager, package_map, command_paths)

	def get_install_action(self, name):
		action = self.package_map.get(name)
		if not action:
			return	None
		return	action

	def find_command(self, name):
		""" locates the client program to use for the given session type """
		paths = self.command_paths.get(name)
		self.sdebug("paths=%s" % csv_list(paths), name)
		if not paths:
			return	None
		for p in paths:
			if is_valid_exe(p):
				self.slog("found in %s" % p, name)
				return	p
		return	None


if __name__ == "__main__":
	dh = get_distro_helper()
	logger.slog("main() distro_helper=%s" % dh)
	for st in XPRA_TYPE, NX_TYPE, VNC_TYPE, WINDOWS_TYPE:
		action = dh.get_install_action(st)
		logger.slog("main() install(%s)=%s" % (st, csv_list(action)))
		logger.slog("main() find_command(%s)=%s" % (st, dh.find_command(st)))
