#!/usr/bin/env python3

import sys
import re

from twisted.internet import defer
from twisted.internet import protocol
from twisted.internet import reactor
from twisted.python import log
from twisted.enterprise import adbapi
from twisted.protocols.basic import LineReceiver

# Connect to:
HOST = "127.0.0.1"
PORT = 2002
# Listen on:
LISTEN_PORT = 9999
LISTEN_ON = "127.0.0.1"


class LineRecv(LineReceiver):
    def __init__(self, notify):
        self.delimiter = b"\n"  # \r"
        self.notify = notify

    def lineReceived(self, line):
        log.msg("LR:", line)
        self.notify.gotLine(line)


class PlayerProtocol(protocol.Protocol):
    def __init__(self):
        self.user = None
        self.dbinit = False
        self.db = None
        self.buffer = ""
        self.linereader = LineRecv(self)
        self.linereader.connectionMade()

    def connectionMade(self):
        log.msg("Client: connected to peer")
        self.queue_twgs = self.factory.queue_twgs
        self.queue_twgs.get().addCallback(self.serverDataReceived)

    def gotLine(self, line):
        log.msg(">>> [{0}]".format(line.decode("utf-8", "ignore")))

    def serverDataReceived(self, chunk):
        # rlogin looks like this:  \x00 password \x00 username \x00 terminal/speed \x00
        # b'\x00up2lat3\x00bugz\x00ansi-bbs/115200\x00'
        # We're looking for 4 \x00!
        # TODO: Line processing, and line cleaning (remove ANSI color codes)
        if chunk is False:
            self.queue_twgs = None
            log.msg("Client: disconnecting from peer")
            self.factory.continueTrying = False
            self.transport.loseConnection()
        else:
            self.buffer += chunk.decode("utf-8")
            if self.user is None:
                # Ok, process this
                # self.buffer += chunk.decode('utf-8')
                # We don't have the username yet
                parts = self.buffer.split("\x00")
                if len(parts) >= 5:
                    # Got it!
                    self.user = parts[1]
                    log.msg("User: {0}".format(self.user))
                    # Reset buffer -- remove everything before last \x00
                    zpos = self.buffer.rindex("\x00")
                    self.buffer = self.buffer[zpos + 1 :]
                    self.buffer = ""
                    # init sqlite db using the username
            else:
                # process the buffer
                # Handle backspaces by deleting previous character.

                # Send the received data into the linereader for "automatic" line processing.
                self.linereader.dataReceived(chunk)

                #
                #
                # Strip out ANSI color codes
                # self.buffer = re.sub(r'\x1b[\d;?\d+m', '', self.buffer)
                # Process lines ...

            self.transport.write(chunk)
            self.queue_twgs.get().addCallback(self.serverDataReceived)

        # elif b"$" == chunk:
        #     self.factory.svr_queue.put(b"HELLO.\r\n")
        #     self.cli_queue.get().addCallback(self.serverDataReceived)
        # elif self.cli_queue:
        #     log.msg("Client: writing %d bytes to peer" % len(chunk))
        #     log.msg(">>", repr(chunk))
        #     self.transport.write(chunk)
        #     self.cli_queue.get().addCallback(self.serverDataReceived)
        # else:
        #     self.factory.cli_queue.put(chunk)

    def dataReceived(self, chunk):
        # log.msg("Client: %d bytes received from peer" % len(chunk))
        # clean, strip ANSI, etc.

        # log.msg("<<", chunk.decode("utf-8", "ignore"))
        log.msg("<<", repr(chunk))
        self.factory.queue_client.put(chunk)

    def connectionLost(self, why):
        log.msg("connectionLost because: %s" % why)
        # if self.cli_queue:
        #     self.cli_queue = None
        #     log.msg("Client: peer disconnect unexpectedly")
        self.factory.queue_client.put(False)
        self.queue_twgs = None
        self.transport.loseConnection()


class GlueFactory(protocol.ClientFactory):
    maxDelay = 10
    protocol = PlayerProtocol

    def __init__(self, queue_client, queue_twgs):
        self.queue_client = queue_client
        self.queue_twgs = queue_twgs

    def closeIt(self):
        log.msg("closeIt")
        self.queue_client.put(False)

    def clientConnectionFailed(self, connector, why):
        log.msg("connectionFailed: %s" % why)
        self.queue_client.put(b"Sorry!  I'm Unable to connect to the game server.\r\n")
        # syncterm gets cranky/locks up if we close this here.
        # (Because it is still sending rlogin information?)
        reactor.callLater(2, self.closeIt)


# ProxyServer is created for each connection


class TWGSServer(protocol.Protocol):
    def connectionMade(self):
        self.queue_twgs = defer.DeferredQueue()
        self.queue_client = defer.DeferredQueue()
        self.queue_client.get().addCallback(self.clientDataReceived)

        factory = GlueFactory(self.queue_client, self.queue_twgs)
        reactor.connectTCP(HOST, PORT, factory, 5)

    def clientDataReceived(self, chunk):
        if chunk is False:
            self.transport.loseConnection()
        else:
            # log.msg("Server: writing %d bytes to original client" % len(chunk))
            self.transport.write(chunk)
            self.queue_client.get().addCallback(self.clientDataReceived)

    def dataReceived(self, chunk):
        # log.msg("Server: %d bytes received" % len(chunk))
        self.queue_twgs.put(chunk)

    def connectionLost(self, why):
        log.msg("lost connection %s" % why)
        self.queue_twgs.put(False)

    def connectionFailed(self, why):
        log.msg("connectionFailed: %s" % why)


if __name__ == "__main__":
    log.startLogging(sys.stdout)
    factory = protocol.Factory()
    factory.protocol = TWGSServer
    reactor.listenTCP(LISTEN_PORT, factory, interface=LISTEN_ON)
    reactor.run()