#!/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.objects.common import ModifiedCallbackObject

COMMAND_FIELD_CODES = re.compile("%[fFuUdDnNickvm]")

def strip_exec(command):
	return re.sub(COMMAND_FIELD_CODES, "", command)

class ServerCommand(ModifiedCallbackObject):
	COMMAND = "Command"
	CATEGORY = "Category"
	DESKTOP = "Desktop"
	ACTION = "Action"

	CUSTOM_UUID_PREFIX = "custom-command://";

	UPDATABLE_FIELDS = ["name", "command", "comment",
						"type", "filename",
						"names", "comments", "categories", "menu_category", "uses_sound_out", "uses_sound_in",
						"args"]

	def __init__(self, uuid, name, command, comment, icon_filename, names={}, comments={}, categories=[]):
		ModifiedCallbackObject.__init__(self)
		self.uuid = uuid
		self.name = name
		self.command = command
		self.comment = ""
		if comment:
			self.comment = comment
		self.type = ServerCommand.COMMAND
		self.icon_names = []
		self.icon_names_failed = False
		self.icon_data = None
		self.icon_filename = icon_filename
		self.icon = None
		self.filename = ""
		self.names = names
		self.comments = comments
		self.categories = categories
		self.menu_category = ""
		self.args = ""
		self.missing_data_warning = False
		self.logger = None
		self.uses_sound_in = False				#this command is likely to make use of sound input
		self.uses_sound_out = False				#this command is likely to make use of sound output
		self.uses_video = None					#this command is likely to send video or high rate of screen updates
		self.run_once_only = False				#this command cannot run more than one instance per user
		self.remove_callback = None				#so we can remove shortcuts (and do it only once)
		self.enabled = True
		self.last_updated = time.time()

	def update(self, command):
		return	self.update_fields(ServerCommand.UPDATABLE_FIELDS, command)

	def get_command_for_display(self, display, filenames=None):
		"""
		This is here so we can override it when the command varies with the display.
		If the argument filename(s) are provided, we can also place them where they belongs in the command string.
		"""
		cmd = self.command
		if not filenames:
			return	strip_exec(cmd)
		if cmd.find("%f")>0 or cmd.find("%u")>0:
			if len(filenames)>1:
				raise Exception("'%s' cannot handle more than one file at once!" % cmd)
			if cmd.find("%f")>0:
				return	cmd.replace("%f", filenames[0])
			elif cmd.find("%u")>0:
				return	cmd.replace("%u", filenames[0])
		elif cmd.find("%F")>0 or cmd.find("%U")>0:
			joined = "' '".join(filenames)
			args = "'%s'" % joined
			if cmd.find("%F")>0:
				return	cmd.replace("%F", args)
			elif cmd.find("%U")>0:
				return	cmd.replace("%U", args)
		return	cmd

	def remove(self):
		if self.remove_callback:
			self.remove_callback()
			self.remove_callback = None

	def get_icon(self):
		if not self.icon and self.icon_data:
			from winswitch.util.icon_util import get_icon_from_data
			self.icon = get_icon_from_data(self.icon_data)
			if not self.icon:
				if not self.logger:
					from winswitch.util.simple_logger import Logger
					self.logger = Logger(self, log_colour=Logger.CYAN)
				self.serror("for %s, invalid data!" % self)
				self.icon_data = None
		return self.icon

	def get_icon_data(self):
		if not self.icon_data and self.icon:
			from winswitch.util.icon_util import get_data_from_icon
			self.icon_data = get_data_from_icon(self.icon)
		return self.icon_data

	def set_icon_data(self, data):
		self.icon = None
		self.icon_data = data

	def lookup_icon_data(self):
		self.get_icon_data()
		if not self.icon_data and len(self.icon_names)>0 and not self.icon_names_failed:
			from winswitch.util.common import is_valid_file, load_binary_file
			for icon_name in self.icon_names:
				if is_valid_file(icon_name):
					self.icon_data = load_binary_file(icon_name)
				else:
					from winswitch.util.icon_cache import guess_icon_from_name
					self.icon_data = guess_icon_from_name(icon_name)
				if self.icon_data:
					break
			self.icon_names_failed = self.icon_data is None
		return	self.icon_data

	def __str__(self):
		if self.command and len(self.command)>0:
			return	"%s(%s: %s)" % (self.type, self.name, self.command)
		else:
			return	"%s(%s)" % (self.type, self.name)

	def __hash__(self):
		return self.uuid.__hash__()

	def __cmp__ (self, other):
		if type(other)!=type(self):
			return -1
		c = cmp(self.name, other.name)
		if c==0:
			c =	cmp(self.uuid, other.uuid)
		if c==0:
			c = ModifiedCallbackObject.__cmp__(self, other)
		return c
