#!/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 sys, os

from winswitch.util.paths import APP_DIR, PIPE_EXE, APP_DESKTOP_FILE, PREFIX_SEARCH_ORDER
from winswitch.consts import APPLICATION_NAME
from winswitch.util.common import is_valid_file, delete_if_exists
from winswitch.util.simple_logger import Logger, msig
from winswitch.util.format_util import format_message
from winswitch.util.file_io import get_command_icons_dir, mksubdir, RWX
from winswitch.util.icon_util import get_icon_from_data, get_data_from_icon
from winswitch.globals import insert_exit_hook, add_exit_hook, add_last_exit_hook, WIN32
from winswitch.ui.ui_util import get_ui_util
from winswitch.ui import icons

logger=Logger("win32_startmenu", log_colour=Logger.HIGHLIGHTED_BROWN)

png_not_supported = False

start_menu_location = None
if WIN32:
	import pythoncom								#@UnresolvedImport
	from win32com.shell import shell, shellcon		#@UnresolvedImport
	start_menu_location = shell.SHGetPathFromIDList (shell.SHGetSpecialFolderLocation (0, shellcon.CSIDL_PROGRAMS))
	#, shellcon.CSIDL_COMMON_PROGRAMS
	logger.sdebug("win32 programs directory=%s" % start_menu_location)


def _get_icon_location(uuid):
	return	os.path.join(get_command_icons_dir(), "%s.ico" % uuid)


def save_command_icon(uuid, data):
	global start_menu_location
	global png_not_supported
	if not start_menu_location:
		return
	if png_not_supported:
		return
	icon = get_icon_from_data(data)
	if icon:
		scaled = get_ui_util().scale_icon(icon, 48)
		filename = _get_icon_location(uuid)
		#try png:
		if not png_not_supported:
			try:
				scaled.save(filename, "png", {"depth":"16"})
			except Exception, e:
				logger.serr("error saving PNG file!", e, uuid, "[...]")
				if str(e).find("does not support saving the image format: png")>=0:
					png_not_supported = True
	elif data:
		logger.serror("failed to load icon", uuid, type(data))


def add_command(server, new_server_command):
	global start_menu_location
	if not start_menu_location:
		return
	try:
		do_add_command(server, new_server_command)
	except Exception, e:
		logger.serr(None, e, server, new_server_command)

def do_add_command(server, new_server_command):
	data = new_server_command.get_icon_data()
	if not data:
		data = get_data_from_icon(icons.get("empty"))
	save_command_icon(new_server_command.uuid, data)
	#create server sub-menu (if needed):
	server_start_menu_dir = _server_menu(server.name)
	#create category sub-menu (if needed):
	category = _category_menu(server_start_menu_dir, new_server_command.menu_category)
	#create .lnk in start menu:
	path = _create_start_menu_entry(server.ID, category, new_server_command.uuid, new_server_command.name)
	if path:
		# we may call remove before the exit_hook if the server timesout or the command is removed
		new_server_command.remove_callback = lambda : _clean_server_menu_shortcut_exit_hook(path)
		insert_exit_hook(new_server_command.remove)


def _server_menu(name):
	#create server sub-menu (if needed):
	server_start_menu_dir = os.path.join(start_menu_location, name)
	if not os.path.exists(server_start_menu_dir):
		logger.sdebug("creating directory '%s' and scheduling deletion on exit" % server_start_menu_dir, name)
		os.mkdir(server_start_menu_dir)
		add_last_exit_hook(lambda : _clean_server_menu_dir_exit_hook(server_start_menu_dir))
	return server_start_menu_dir

def _clean_server_menu_dir_exit_hook(directory):
	if os.path.exists(directory):
		os.rmdir(directory)
	else:
		logger.serror("directory is missing", directory)

def _clean_server_menu_shortcut_exit_hook(shortcut_file):
	if os.path.exists(shortcut_file):
		os.unlink(shortcut_file)
	else:
		logger.serror("file is missing", shortcut_file)


def _category_menu(server_menu, category):
	#create category sub-menu (if needed):
	category_start_menu_dir = os.path.join(server_menu, category)
	if not os.path.exists(category_start_menu_dir):
		os.mkdir(category_start_menu_dir)
		add_exit_hook(lambda : _clean_server_menu_dir_exit_hook(category_start_menu_dir))
	return category_start_menu_dir


def _create_start_menu_entry(server_id, dirname, uuid, description):
	"""
	Creates a shortcut in the given directory.
	Returns the path or None if failed.
	"""
	sig = msig(server_id, dirname, uuid, description)
	if not WIN32:
		logger.debug(sig+" only implemented for win32...")
		return	None

	from winswitch.net.local_common import COMMAND_START_SESSION

	filename = description.replace(":", " ").replace("/", "-").replace(".", " ").replace("\\", "")			#ie: dvd::rip, CD/DVD Creator, C:\ Drive

	Args = '"' + format_message(COMMAND_START_SESSION, (server_id, uuid)) + '"'
	StartIn = APP_DIR
	Path = os.path.join(dirname, "%s.lnk" % filename)
	Target = os.path.join(APP_DIR, PIPE_EXE)
	Icon = _get_icon_location(uuid)
	Description=description

	if os.path.exists(Path):
		logger.log(sig+" shortcut %s already exists - removing it!" % Path)
		os.unlink(Path)

	try:
		pythoncom.CoInitialize()
		sh = pythoncom.CoCreateInstance (
				shell.CLSID_ShellLink,
				None,
				pythoncom.CLSCTX_INPROC_SERVER,
				shell.IID_IShellLink
			)

		sh.SetPath (Target)
		sh.SetDescription (Description)
		sh.SetArguments (Args)
		sh.SetWorkingDirectory (StartIn)
		sh.SetIconLocation (Icon, 0)

		persist = sh.QueryInterface (pythoncom.IID_IPersistFile)
		persist.Save (Path, 1)
		return	Path
	except Exception, e:
		logger.error(sig+" Path=%s" % Path, e)
		return	None
	pythoncom.CoUninitialize()


#*******************************************************************************************
# For creating auto-start

def set_auto_start_state(enabled):
	auto_start_filename = _get_auto_start_file()
	if enabled:
		if not os.path.exists(auto_start_filename):
			_create_auto_start_file(auto_start_filename)
	else:
		delete_if_exists(auto_start_filename)

def get_auto_start_state():
	return	os.path.exists(_get_auto_start_file())

def _get_auto_start_file():
	if not WIN32:
		d = os.path.expanduser("~/")
		d = mksubdir(d, ".config")
		d = mksubdir(d, "autostart", RWX)
		return	os.path.join(d, APP_DESKTOP_FILE)
	else:
		startup = shell.SHGetPathFromIDList (shell.SHGetSpecialFolderLocation (0, shellcon.CSIDL_STARTUP))
		logger.sdebug("win32 startup directory=%s" % startup)
		return os.path.join(startup, "Window-Switch.lnk")

def _create_auto_start_file(auto_start_filename):
	if not WIN32:
		#easy!
		desktop_file = None
		for path in PREFIX_SEARCH_ORDER:
			filename = os.path.join(path, "share", "applications", APP_DESKTOP_FILE)
			if is_valid_file(filename):
				desktop_file = filename
				break
		if not desktop_file:
			logger.serror("could not find '%s'" % APP_DESKTOP_FILE)
		else:
			os.symlink(desktop_file, auto_start_filename)
		return

	exe = os.path.abspath(sys.argv[0])
	logger.sdebug("exe=%s" % exe)

	StartIn = os.path.dirname(exe)
	Path = auto_start_filename
	Target = exe
	Icon = (exe, 0)
	Description=APPLICATION_NAME

	sh = pythoncom.CoCreateInstance (
			shell.CLSID_ShellLink,
			None,
			pythoncom.CLSCTX_INPROC_SERVER,
			shell.IID_IShellLink
		)

	sh.SetPath (Target)
	sh.SetDescription (Description)
	sh.SetArguments ("")
	sh.SetWorkingDirectory (StartIn)
	sh.SetIconLocation (Icon)

	persist = sh.QueryInterface (pythoncom.IID_IPersistFile)
	persist.Save (Path, 1)
