# Copyright (C) 2006, Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import dbus

PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
ACTIVITY_DBUS_OBJECT_PATH = "/org/laptop/Presence/Activities/"
ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"


class ActivityDBusHelper(dbus.service.Object):
	def __init__(self, parent, bus_name, object_path):
		self._parent = parent
		self._bus_name = bus_name
		self._object_path = object_path
		dbus.service.Object.__init__(self, bus_name, self._object_path)

	@dbus.service.method(ACTIVITY_DBUS_INTERFACE,
						in_signature="s", out_signature="ao")
	def getServicesOfType(self, stype):
		ret = []
		for serv in self._parent.get_services_of_type(stype):
			ret.append(serv.object_path())
		return ret

	@dbus.service.method(ACTIVITY_DBUS_INTERFACE,
						in_signature="", out_signature="ao")
	def getServices(self):
		ret = []
		for serv in self._parent.get_services():
			ret.append(serv.object_path())
		return ret

	@dbus.service.method(ACTIVITY_DBUS_INTERFACE,
						in_signature="", out_signature="s")
	def getId(self):
		return self._parent.get_id()

	@dbus.service.method(ACTIVITY_DBUS_INTERFACE,
						in_signature="", out_signature="s")
	def getColor(self):
		return self._parent.get_color()

	@dbus.service.method(ACTIVITY_DBUS_INTERFACE,
						in_signature="", out_signature="ao")
	def getJoinedBuddies(self):
		ret = []
		for buddy in self._parent.get_joined_buddies():
			ret.append(buddy.object_path())
		return ret
	
	@dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
						signature="o")
	def ServiceAppeared(self, object_path):
		pass

	@dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
						signature="o")
	def ServiceDisappeared(self, object_path):
		pass

	@dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
						signature="o")
	def BuddyJoined(self, object_path):
		pass

	@dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
						signature="o")
	def BuddyLeft(self, object_path):
		pass


class Activity(object):
	def __init__(self, bus_name, object_id, initial_service):
		if not initial_service.get_activity_id():
			raise ValueError("Service must have a valid Activity ID")
		self._activity_id = initial_service.get_activity_id()

		self._buddies = []
		self._services = {}	# service type -> list of Services
		self._color = None
		self._valid = False

		self._object_id = object_id
		self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id
		self._dbus_helper = ActivityDBusHelper(self, bus_name, self._object_path)
		
		self.add_service(initial_service)

	def object_path(self):
		return dbus.ObjectPath(self._object_path)

	def is_valid(self):
		"""An activity is only valid when it's color is available."""
		return self._valid

	def get_id(self):
		return self._activity_id

	def get_color(self):
		return self._color

	def get_services(self):
		ret = []
		for serv_list in self._services.values():
			for service in serv_list:
				if service not in ret:
					ret.append(service)
		return ret

	def get_services_of_type(self, stype):
		if self._services.has_key(stype):
			return self._services[stype]
		return []

	def get_joined_buddies(self):
		buddies = []
		for serv_list in self._services.values():
			for serv in serv_list:
				owner = serv.get_owner()
				if owner and not owner in buddies and owner.is_valid():
					buddies.append(owner)
		return buddies

	def add_service(self, service):
		stype = service.get_type()
		if not self._services.has_key(stype):
			self._services[stype] = []

		if not self._color:
			color = service.get_one_property('color')
			if color:
				self._color = color
				self._valid = True

		# Send out the BuddyJoined signal if this is the first
		# service from the buddy that we've seen
		buddies = self.get_joined_buddies()
		serv_owner = service.get_owner()
		if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
			self._dbus_helper.BuddyJoined(serv_owner.object_path())
			serv_owner.add_activity(self)

		if not service in self._services[stype]:
			self._services[stype].append(service)
			self._dbus_helper.ServiceAppeared(service.object_path())

	def remove_service(self, service):
		stype = service.get_type()
		if not self._services.has_key(stype):
			return
		self._services[stype].remove(service)
		self._dbus_helper.ServiceDisappeared(service.object_path())
		if len(self._services[stype]) == 0:
			del self._services[stype]

		# Send out the BuddyLeft signal if this is the last
		# service from the buddy
		buddies = self.get_joined_buddies()
		serv_owner = service.get_owner()
		if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
			serv_owner.remove_activity(self)
			self._dbus_helper.BuddyLeft(serv_owner.object_path())