from messagebus import (
    DataType,
    DefaultToken,
    Message,
)


class MessageDecoder(object):
    @staticmethod
    def parse_message(data):
        parts = data.split(b"\0")
        if len(parts) < 2:
            return None

        try:
            token = int(parts[0])
            data_type = int(parts[1])
        except ValueError:
            return None

        timeout = int(parts[2])
        header_qty = int(parts[3])
        headers = MessageDecoder.parse_headers(parts, 3)

        data = b"\0".join(parts[4 + 2 * header_qty:])

        return Message(token, data_type, data, timeout, headers)

    @staticmethod
    def format_message(message):
        # type: (Message) -> bytes
        data = b"\0".join([str(message.token).encode("utf-8"), str(message.data_type).encode("utf-8")])
        data += b"\0" + str(message.timeout).encode("utf-8") + b"\0"
        data += MessageDecoder.convert_dict_to_bytes(message.headers)
        data += b"\0"
        if message.data is not None:
            data += message.data

        return data

    @staticmethod
    def get_message_from_event(event):
        type_data = event.event_type.encode("utf-8") if event.event_type is not None else b""
        event_data = b"" if event.data is None else event.data
        data = event.subject.encode("utf-8") + b" " + type_data + b"\0" b"0" + b"\0" + event_data
        timeout = event.timeout
        if timeout == -1 or timeout > 30000:
            timeout = 30000
        return Message(DefaultToken.TK_EVT_EVENT, DataType.param, data, timeout, event.headers)

    @staticmethod
    def convert_dict_to_bytes(d):
        if d is not None:
            ret = str(len(d)).encode("utf-8") + b"\0"
            for key in d.keys():
                ret += key.encode("utf-8") + b"\0" + d[key].encode("utf-8") + b"\0"
            ret = ret[:-1]
            return ret
        return b""

    @staticmethod
    def parse_headers(parts, start_index):
        header_qty = int(parts[start_index])
        headers = {}
        for i in range(header_qty):
            headers[parts[start_index + 1 + 2 * i].decode("utf-8")] = parts[start_index + 2 + 2 * i].decode("utf-8")
        return headers
