#!/usr/bin/env python

# Contributors Listed Below - COPYRIGHT 2015
# [+] International Business Machines Corp.
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.

import sys
import dbus
import dbus.service
import dbus.mainloop.glib
import gobject
from OpenBMCMapper import Path, IntrospectionParser, PathTree
import OpenBMCMapper

class ObjectMapper(dbus.service.Object):
	def __init__(self, bus, path,
			name_match = OpenBMCMapper.org_dot_openbmc_match,
			intf_match = OpenBMCMapper.org_dot_openbmc_match):
		super(ObjectMapper, self).__init__(bus.dbus, path)
		self.cache = PathTree()
		self.bus = bus
		self.name_match = name_match
		self.intf_match = intf_match
		self.tag_match = OpenBMCMapper.ListMatch(['children', 'interface'])
		self.service = None

		gobject.idle_add(self.discover)
		self.bus.dbus.add_signal_receiver(self.bus_handler,
			dbus_interface = dbus.BUS_DAEMON_IFACE,
			signal_name = 'NameOwnerChanged')
		self.bus.dbus.add_signal_receiver(self.interfaces_added_handler,
			dbus_interface = dbus.BUS_DAEMON_IFACE + '.ObjectManager',
			signal_name = 'InterfaceesAdded',
			sender_keyword = 'sender')
		self.bus.dbus.add_signal_receiver(self.interfaces_removed_handler,
			dbus_interface = dbus.BUS_DAEMON_IFACE + '.ObjectManager',
			signal_name = 'InterfacesRemoved',
			sender_keyword = 'sender')

	def discovery_pending(self):
		return not bool(self.service)

	def interfaces_added_handler(self, path, iprops, **kw):
		if self.discovery_pending():
			return
		matches = [ x for x in iprops.iterkeys() if self.intf_match(x) ]
		d = self.cache.setdefault(path, {})
		d[path].setdefault(kw['sender'], []).extend(matches)
		self.cache[path] = d

	def interfaces_removed_handler(self, path, interfaces, **kw):
		if self.discovery_pending():
			return
		item = self.cache[path]
		name = kw['sender']
		for x in interfaces:
			item[name].remove(x)

		# remove the owner if there aren't any interfaces left
		if not item[name]:
			del item[name]

		# update if interfaces remain
		if item:
			self.cache[path] = item
		# mark for removal if no interfaces remain
		elif self.cache.get_children(item):
			self.cache.demote(item)
		# delete the entire path if everything is gone
		else:
			del self.cache[path]

	def process_new_owner(self, name):
		# unique name
		return self.discover([ IntrospectionParser(name,
			self.bus.dbus, self.tag_match, self.intf_match) ])

	def process_old_owner(self, name):
		for x,y in self.cache.dataitems():
			if name not in y:
				continue
			del y[name]
			if y:
				self.cache[x] = y
			elif self.cache.get_children(x):
				self.cache.demote(x)
			else:
				del self.cache[x]

	def bus_handler(self, service, old, new):
		if self.discovery_pending() or \
				not self.name_match(service):
			return

		if new:
			self.process_new_owner(new)
		if old:
			self.process_old_owner(old)

	def add_interfaces(self, path, owner, interfaces):
		d = self.cache.setdefault(path, { })
		d.setdefault(owner, []).extend(interfaces)
		self.cache[path] = d

	def add_items(self, owner, bus_items):
		for x,y in bus_items.iteritems():
			self.add_interfaces(x, owner, y['interfaces'])

	def discover(self, owners = None):
		if not owners:
			owners = [ IntrospectionParser(x, self.bus.dbus,
				self.tag_match, self.intf_match) \
						for x in self.bus.get_owner_names(self.name_match) ]
		for o in owners:
			self.add_items(o.name, o.introspect())

		if self.discovery_pending():
			print "ObjectMapper discovery complete..."
			self.service = dbus.service.BusName(
					OpenBMCMapper.MAPPER_NAME, self.bus.dbus)

	@dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 's', 'a{sas}')
	def GetObject(self, path):
		o = self.cache.get(path)
		if not o:
			raise MapperNotFoundException(path)
		return o

	@dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'as')
	def GetSubTreePaths(self, path, depth):
		try:
			return self.cache.iterkeys(path, depth)
		except KeyError:
			raise MapperNotFoundException(path)

	@dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
	def GetSubTree(self, path, depth):
		try:
			return { x:y for x, y in self.cache.dataitems(path, depth) }
		except KeyError:
			raise MapperNotFoundException(path)

class BusWrapper:
	def __init__(self, bus):
		self.dbus = bus

	def get_service_names(self, match):
		# these are well known names
		return [ x for x in self.dbus.list_names() \
				if match(x) and x != OpenBMCMapper.MAPPER_NAME ]

	def get_owner_names(self, match):
		# these are unique connection names
		return list( set( [ self.dbus.get_name_owner(x) \
				for x in self.get_service_names(match) ] ) )

if __name__ == '__main__':
	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
	bus = dbus.SystemBus()
	o = ObjectMapper(BusWrapper(bus), OpenBMCMapper.MAPPER_PATH)
	loop = gobject.MainLoop()

	loop.run()
