"""Handle MySensors messages."""
import logging

from openpeerpower.core import callback
from openpeerpower.helpers.dispatcher import async_dispatcher_send
from openpeerpower.util import decorator

from .const import CHILD_CALLBACK, MYSENSORS_GATEWAY_READY, NODE_CALLBACK
from .device import get_mysensors_devices
from .helpers import discover_mysensors_platform, validate_set_msg

_LOGGER = logging.getLogger(__name__)
HANDLERS = decorator.Registry()


@HANDLERS.register("set")
async def handle_set(opp, opp_config, msg):
    """Handle a mysensors set message."""
    validated = validate_set_msg(msg)
    _handle_child_update(opp, opp_config, validated)


@HANDLERS.register("internal")
async def handle_internal(opp, opp_config, msg):
    """Handle a mysensors internal message."""
    internal = msg.gateway.const.Internal(msg.sub_type)
    handler = HANDLERS.get(internal.name)
    if handler is None:
        return
    await handler(opp, opp_config, msg)


@HANDLERS.register("I_BATTERY_LEVEL")
async def handle_battery_level(opp, opp_config, msg):
    """Handle an internal battery level message."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_HEARTBEAT_RESPONSE")
async def handle_heartbeat(opp, opp_config, msg):
    """Handle an heartbeat."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_SKETCH_NAME")
async def handle_sketch_name(opp, opp_config, msg):
    """Handle an internal sketch name message."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_SKETCH_VERSION")
async def handle_sketch_version(opp, opp_config, msg):
    """Handle an internal sketch version message."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_GATEWAY_READY")
async def handle_gateway_ready(opp, opp_config, msg):
    """Handle an internal gateway ready message.

    Set asyncio future result if gateway is ready.
    """
    gateway_ready = opp.data.get(MYSENSORS_GATEWAY_READY.format(id(msg.gateway)))
    if gateway_ready is None or gateway_ready.cancelled():
        return
    gateway_ready.set_result(True)


@callback
def _handle_child_update(opp, opp_config, validated):
    """Handle a child update."""
    signals = []

    # Update all platforms for the device via dispatcher.
    # Add/update entity for validated children.
    for platform, dev_ids in validated.items():
        devices = get_mysensors_devices(opp, platform)
        new_dev_ids = []
        for dev_id in dev_ids:
            if dev_id in devices:
                signals.append(CHILD_CALLBACK.format(*dev_id))
            else:
                new_dev_ids.append(dev_id)
        if new_dev_ids:
            discover_mysensors_platform(opp, opp_config, platform, new_dev_ids)
    for signal in set(signals):
        # Only one signal per device is needed.
        # A device can have multiple platforms, ie multiple schemas.
        async_dispatcher_send(opp, signal)


@callback
def _handle_node_update(opp, msg):
    """Handle a node update."""
    signal = NODE_CALLBACK.format(id(msg.gateway), msg.node_id)
    async_dispatcher_send(opp, signal)

"""Handle MySensors messages."""
import logging

from openpeerpower.core import callback
from openpeerpower.helpers.dispatcher import async_dispatcher_send
from openpeerpower.util import decorator

from .const import CHILD_CALLBACK, MYSENSORS_GATEWAY_READY, NODE_CALLBACK
from .device import get_mysensors_devices
from .helpers import discover_mysensors_platform, validate_set_msg

_LOGGER = logging.getLogger(__name__)
HANDLERS = decorator.Registry()


@HANDLERS.register("set")
async def handle_set(opp, opp_config, msg):
    """Handle a mysensors set message."""
    validated = validate_set_msg(msg)
    _handle_child_update(opp, opp_config, validated)


@HANDLERS.register("internal")
async def handle_internal(opp, opp_config, msg):
    """Handle a mysensors internal message."""
    internal = msg.gateway.const.Internal(msg.sub_type)
    handler = HANDLERS.get(internal.name)
    if handler is None:
        return
    await handler(opp, opp_config, msg)


@HANDLERS.register("I_BATTERY_LEVEL")
async def handle_battery_level(opp, opp_config, msg):
    """Handle an internal battery level message."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_HEARTBEAT_RESPONSE")
async def handle_heartbeat(opp, opp_config, msg):
    """Handle an heartbeat."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_SKETCH_NAME")
async def handle_sketch_name(opp, opp_config, msg):
    """Handle an internal sketch name message."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_SKETCH_VERSION")
async def handle_sketch_version(opp, opp_config, msg):
    """Handle an internal sketch version message."""
    _handle_node_update(opp, msg)


@HANDLERS.register("I_GATEWAY_READY")
async def handle_gateway_ready(opp, opp_config, msg):
    """Handle an internal gateway ready message.

    Set asyncio future result if gateway is ready.
    """
    gateway_ready = opp.data.get(MYSENSORS_GATEWAY_READY.format(id(msg.gateway)))
    if gateway_ready is None or gateway_ready.cancelled():
        return
    gateway_ready.set_result(True)


@callback
def _handle_child_update(opp, opp_config, validated):
    """Handle a child update."""
    signals = []

    # Update all platforms for the device via dispatcher.
    # Add/update entity for validated children.
    for platform, dev_ids in validated.items():
        devices = get_mysensors_devices(opp, platform)
        new_dev_ids = []
        for dev_id in dev_ids:
            if dev_id in devices:
                signals.append(CHILD_CALLBACK.format(*dev_id))
            else:
                new_dev_ids.append(dev_id)
        if new_dev_ids:
            discover_mysensors_platform(opp, opp_config, platform, new_dev_ids)
    for signal in set(signals):
        # Only one signal per device is needed.
        # A device can have multiple platforms, ie multiple schemas.
        async_dispatcher_send(opp, signal)


@callback
def _handle_node_update(opp, msg):
    """Handle a node update."""
    signal = NODE_CALLBACK.format(id(msg.gateway), msg.node_id)
    async_dispatcher_send(opp, signal)

Handle MySensors messages. Handle a mysensors set message. Handle a mysensors internal message. Handle an internal battery level message. Handle an heartbeat. Handle an internal sketch name message. Handle an internal sketch version message. Handle an internal gateway ready message.      Set asyncio future result if gateway is ready. Handle a child update. # Update all platforms for the device via dispatcher. # Add/update entity for validated children. # Only one signal per device is needed. # A device can have multiple platforms, ie multiple schemas. Handle a node update.