import time
import socket
import threading

login_lines_raw = [
    "NICK bridge",
    "USER bridge bridge * !",
    "JOIN #io23-bridge"
]

login_lines = map( lambda x: (x + "\n").encode("utf-8"), login_lines_raw )

recv_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

send_buffer = []
reconnecting = False

LINE_END = "\r\n".encode("utf-8")

recv_s.bind( ("127.0.0.1", 5001) )

def reconnect():
    global s, reconnecting
    reconnecting = True
    while True:
        try:
            s.close()
        except:
            pass
        
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect( ("10.1.1.1", 6667) )
    
            for i in login_lines:
                s.send(i)
                time.sleep(0.5)
            
            reconnecting = False
            break
        except Exception as e:
            print(f"[reconnect:main] ERROR: got exception {e}")
            t = time.time()
            open("error.log", "a", encoding = "utf-8").write(f"[{t}] recv_thread:main ERROR: got exception {e}\n")

            time.sleep(2)

def recv_thread():
    global s, send_buffer, reconnecting
    databuffer = bytes()
    while True:
        try:
            new_data = s.recv(1024)
            print(f"[DEBUG] new_data: {new_data}")
            if len(new_data) == 0:
                if not reconnecting:
                    reconnect() # bin the old socket and get a new one instead
                continue

            databuffer += new_data

            if LINE_END in databuffer:
                commands = map( lambda x: x.decode("UTF-8"), databuffer.split(LINE_END)[:-1])

                for command in commands:
                    if len(command) > 0:
                        if command.split(" ")[0] == "PING":
                            print("[DEBUG] recv_thread:command:ping: Responding with {}".format(command.split(" ")[1]).encode("UTF-8"))
                            send_buffer.append(("PONG {}\n".format( command.split(" ")[1]).encode("UTF-8") ))
                        else:
                            pass

                databuffer = databuffer.split(LINE_END)[-1]
        except Exception as e:
            print(f"[recv_thread:main] ERROR: got exception {e}")
            t = time.time()
            open("error.log", "a", encoding = "utf-8").write(f"[{t}] recv_thread:main ERROR: got exception {e}\n")
            try:
                if not reconnecting:
                    reconnect()
            except Exception as e:
                print(f"[recv_thread:except:reconnect] ERROR: got exception {e}")
                t = time.time()
                open("error.log", "a", encoding = "utf-8").write(f"[{t}] recv_thread:except:reconnect ERROR: got exception {e}\n")

def send_thread():
    global s, send_buffer, reconnecting
    while True:
        if len(send_buffer) > 0:
            try:
                print(f"[DEBUG] send_thread: sending {send_buffer[0]}")
                s.send(send_buffer[0])
                del send_buffer[0]
            except Exception as e:
                print(f"[send_thread:main] ERROR: got exception {e}")
                t = time.time()
                open("error.log", "a", encoding = "utf-8").write(f"[{t}] send_thread:main ERROR: got exception {e}\n")

                if not reconnecting:
                    reconnect()

            time.sleep(0.2)
        else:
            time.sleep(3)

def msg_thread():
    global recv_s, send_buffer
    while True:
        d = recv_s.recvfrom(16384)
        print(f"[DEBUG] msg_thread:d: {d}")
        send_buffer.append(d[0])

st = threading.Thread(target = send_thread, args = [])
rt = threading.Thread(target = recv_thread, args = [])
mt = threading.Thread(target = msg_thread, args = [])

reconnect()

st.start()
rt.start()
mt.start()