#     Copyright 2020. ThingsBoard
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.

from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.constants import Endian

from thingsboard_gateway.connectors.modbus.modbus_converter import ModbusConverter, log


class BytesModbusDownlinkConverter(ModbusConverter):

    def __init__(self, config):
        self.__config = config

    def convert(self, config, data):
        byte_order_str = config.get("byteOrder", "LITTLE")
        byte_order = Endian.Big if byte_order_str.upper() == "BIG" else Endian.Little
        builder = BinaryPayloadBuilder(byteorder=byte_order)
        builder_functions = {"string": builder.add_string,
                             "bits": builder.add_bits,
                             "8int": builder.add_8bit_int,
                             "16int": builder.add_16bit_int,
                             "32int": builder.add_32bit_int,
                             "64int": builder.add_64bit_int,
                             "8uint": builder.add_8bit_uint,
                             "16uint": builder.add_16bit_uint,
                             "32uint": builder.add_32bit_uint,
                             "64uint": builder.add_64bit_uint,
                             "16float": builder.add_16bit_float,
                             "32float": builder.add_32bit_float,
                             "64float": builder.add_64bit_float}

        value = config["value"]
        lower_type = config["tag"].lower()
        variable_size = config.get("registerCount", 1) * 8
        if lower_type in ["integer", "dword", "dword/integer", "word"]:
            lower_type = str(variable_size) + "int"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](value)
        elif lower_type in ["uint", "unsigned", "unsigned integer", "unsigned int"]:
            lower_type = str(variable_size) + "uint"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](value)
        elif lower_type in ["float", "double"]:
            lower_type = str(variable_size) + "float"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](value)
        elif lower_type in ["coil", "bits"]:
            assert builder_functions.get("bits") is not None
            builder_functions["bits"](value)
        elif lower_type in ["string"]:
            assert builder_functions.get("string") is not None
            builder_functions[lower_type](value)
        elif lower_type in ["bit"]:
            bits = [0 for _ in range(8)]
            bits[config["bit"]-1] = int(value)
            log.debug(bits)
            builder.add_bits(bits)
            return builder.to_string()

        builder_converting_functions = {5: builder.to_coils,
                                        15: builder.to_coils,
                                        6: builder.to_registers,
                                        16: builder.to_registers}

        function_code = config["functionCode"]

        if function_code in builder_converting_functions:
            return builder_converting_functions[function_code]()
        log.warning("Unsupported function code, for the device %s in the Modbus Downlink converter", self.__config["deviceName"])
        return None
