#
# Code based on:
#        https://github.com/Vudentz/BlueZ/blob/master/test/example-gatt-server
#        https://github.com/Vudentz/BlueZ/blob/master/test/example-advertisement
#

import array
import dbus

from service import Service, Characteristic, Descriptor
from exception import NotPermittedException


class ExampleService(Service):
    """Dummy test service that provides characteristics and descriptors that exercise various API functionality."""

    TEST_SVC_UUID = '12345678-1234-5678-1234-56789abcdef0'

    def __init__(self, bus, index):
        Service.__init__(self, bus, index, self.TEST_SVC_UUID, False)
        self.add_characteristic(ExampleCharacteristic(bus, 0, self))
        self.add_characteristic(ExampleEncryptCharacteristic(bus, 1, self))


class ExampleCharacteristic(Characteristic):
    """
    Dummy test characteristic.

    Allows writing arbitrary bytes to its value, and
    contains "extended properties", as well as a test descriptor.
    """

    TEST_CHRC_UUID = '12345678-1234-5678-1234-56789abcdef1'

    def __init__(self, bus, index, service):
        Characteristic.__init__(
                self, bus, index,
                self.TEST_CHRC_UUID,
                ['read', 'write', 'writable-auxiliaries'],
                service)
        self.value = []
        self.add_descriptor(ExampleDescriptor(bus, 0, self))
        self.add_descriptor(
                CharacteristicUserDescriptionDescriptor(bus, 1, self))

    def ReadValue(self):
        print('ExampleCharacteristic Read: ' + repr(self.value))
        return self.value

    def WriteValue(self, value):
        print('ExampleCharacteristic Write: ' + repr(value))
        self.value = value


class ExampleDescriptor(Descriptor):
    """Dummy test descriptor. Returns a static value."""

    TEST_DESC_UUID = '12345678-1234-5678-1234-56789abcdef2'

    def __init__(self, bus, index, characteristic):
        Descriptor.__init__(
                self, bus, index,
                self.TEST_DESC_UUID,
                ['read', 'write'],
                characteristic)

    def ReadValue(self):
        return [
                dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t')
        ]


class CharacteristicUserDescriptionDescriptor(Descriptor):
    """Writable CUD descriptor."""

    CUD_UUID = '2901'

    def __init__(self, bus, index, characteristic):
        self.writable = 'writable-auxiliaries' in characteristic.flags
        self.value = array.array('B', 'This is a characteristic for testing')
        self.value = self.value.tolist()
        Descriptor.__init__(
                self, bus, index,
                self.CUD_UUID,
                ['read', 'write'],
                characteristic)

    def ReadValue(self):
        return self.value

    def WriteValue(self, value):
        if not self.writable:
            raise NotPermittedException()
        self.value = value


class ExampleEncryptCharacteristic(Characteristic):
    """Dummy test characteristic requiring encryption."""

    TEST_CHRC_UUID = '12345678-1234-5678-1234-56789abcdef3'

    def __init__(self, bus, index, service):
        Characteristic.__init__(
                self, bus, index,
                self.TEST_CHRC_UUID,
                ['encrypt-read', 'encrypt-write'],
                service)
        self.value = []
        self.add_descriptor(ExampleEncryptDescriptor(bus, 2, self))
        self.add_descriptor(
                CharacteristicUserDescriptionDescriptor(bus, 3, self))

    def ReadValue(self):
        print('ExampleCharacteristic Read: ' + repr(self.value))
        return self.value

    def WriteValue(self, value):
        print('ExampleCharacteristic Write: ' + repr(value))
        self.value = value


class ExampleEncryptDescriptor(Descriptor):
    """Dummy test descriptor requiring encryption. Returns a static value."""

    TEST_DESC_UUID = '12345678-1234-5678-1234-56789abcdef4'

    def __init__(self, bus, index, characteristic):
        Descriptor.__init__(
                self, bus, index,
                self.TEST_DESC_UUID,
                ['encrypt-read', 'encrypt-write'],
                characteristic)

    def ReadValue(self):
        return [
                dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t')
        ]

