from __future__ import print_function

try:
    import queue
except ImportError:
    import Queue as queue
import socket
import sys
import threading
import time

from . import log


class ConnectionHandler:
    """Handles read and write operations to a given socket."""

    def __init__(self, socket, address):
        """Accept the socket used for reading and writing.

        socket -- the network socket
        """
        self.sock = socket
        self.address = address

    def __del__(self):
        """Make sure the connection is closed."""
        self.close()

    def isconnected(self):
        return 1

    def close(self):
        """Close the connection."""
        log.Log("Closing the socket", log.Logger.DEBUG)
        self.sock.close()

    def __recv_length(self):
        """Get the length of the proceeding message."""
        length = []
        while 1:
            c = self.sock.recv(1)
            if c == b'':
                self.close()
                raise EOFError('Socket Closed')
            if c == b'\x00':
                return int(b''.join(length))
            if c.isdigit():
                length.append(c)

    def __recv_null(self):
        """Receive a null byte."""
        while 1:
            c = self.sock.recv(1)
            if c == b'':
                self.close()
                raise EOFError('Socket Closed')
            if c == b'\x00':
                return

    def __recv_body(self, to_recv):
        body = []
        while to_recv > 0:
            buf = self.sock.recv(to_recv)
            if buf == b'':
                self.close()
                raise EOFError('Socket Closed')
            to_recv -= len(buf)
            body.append(buf.decode("utf-8"))
        return ''.join(body)

    def recv_msg(self):
        """Receive a message from the debugger.

        Returns a string, which is expected to be XML.
        """
        length = self.__recv_length()
        body = self.__recv_body(length)
        self.__recv_null()
        return body

    def send_msg(self, cmd):
        """Send a message to the debugger.

        cmd -- command to send
        """
        #self.sock.send(cmd + '\0')
        MSGLEN = len(cmd)
        totalsent = 0
        while totalsent < MSGLEN:
            sent = self.sock.send(bytes(cmd[totalsent:].encode()))
            if sent == 0:
                raise RuntimeError("socket connection broken")
            totalsent = totalsent + sent
        sent = self.sock.send(b'\x00')



class SocketCreator:

    def __init__(self, input_stream=None):
        """Create a new Connection.

        The connection is not established until open() is called.

        input_stream -- object for checking input stream and user interrupts (default None)
        """
        self.__sock = None
        self.input_stream = input_stream

    def start(self, host='', port=9000, timeout=30):
        """Listen for a connection from the debugger. Listening for the actual
        connection is handled by self.listen()

        host -- host name where debugger is running (default '')
        port -- port number which debugger is listening on (default 9000)
        timeout -- time in seconds to wait for a debugger connection before giving up (default 30)
        """
        print('Waiting for a connection (Ctrl-C to cancel, this message will '
              'self-destruct in ', timeout, ' seconds...)')
        serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            serv.setblocking(1)
            serv.bind((host, port))
            serv.listen(5)
            self.__sock = self.listen(serv, timeout)
        except socket.timeout:
            raise TimeoutError("Timeout waiting for connection")
        finally:
            serv.close()

    def listen(self, serv, timeout):
        """Non-blocking listener. Provides support for keyboard interrupts from
        the user. Although it's non-blocking, the user interface will still
        block until the timeout is reached.

        serv -- Socket server to listen to.
        timeout -- Seconds before timeout.
        """
        start = time.time()
        while True:
            if (time.time() - start) > timeout:
                raise socket.timeout
            try:
                """Check for user interrupts"""
                if self.input_stream is not None:
                    self.input_stream.probe()
                return serv.accept()
            except socket.error:
                pass

    def clear(self):
        self.__sock = None

    def socket(self):
        return self.__sock

    def has_socket(self):
        return self.__sock is not None


class BackgroundSocketCreator(threading.Thread):

    def __init__(self, host, port, message_q, output_q):
        self.__message_q = message_q
        self.__output_q = output_q
        self.__host = host
        self.__port = port
        threading.Thread.__init__(self)

    @staticmethod
    def log(message):
        log.Log(message, log.Logger.DEBUG)

    def run(self):
        self.log("Started")
        self.log("Listening on port %s" % self.__port)
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.setblocking(1)
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            s.bind((self.__host, self.__port))
            s.listen(5)
            while 1:
                try:
                    self.__peek_for_exit()
                    client, address = s.accept()
                    self.log("Found client, %s" % str(address))
                    self.__output_q.put((client, address))
                    break
                except socket.error:
                    # No connection
                    pass
        except Exception:
            self.log("Error: %s" % str(sys.exc_info()))
            self.log("Stopping server")
        finally:
            self.log("Finishing socket server")
            s.close()

    def __peek_for_exit(self):
        try:
            #self.log("Checking for exit")
            self.__check_exit(self.__message_q.get_nowait())
        except queue.Empty:
            pass

    @staticmethod
    def __check_exit(message):
        if message == "exit":
            raise Exception("Exiting")


class SocketServer:

    def __init__(self):
        self.__message_q = queue.Queue(0)
        self.__socket_q = queue.Queue(1)
        self.__thread = None

    def __del__(self):
        self.stop()

    def start(self, host, port):
        if not self.is_alive():
            self.__thread = BackgroundSocketCreator(
                host, port, self.__message_q, self.__socket_q)
            self.__thread.start()

    def is_alive(self):
        return self.__thread and self.__thread.is_alive()

    def has_socket(self):
        return self.__socket_q.full()

    def socket(self):
        return self.__socket_q.get_nowait()

    def stop(self):
        if self.is_alive():
            self.__message_q.put_nowait("exit")
            self.__thread.join(3000)
        if self.has_socket():
            self.socket()[0].close()

@@ -5403,24 +5403,103 @@
 lf.__port))%0A
+            s.settimeout(5) # timeout after 5 seconds so we can check messages%0A
             
@@ -6154,24 +6154,25 @@
            #
+ 
 self.log(%22Ch

set a timeout on the blocking socket connection