import socket
import threading
import config as cfg

LenFunc = cfg.LenFunc

class SocketHTTP(threading.Thread):

    def __init__(self, HOST,PORT, parent):
        try: 
            self.parent = parent
            super(SocketHTTP,self).__init__(None,None,None,None)
            self.port = PORT
            self.Host = HOST
            self.history = []
            self.socket = socket.socket()
            self.socket.connect((HOST, PORT))
            t = threading.Thread(target=self.receive)
            t.start()
            print("socket is created and Listener is created\n",(HOST, PORT))
        except:
            print("\33[41m\33[41mAn exception occurred  SocketHTTP\33[0m" )


    def send(self,M):
        try: 
            self.socket.sendall(M)
            self.history.append(("send",M))
            print("\033[91m\n\t Send -> ",M,"\n\033[0m")
        except:
            print("\33[41m\33[41mAn exception occurred  SocketHTTP send\33[0m" )

    def receive(self):
        try: 
            while True: 
                data = self.socket.recv(65565)
                # print("data",data)
                if bytes.hex(data) == "":
                    continue
                self.parent.recv(bytes.hex(data))
        except NameError:
            print("\33[41m\33[41mAn exception occurred  SocketHTTP receiv e    NameError\33[0m",NameError )

class SocketClient(threading.Thread):

    def __init__(self, HOST,PORT, parser,id):
        try: 
            self.parser = parser
            super(SocketClient,self).__init__(None,None,None,None)
            self.port = PORT
            self.Host = HOST
            self.history = []
            self.id = id
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((HOST, PORT))
            t = threading.Thread(target=self.receive)
            t.start()
            print("socket is created and Listener is created\n")
        except:
            print("\33[41m\33[41mAn exception occurred  SocketClient\33[0m" )


    def send(self,M):
        try: 
            Message=bytes(M,'utf-8')
            self.socket.sendall(Message)
            self.history.append(("send",Message))
            print("\033[91m\n\t Send -> ",M,"\n\033[0m")
        except:
            print("\33[41m\33[41mAn exception occurred  socket Client send\33[0m" )

    def receive(self):
        try: 
            while True: 
                len = self.socket.recv(cfg.LenFunc)
                if not len:
                    break
                data = self.socket.recv(int(len.decode("utf-8")))
                data = self.parser.toJSON(data.decode("utf-8"))
                print("\033[94m\n\t receive -> ",data,"\n\033[0m")
                self.parser.parser(data,None,self)
        except:
            print("\33[41m\33[41mAn exception occurred  socket Client receive\33[0m" )




class SocketServer():

    def __init__(self, socketPort, parser,id):
        try:  
            self.parser = parser
            self.history = []
            self.connected = []
            self.socketPort = socketPort 
            self.id = id
            t = threading.Thread(target=self.connection)
            t.start()
            print("socket is created and Listener is created",socketPort)
        except:
            print("\33[41m\33[41mAn exception occurred  SocketServer\33[0m" )

    def connection(self):
        try: 
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.bind(("localhost", self.socketPort))
                s.listen()
                self.socket = s
                while True:
                    conn, addr = self.socket.accept()
                    print("user connected to ",conn, "-> ",addr)
                    u = Connection(conn, addr,self.socketPort+1,self.parser)# TODO socketprot dynamic
                    self.connected.append(u)
                    print(self.connected)
        except Exception as exception:
            print("\33[41m\33[41mAn exception occurred  SocketServer connection ",exception,"\33[0m" )

class Connection():
    def __init__(self,connection,address,oracleSocketPort, parser): 
        try:
            self.parser = parser
            self.socket = connection
            self.addr = address
            self.history = []
            self.type = None
            # self.id = os.urandom(32)
            self.oracleSocketPort = oracleSocketPort


            t = threading.Thread(target=self.receive)
            t.start()
            # self.send("Connection")
        except:
            print("\33[41m\33[41mAn exception occurred  Connection connection\33[0m" )
        
    def send(self,M):
        try:
            Message=bytes(M,'utf-8')
            self.socket.sendall(Message)
            self.history.append(("send",Message))
            print("\033[91m\n\t Send -> ",M,"\n\033[0m")
        except:
            print("\33[41m\33[41mAn exception occurred  Connection sebd\33[0m" )

    def receive(self):
        try:
            while True: 
                len = self.socket.recv(cfg.LenFunc)
                if not len:
                    break
                print(int(len.decode("utf-8")))
                data = self.socket.recv(int(len.decode("utf-8")))
                data = self.parser.toJSON(data.decode("utf-8"))
                print("\033[94m\n\t receive -> ",data,"\n\033[0m")
                self.parser.parser(data,None,self)
        except  :
            print("\33[41m\33[41mAn exception occurred  Connection receive\33[0m" )
