#
# Implement an asyncio.Protocol for Electrum (clients)
#
#
import asyncio
import json
import logging
import socket

logger = logging.getLogger(__name__)


class StratumProtocol(asyncio.Protocol):
    client = None
    closed = False
    transport = None
    buf = b""
    connection_lost_called = False

    def connection_made(self, transport):
        self.transport = transport
        logger.debug("Transport connected ok")

        # To detect if server disconnected us
        sock = self.transport.get_extra_info("socket")
        if sock is not None:
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

    def connection_lost(self, exc):
        if not self.closed:
            self.closed = True
            self.close()
        if not self.connection_lost_called:
            self.connection_lost_called = True
            self.client.connection_lost(self)

    def data_received(self, data):
        self.buf += data

        # Unframe the mesage. Expecting JSON.
        *lines, self.buf = self.buf.split(b"\n")

        for line in lines:
            if not line:
                continue

            try:
                msg = line.decode("utf-8", "error").strip()
            except UnicodeError as exc:
                logger.exception("Encoding issue on %r", line)
                self.connection_lost(exc)
                return

            try:
                msg = json.loads(msg)
            except ValueError as exc:
                logger.exception("Bad JSON received from server: %r", msg)
                self.connection_lost(exc)
                return

            # logger.debug("RX:\n%s", json.dumps(msg, indent=2))

            # pylint: disable=protected-access
            try:
                self.client._got_response(msg)
            except Exception as e:
                logger.exception("Trouble handling response! (%s)", e)
                continue

    def send_data(self, message):
        """
        Given an object, encode as JSON and transmit to the server.
        """
        # logger.debug("TX:\n%s", json.dumps(message, indent=2))
        data = json.dumps(message).encode("utf-8") + b"\n"
        self.transport.write(data)

    def close(self):
        if not self.closed:
            try:
                self.transport.close()
            finally:
                self.closed = True


# EOF
