#!/usr/bin/env python3
try:
  from gi.repository import GObject
except ImportError:
  import gobject as GObject
import sys
import array
from bluez_components import *

from sense_hat import SenseHat
sense = SenseHat()

class SmartLightService(Service):
    SVC_UUID = 'FF10'

    def __init__(self, bus, index):
        Service.__init__(self, bus, index, self.SVC_UUID, True)
        self.add_characteristic(LightColourCharacteristic(bus, 0, self))

class LightColourCharacteristic(Characteristic):
    TEST_CHRC_UUID = 'FF11'

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

    def ReadValue(self, options):
        print('LightColourCharacteristic Read: ' + repr(self.value))
        return self.value

    def WriteValue(self, value, options):
        print('Demo Characteristic WriteValue called')
        if len(value)!=3:
            raise InvalidValueLengthException()
        sense.clear([int(value[0]),int(value[1]),int(value[2])])
        self.value = value
        print('Finished changing colour!')

class LightColourUserDescription(Descriptor):
    CUD_UUID = '2901'

    def __init__(self, bus, index, characteristic):
        self.writable = 'writable-auxiliaries' in characteristic.flags
        self.value = array.array('B', b'Demo Characteristic User Description')
        self.value = self.value.tolist()
        Descriptor.__init__(
                self, bus, index,
                self.CUD_UUID,
                ['read', 'write'],
                characteristic)

    def ReadValue(self, options):
        return self.value

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

class EnvironmentService(Service):

    ENV_UUID = '181a'

    def __init__(self, bus, index):
        Service.__init__(self, bus, index, self.ENV_UUID, True)
        self.add_characteristic(TemperatureCharacteristic(bus, 0, self))

class TemperatureCharacteristic(Characteristic):
    TEMP_UUID = '2a6e'

    def __init__(self, bus, index, service):
        Characteristic.__init__(
                self, bus, index,
                self.TEMP_UUID,
                ['read', 'notify'],
                service)
        self.notifying = False
        self.temp = temp_sint16(sense.get_temperature())
        GObject.timeout_add(1000, self.get_temp)

    def notify_temp(self):
        if not self.notifying:
            return
        self.PropertiesChanged(
                GATT_CHRC_IFACE,
                                { 'Value': self.temp }, [])
        print('temp notify: ' + repr(self.temp))
        return self.notifying

    def get_temp(self):
        self.temp = temp_sint16(sense.get_temperature())
        if not self.notifying:
            return True
        self.notify_temp()
        return True

    def ReadValue(self, options):
        self.get_temp()
        print('temp read: ' + repr(self.temp))
        return self.temp

    def StartNotify(self):
        if self.notifying:
            print('Already notifying, nothing to do')
            return
        self.notifying = True

    def StopNotify(self):
        if not self.notifying:
            print('Not notifying, nothing to do')
            return
        self.notifying = False

## Utility function to convert temp value to 16 bit int value, preserving 2 decimal places
def temp_sint16(value):
    answer = []
    value_int16=int(value * 100).to_bytes(2, byteorder='little', signed=True)
    for bytes in value_int16:
        answer.append(dbus.Byte(bytes))
    return answer

def main():
    global mainloop

    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    bus = dbus.SystemBus()

    adapter = find_adapter(bus)
    if not adapter:
        print('GattManager1 interface not found')
        return

    service_manager = dbus.Interface(
            bus.get_object(BLUEZ_SERVICE_NAME, adapter),
            GATT_MANAGER_IFACE)

    app = Application(bus)
    app.add_service(SmartLightService(bus, 0))
    app.add_service(EnvironmentService(bus, 1))

    mainloop = GObject.MainLoop()

    print('Registering GATT application...')

    service_manager.RegisterApplication(app.get_path(), {},
                                    reply_handler=register_app_cb,
                                    error_handler=register_app_error_cb)

    mainloop.run()

if __name__ == '__main__':
    main()
