import threading
import bluetooth
import ast


class BtRemote:

    __remote_event = None   # event generated by the the remote (this class)
    __msg = None            # message exchange object
    __server_socket = None  # bluetooth server socket
    __client_socket = None  # bluetooth client socket
    __termination = None
    __SOCKET_TIMEOUT = 5      # socket timeout in seconds

    def __init__(self, remote_event, message):
        super().__init__()
        self.__remote_event = remote_event
        self.__msg = message
        self.__server_socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
        self.__server_socket.settimeout(self.__SOCKET_TIMEOUT)
        self.__termination = threading.Event()

    def run(self):
        threading.Thread(target=self.__run).start()

    def __run(self):
        self.__server_socket.bind(("", bluetooth.PORT_ANY))
        self.__server_socket.listen(1)
        port = self.__server_socket.getsockname()[1]
        uuid = "00001101-0000-1000-8000-00805f9b34fb"           # android app looks for this

        bluetooth.advertise_service(self.__server_socket, "MPRadio",
                                    service_id=uuid,
                                    service_classes=[uuid, bluetooth.SERIAL_PORT_CLASS],
                                    profiles=[bluetooth.SERIAL_PORT_PROFILE],)

        self.__accept_connection()

        while not self.__termination.is_set():
            try:
                cmd = self.__client_socket.recv(1024)
            except bluetooth.btcommon.BluetoothError as e:       # if a client disconnects, listen for new ones
                if "timed out" in str(e).lower():
                    continue
                else:
                    self.__accept_connection()
                    continue

            if len(cmd) > 0:
                # cmd = cmd.decode().strip().split()  # .lower()
                cmd = ast.literal_eval(cmd.decode())
                self.__msg["command"] = cmd["command"].split()
                self.__msg["data"] = cmd["data"]
                self.__msg["source"] = "bluetooth"
                print("bluetooth_remote received:", cmd)
                self.__remote_event.set()

        print("bluetooth remote stopped")

    def __accept_connection(self):
        self.__client_socket = None
        while self.__client_socket is None:
            try:
                self.__client_socket, address = self.__server_socket.accept()
            except bluetooth.BluetoothError as e:
                # print("ERROR while accept_connection:", str(e))
                if "timed out" in str(e).lower():
                    # self.__client_socket = None   # should be default
                    continue
                else:
                    # print("bluetooth socket closed")
                    return
        print("Acceppted one bluetooth connection!")
        self.__client_socket.settimeout(self.__SOCKET_TIMEOUT)

    def reply(self, message):
        try:
            self.__client_socket.sendall(bytes(message+"\0", 'UTF-8'))
        except bluetooth.btcommon.BluetoothError:
            pass

    def stop(self):
        print("stopping bluetooth remote...")
        self.__termination.set()
        if self.__client_socket is not None:
            self.__client_socket.close()
        if self.__server_socket is not None:
            self.__server_socket.close()
