"""
    Status
    ======

    .. Copyright:
        Copyright 2019 Wirepas Ltd under Apache License, Version 2.0.
        See file LICENSE for full license details.
"""

import enum
from .proto import GenericMessage, ON, OFF

from .event import Event

# Indicates that protobuf message definition in version 1 can be parsed by this implementation
# This API should never be changes in future (purpose of protobuf)
PB_MESSAGE_DEFINITION_VERSION = 1

from .config_helper import (
    parse_config_rw,
    parse_config_ro,
    parse_config_otap,
    set_config_ro,
    set_config_rw,
    set_config_otap
)

class GatewayState(enum.Enum):
    """
    GatewayState

    Enum providing the possible
    states for the gateway

    ONLINE or OFFLINE

    """

    ONLINE = 0
    OFFLINE = 1


class StatusEvent(Event):
    """
    StatusEvent: Event generated by the gateway to set its status (ONLINE/OFFLINE)

    Attributes:
        gw_id (str): gateway unique identifier
        state (GatewayState): state of the gateway
        version (int): protobuf messsage definition version for the gateway. This implementation can only parse protobuf message definitions in version1
        event_id(int): event unique id (random value generated if None)
        sink_configs (list): list of dictionnary containing the sink configs
        gateway_model (string): gateway model
        gateway_version (string): gateway version
    """

    def __init__(
        self,
        gw_id,
        state,
        version=PB_MESSAGE_DEFINITION_VERSION,
        event_id=None,
        sink_configs=None,
        gateway_model=None,
        gateway_version=None,
        max_scratchpad_size=None,
        **kwargs
    ):
        super(StatusEvent, self).__init__(gw_id, event_id=event_id, **kwargs)
        self.state = state
        self.version = version
        self.sink_configs = sink_configs
        self.gateway_model = gateway_model
        self.gateway_version = gateway_version
        self.max_scratchpad_size = max_scratchpad_size

    @staticmethod
    def _get_related_message(generic_message):
        return generic_message.wirepas.status_event

    @classmethod
    def from_payload(cls, payload):
        """ Converts a protobuff message into a python object """

        event = cls._decode_and_get_related_message(payload)

        if event.state == ON:
            online = GatewayState.ONLINE
        else:
            online = GatewayState.OFFLINE

        gw_model = None
        if event.HasField("gw_model"):
            gw_model = event.gw_model

        gw_version = None
        if event.HasField("gw_version"):
            gw_version = event.gw_version

        max_scratchpad_size = None
        if event.HasField("max_scratchpad_size"):
            max_scratchpad_size = event.max_scratchpad_size

        if event.version != PB_MESSAGE_DEFINITION_VERSION:
            raise RuntimeError("Unsupported gateway message definition version {}. The only supported version is {}".format(event.version, str(PB_MESSAGE_DEFINITION_VERSION)))

        configs = None
        for conf in event.configs:
            config = {}

            config["sink_id"] = conf.sink_id

            parse_config_rw(conf, config)
            parse_config_ro(conf, config)
            parse_config_otap(conf, config)
            try:
                configs.append(config)
            except AttributeError:
                # First config
                configs = [config]

        d = Event._parse_event_header(event.header)
        return cls(d["gw_id"],
                   online,
                   event_id=d["event_id"],
                   sink_configs=configs,
                   time_ms_epoch=d["time_ms_epoch"],
                   gateway_model=gw_model,
                   gateway_version=gw_version,
                   max_scratchpad_size=max_scratchpad_size)

    @property
    def payload(self):
        """ Returns a proto serialization of itself """

        message = GenericMessage()
        # Fill the request header
        status = self._get_related_message(message)
        self._load_event_header(status)

        status.version = PB_MESSAGE_DEFINITION_VERSION
        if self.state == GatewayState.ONLINE:
            status.state = ON
        else:
            status.state = OFF

        if self.sink_configs is not None:
            for config in self.sink_configs:
                conf = status.configs.add()
                conf.sink_id = config["sink_id"]

                set_config_rw(conf, config)
                set_config_ro(conf, config)
                set_config_otap(conf, config)

        if self.gateway_model is not None:
            status.gw_model = self.gateway_model

        if self.gateway_version is not None:
            status.gw_version = self.gateway_version

        if self.max_scratchpad_size is not None:
            status.max_scratchpad_size = self.max_scratchpad_size

        return message.SerializeToString()
