import socket
import time


class RPUDP():
    RELEASE, BTN_L, BTN_R, BTN_M, BTN_X1, BTN_X2 = 0x00, 0x01, 0x02, 0x04, 0x08, 0x10

    def __init__(self, ip, port=7777):
        self.ip = ip
        self.port = port
        self.addr = None
        self.sock = None

    @staticmethod
    def normalizePort(port):
        try:
            port = int(str(port).strip())
        except (TypeError, ValueError):
            return False
        if not (1 <= port <= 65535):
            return False
        return port

    def isConnected(self):
        return self.sock is not None

    def open(self):
        self.close()
        self.port = self.normalizePort(self.port)

        if not self.ip:
            print('Invalid IP. Example: 192.168.68.77')
            return False

        if not self.port:
            print('Port must be an integer. Example: 7777')
            return False

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        self.addr = (self.ip, int(self.port))
        return True

    def close(self):
        if self.sock:
            self.sock.close()
            self.sock = None
            self.addr = None

    def sendPacket(self, data):
        if not self.sock:
            return False
        return self.sock.sendto(data, self.addr) == len(data)

    def move(self, x, y):
        if not self.isConnected(): return
        if (x == 0 and y == 0): return
        x = max(-32767, min(32767, x))
        y = max(-32767, min(32767, y))

        buf = bytearray(5)
        buf[0] = 0x01
        buf[1] = x & 0xFF
        buf[2] = (x >> 8) & 0xFF
        buf[3] = y & 0xFF
        buf[4] = (y >> 8) & 0xFF

        self.sendPacket(buf)

    def setButtons(self, mask):
        if not self.isConnected(): return
        buf = bytearray(2)
        buf[0] = 0x02
        buf[1] = mask & 0x1F
        self.sendPacket(buf)

    def click(self, mask, down_ms=30):
        self.setButtons(mask)
        time.sleep(down_ms / 1000)
        self.setButtons(0x00)