# Path: communication/MqttConnection.py
# class MqttConnection:
#     MOVEMENT_CHANNEL = 'robot/movement'
#     STATUS_CHANNEL = 'robot/status'
# 
#     def __init__(self, host: str, port: str, user: str, password: str):
#         self.__host = host
#         self.__port = port
#         self.__user = user
#         self.__password = password
#         self.__callback = None
#         self.__client = None
# 
#     def connect(self):
#         self.__client = mqtt.Client()
# 
#         def on_connect(client, userdata, flags, rc):
#             self.__client.subscribe(self.MOVEMENT_CHANNEL)
# 
#         def on_message(client, userdata, msg):
#             if self.__callback is not None:
#                 self.__callback(msg.payload)
# 
#         self.__client.on_connect = on_connect
#         self.__client.on_message = on_message
#         self.__client.username_pw_set(self.__user, self.__password)
#         self.__client.connect_async(self.__host, self.__port, 60)
#         self.__client.loop_start()
# 
#     def listen(self, callback: Callable[[codecs.StreamReader], None]):
#         self.__callback = callback
# 
#     def send(self, channel: str, message: str):
#         self.__client.publish(channel, message, 2)
# 
# Path: communication/Serial.py
# class Serial:
#     def __init__(self, port: str, baud_rate: str):
#         self.__port = port
#         self.__baud_rate = baud_rate
#         self.__message_buffer = ''
#         self.__serial = None
#         self.__receive_message_callback = None
# 
#     def add_callback(self, receive_message_callback):
#         self.__receive_message_callback = receive_message_callback
# 
#     def connect(self):
#         self.__serial = serial.Serial(self.__port, self.__baud_rate,timeout=0.5, writeTimeout=0.5)
# 
#     def disconnect(self):
#         self.__serial.close()
# 
#     def send(self, value: str):
#         self.__serial.write(value)
# 
#     def loop(self):
#         if self.__receive_message_callback is None:
#             return
#         received_data = self.__serial.read()
#         if received_data.decode() is False or received_data.decode() == '':
#             return
#         self.__message_buffer += received_data.decode()
#         if not self.__has_received_full_message():
#             return
#         self.__receive_message_callback(self.__message_buffer)
#         self.__message_buffer = ''
# 
#     def __has_received_full_message(self):
#         return True if self.__message_buffer[-1] == RobotSerialCommandsConverter.MESSAGE_TERMINATOR else False
# 
# Path: navigation/RobotSerialCommandsConverter.py
# class RobotSerialCommandsConverter:
#     MAX_ANGLE = 180
#     MIN_ANGLE = 0
#     MOTOR_COMMAND = 'M:{0}:{1}'
#     LIGHT_COMMAND = 'L:{0}'
#     MESSAGE_TERMINATOR = ';'
#     POWER_LIMITS = {'forward': {'max': 50, 'min': 0}, 'backward': {'max': -50, 'min': 0}}
#     DIRECTION_LIMITS = {'right': 50, 'left': -50}
# 
#     def get_steer_command(self, angle: int, percent_power: int, forward: bool) -> str:
#         direction = self.__get_converted_direction(angle)
#         power = self.__get_converted_power(percent_power, forward)
#         return self.MOTOR_COMMAND.format(direction, power)
# 
#     def get_lights_command(self, state: bool) -> str:
#         literal_state = {True: '1', False: '0'}
#         return self.LIGHT_COMMAND.format(literal_state[state])
# 
#     def __get_converted_power(self, percent_power: int, forward: bool) -> str:
#         power_limits_key = {True: 'forward', False: 'backward'}[forward]
#         return str(MathUtils.remap(
#                 percent_power, 0, 100,
#                 self.POWER_LIMITS[power_limits_key]['min'], self.POWER_LIMITS[power_limits_key]['max']))
# 
#     def __get_converted_direction(self, angle: int) -> int:
#         return MathUtils.remap(angle, self.MIN_ANGLE, self.MAX_ANGLE,
#                                self.DIRECTION_LIMITS['left'], self.DIRECTION_LIMITS['right'])


import codecs
import logging
from communication.MqttConnection import MqttConnection
from communication.Serial import Serial
from navigation.RobotSerialCommandsConverter import RobotSerialCommandsConverter



class SerialMqttBridge:
    COMMUNICATION_TERMINATOR = ';'

    def __init__(self, mqtt_connection : MqttConnection, serial: Serial, logging: logging.Logger):
        self.__mqtt_connection = mqtt_connection
        self.__serial = serial
        self.__logging = logging

    def received_serial_message(self, message: str):
        self.__logging.debug("Received through serial:" + message)

# Path: communication/MqttConnection.py
# class MqttConnection:
#     MOVEMENT_CHANNEL = 'robot/movement'
#     STATUS_CHANNEL = 'robot/status'
# 
#     def __init__(self, host: str, port: str, user: str, password: str):
#         self.__host = host
#         self.__port = port
#         self.__user = user
#         self.__password = password
#         self.__callback = None
#         self.__client = None
# 
#     def connect(self):
#         self.__client = mqtt.Client()
# 
#         def on_connect(client, userdata, flags, rc):
#             self.__client.subscribe(self.MOVEMENT_CHANNEL)
# 
#         def on_message(client, userdata, msg):
#             if self.__callback is not None:
#                 self.__callback(msg.payload)
# 
#         self.__client.on_connect = on_connect
#         self.__client.on_message = on_message
#         self.__client.username_pw_set(self.__user, self.__password)
#         self.__client.connect_async(self.__host, self.__port, 60)
#         self.__client.loop_start()
# 
#     def listen(self, callback: Callable[[codecs.StreamReader], None]):
#         self.__callback = callback
# 
#     def send(self, channel: str, message: str):
#         self.__client.publish(channel, message, 2)
# 
# Path: communication/Serial.py
# class Serial:
#     def __init__(self, port: str, baud_rate: str):
#         self.__port = port
#         self.__baud_rate = baud_rate
#         self.__message_buffer = ''
#         self.__serial = None
#         self.__receive_message_callback = None
# 
#     def add_callback(self, receive_message_callback):
#         self.__receive_message_callback = receive_message_callback
# 
#     def connect(self):
#         self.__serial = serial.Serial(self.__port, self.__baud_rate,timeout=0.5, writeTimeout=0.5)
# 
#     def disconnect(self):
#         self.__serial.close()
# 
#     def send(self, value: str):
#         self.__serial.write(value)
# 
#     def loop(self):
#         if self.__receive_message_callback is None:
#             return
#         received_data = self.__serial.read()
#         if received_data.decode() is False or received_data.decode() == '':
#             return
#         self.__message_buffer += received_data.decode()
#         if not self.__has_received_full_message():
#             return
#         self.__receive_message_callback(self.__message_buffer)
#         self.__message_buffer = ''
# 
#     def __has_received_full_message(self):
#         return True if self.__message_buffer[-1] == RobotSerialCommandsConverter.MESSAGE_TERMINATOR else False
# 
# Path: navigation/RobotSerialCommandsConverter.py
# class RobotSerialCommandsConverter:
#     MAX_ANGLE = 180
#     MIN_ANGLE = 0
#     MOTOR_COMMAND = 'M:{0}:{1}'
#     LIGHT_COMMAND = 'L:{0}'
#     MESSAGE_TERMINATOR = ';'
#     POWER_LIMITS = {'forward': {'max': 50, 'min': 0}, 'backward': {'max': -50, 'min': 0}}
#     DIRECTION_LIMITS = {'right': 50, 'left': -50}
# 
#     def get_steer_command(self, angle: int, percent_power: int, forward: bool) -> str:
#         direction = self.__get_converted_direction(angle)
#         power = self.__get_converted_power(percent_power, forward)
#         return self.MOTOR_COMMAND.format(direction, power)
# 
#     def get_lights_command(self, state: bool) -> str:
#         literal_state = {True: '1', False: '0'}
#         return self.LIGHT_COMMAND.format(literal_state[state])
# 
#     def __get_converted_power(self, percent_power: int, forward: bool) -> str:
#         power_limits_key = {True: 'forward', False: 'backward'}[forward]
#         return str(MathUtils.remap(
#                 percent_power, 0, 100,
#                 self.POWER_LIMITS[power_limits_key]['min'], self.POWER_LIMITS[power_limits_key]['max']))
# 
#     def __get_converted_direction(self, angle: int) -> int:
#         return MathUtils.remap(angle, self.MIN_ANGLE, self.MAX_ANGLE,
#                                self.DIRECTION_LIMITS['left'], self.DIRECTION_LIMITS['right'])


# Path: communication/SerialMqttBridge.py
import codecs
import logging
from communication.MqttConnection import MqttConnection
from communication.Serial import Serial
from navigation.RobotSerialCommandsConverter import RobotSerialCommandsConverter




class SerialMqttBridge:
    COMMUNICATION_TERMINATOR = ';'

    def __init__(self, mqtt_connection : MqttConnection, serial: Serial, logging: logging.Logger):
        self.__mqtt_connection = mqtt_connection
        self.__serial = serial
        self.__logging = logging

    def received_serial_message(self, message: str):
        self.__logging.debug("Received through serial:" + message)

        self.__mqtt_connection.send(MqttConnection.STATUS_CHANNEL, message)