#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
"""
Virtual Device(s)

Targets:
  * MQTT-Interface to control joined devices as one virtual device
  * Primary signal routing
  * No functionality should be implemented here
"""

from base import videv_base
from function.rooms import room, room_collection
import time

try:
    from config import APP_NAME as ROOT_LOGGER_NAME
except ImportError:
    ROOT_LOGGER_NAME = 'root'


class videv_pure_switch(videv_base):
    KEY_STATE = 'state'

    def __init__(self, mqtt_client, topic):
        super().__init__(mqtt_client, topic)
        self[self.KEY_STATE] = False
        #
        self.mqtt_client.add_callback(self.topic + '/state/set', self.__state__)

    def __state__(self, mqtt_client, userdata, message):
        self.set(self.KEY_STATE, message.payload == b'true')
        self.__tx__(self.KEY_STATE, message.payload == b'true')


class videv_switching(videv_base):
    KEY_STATE = 'state'

    def __init__(self, mqtt_client, topic, sw_device, sw_key):
        super().__init__(mqtt_client, topic)
        self.add_routing(self.KEY_STATE, sw_device, sw_key)


class videv_switching_timer(videv_base):
    KEY_STATE = 'state'
    KEY_TIMER = 'timer'

    def __init__(self, mqtt_client, topic, sw_device, sw_key, tm_device, tm_key):
        super().__init__(mqtt_client, topic)
        self.add_routing(self.KEY_STATE, sw_device, sw_key)
        self.add_display(self.KEY_TIMER, tm_device, tm_key)


class videv_switching_motion(videv_base):
    KEY_STATE = 'state'
    #
    KEY_TIMER = 'timer'
    KEY_MOTION_SENSOR = 'motion_%d'

    def __init__(self, mqtt_client, topic, sw_device, sw_key, motion_function):
        self.motion_sensors = motion_function.motion_sensors
        #
        super().__init__(mqtt_client, topic)
        self.add_routing(self.KEY_STATE, sw_device, sw_key)
        self.add_display(self.KEY_TIMER, motion_function, motion_function.KEY_TIMER)
        # motion sensor state
        for index, motion_sensor in enumerate(self.motion_sensors):
            self.add_display(self.KEY_MOTION_SENSOR % index, motion_sensor, motion_sensor.KEY_OCCUPANCY)


class videv_switch_brightness(videv_base):
    KEY_STATE = 'state'
    KEY_BRIGHTNESS = 'brightness'

    def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key):
        super().__init__(mqtt_client, topic)
        self.add_routing(self.KEY_STATE, sw_device, sw_key)
        self.add_routing(self.KEY_BRIGHTNESS, br_device, br_key)


class videv_switch_brightness_color_temp(videv_base):
    KEY_STATE = 'state'
    KEY_BRIGHTNESS = 'brightness'
    KEY_COLOR_TEMP = 'color_temp'

    def __init__(self, mqtt_client, topic, sw_device, sw_key, br_device, br_key, ct_device, ct_key):
        super().__init__(mqtt_client, topic)
        self.add_routing(self.KEY_STATE, sw_device, sw_key)
        self.add_routing(self.KEY_BRIGHTNESS, br_device, br_key)
        self.add_routing(self.KEY_COLOR_TEMP, ct_device, ct_key)


class videv_heating(videv_base):
    KEY_USER_TEMPERATURE_SETPOINT = 'user_temperature_setpoint'
    KEY_VALVE_TEMPERATURE_SETPOINT = 'valve_temperature_setpoint'
    KEY_AWAY_MODE = 'away_mode'
    KEY_SUMMER_MODE = 'summer_mode'
    KEY_START_BOOST = 'start_boost'
    KEY_SET_DEFAULT_TEMPERATURE = 'set_default_temperature'
    KEY_BOOST_TIMER = 'boost_timer'
    #
    KEY_TEMPERATURE = 'temperature'

    def __init__(self, mqtt_client, topic, heating_function):
        super().__init__(mqtt_client, topic)
        #
        self.add_routing(self.KEY_USER_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_USER_TEMPERATURE_SETPOINT)
        self.add_routing(self.KEY_AWAY_MODE, heating_function, heating_function.KEY_AWAY_MODE)
        self.add_routing(self.KEY_SUMMER_MODE, heating_function, heating_function.KEY_SUMMER_MODE)
        #
        self.add_control(self.KEY_START_BOOST, heating_function, heating_function.KEY_START_BOOST, False)
        self.add_control(self.KEY_SET_DEFAULT_TEMPERATURE, heating_function, heating_function.KEY_SET_DEFAULT_TEMPERATURE, False)
        #
        self.add_display(self.KEY_VALVE_TEMPERATURE_SETPOINT, heating_function, heating_function.KEY_TEMPERATURE_SETPOINT)
        self.add_display(self.KEY_BOOST_TIMER, heating_function, heating_function.KEY_BOOST_TIMER)
        self.add_display(self.KEY_TEMPERATURE, heating_function, heating_function.KEY_TEMPERATURE_CURRENT, False)


class videv_multistate(videv_base):
    KEY_STATE = 'state_%d'

    def __init__(self, mqtt_client, topic, key_for_device, device, num_states, default_values=None):
        super().__init__(mqtt_client, topic)
        self.num_states = num_states
        # send default values
        for i in range(0, num_states):
            self.__tx__(self.KEY_STATE % i, False)
        #
        device.add_callback(key_for_device, None, self.__index_rx__, True)

    def __index_rx__(self, device, key, data):
        for i in range(0, self.num_states):
            self.__tx__(self.KEY_STATE % i, i == data)


class videv_audio_player(videv_base):
    KEY_ACTIVE_PLAYER = 'player_%d'
    KEY_TITLE = 'title'
    NO_TITLE = '---'

    def __init__(self, mqtt_client, topic, *args):
        super().__init__(mqtt_client, topic)
        for i, device in enumerate(args):
            self.add_display(self.KEY_ACTIVE_PLAYER % i, device, device.KEY_STATE)
        #
        for audio_device in args:
            audio_device.add_callback(audio_device.KEY_TITLE, None, self.__title_rx__, True)

    def __title_rx__(self, device, key, data):
        self.__tx__(self.KEY_TITLE, data or self.NO_TITLE)


class all_off(videv_base):
    ALLOWED_CLASSES = (room, room_collection, )

    def __init__(self, mqtt_client, topic, room_collection):
        super().__init__(mqtt_client, topic)
        self.__room_collection__ = room_collection
        # init __inst_dict__
        self.__inst_dict__ = {}
        self.__add_instances__("all", self.__room_collection__)
        # register mqtt callbacks for all my keys
        for key in self.__inst_dict__:
            mqtt_client.add_callback(topic + "/" + key, self.all_off)

    def __check_inst_capabilities__(self, name, inst):
        # fits to specified classes
        if isinstance(inst, self.ALLOWED_CLASSES):
            try:
                # all_off method is callable
                return callable(inst.all_off)
            except AttributeError:
                # all_off method does not exist
                return False
        return False

    def __add_instances__(self, name, inst, level=0):
        if self.__check_inst_capabilities__(name, inst):
            # add given instance to my __inst_dict__
            self.__inst_dict__[name] = inst
            # iterate over all attribute names of instance
            for sub_name in dir(inst):
                # attribute name is not private
                if not sub_name.startswith("__"):
                    sub = getattr(inst, sub_name)
                    # recurse with this object
                    if level == 0:
                        self.__add_instances__(sub_name, sub, level=level+1)
                    else:
                        self.__add_instances__(name + "/" + sub_name, sub, level=level+1)

    def all_off(self, client, userdata, message):
        key = message.topic[len(self.topic) + 1:]
        self.__inst_dict__[key].all_off()