# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import collections
import dbus.service

from autotest_lib.client.cros.tendo import peerd_dbus_helper
from autotest_lib.client.cros.tendo.n_faced_peerd import dbus_property_exposer

IpInfo = collections.namedtuple('IpInfo', ['addr', 'port'])

class Service(dbus_property_exposer.DBusPropertyExposer):
    """Represents local and remote services."""


    def __init__(self, bus, path, peer_id, service_id, service_info, ip_info,
                 object_manager):
        """Construct a org.chromium.peerd.Service DBus object.

        @param bus: dbus.Bus object to export this object on.
        @param path: string object path to export this object at.
        @param service_id: string peerd service ID.
        @param service_info: dictionary of string,string items comprising
                the metadata for the service.
        @param ip_info: an instance of IpInfo defined above.
        @param object_manager: an instance of ObjectManager.

        """
        super(Service, self).__init__(
                bus, path, peerd_dbus_helper.DBUS_INTERFACE_SERVICE)
        self.peer_id = peer_id
        self.service_id = service_id
        self.service_info = service_info
        self.ip_info = ip_info
        # Register properties with the property exposer.
        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_PEER_ID,
                               self._get_peer_id)
        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_ID,
                               self._get_service_id)
        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_INFO,
                               self._get_service_info)
        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_IPS,
                               self._get_ip_info)
        # Claim the service interface.
        self._object_manager = object_manager
        self._path = path
        self._object_manager.claim_interface(
                path, peerd_dbus_helper.DBUS_INTERFACE_SERVICE,
                self.property_getter)


    def _get_peer_id(self):
        """Getter for SERVICE_PROPERTY_PEER_ID.

        @return dbus.String containing this service's peer_id.

        """
        return dbus.String(self.peer_id)


    def _get_service_id(self):
        """Getter for SERVICE_PROPERTY_ID.

        @return dbus.String containing this service's service_id.

        """
        return dbus.String(self.service_id)


    def _get_service_info(self):
        """Getter for SERVICE_PROPERTY_INFO.

        @return dbus.Dictionary containing this service's metadata.

        """
        return dbus.Dictionary(self.service_info, 'ss')


    def _get_ip_info(self):
        """Getter for SERVICE_PROPERTY_IPS.

        @return dbus.Array of dbus.Struct objects containing an array of bytes
                and a port number.  See DBus API documentation.

        """
        dbus_port = dbus.UInt16(self.ip_info.port)
        dbus_ip = dbus.Array([dbus.Byte(int(octet))
                              for octet in self.ip_info.addr.split('.')])
        ip_info = dbus.Struct((dbus_ip, dbus_port), signature='ayq')
        return dbus.Array([ip_info], signature='(ayq)')


    def update(self, service_info, ip_info):
        """Update service metadata and trigger DBus signals.

        @param service_info: see constructor.
        @param ip_info: see constructor.

        """
        if service_info != self.service_info:
            self.service_info = service_info
            self.on_property_changed(peerd_dbus_helper.SERVICE_PROPERTY_INFO)
        if ip_info != self.ip_info:
            self.ip_info = ip_info
            self.on_property_changed(peerd_dbus_helper.SERVICE_PROPERTY_IPS)


    def close(self):
        """Release interfaces claimed by this object."""
        self._object_manager.release_interface(
                self._path, peerd_dbus_helper.DBUS_INTERFACE_SERVICE)