from twisted.protocols.basic import LineReceiver
import json
import logging
import platform

try:
    # Python 2: "unicode" is built-in
    unicode
except NameError:
    unicode = str

logger = logging.getLogger()
system = platform.system()


class SerialLineReceiverBase(LineReceiver, object):
    MAX_LENGTH = 1024*1024*128

    def __init__(self, *args, **kwargs):
        if system == "FreeBSD":
            self.delimiter = b'\n'
        else:
            self.delimiter = b'\r'
        super(SerialLineReceiverBase, self).__init__(*args, **kwargs)

    def send_response(self, response, args):
#        logger.debug("send_response %s %s" % (response, args))
        self.transport.write(json.dumps({'response': response,
                                         'args': args}) + '\r\n')

    def send_command(self, command, args):
        self.transport.write(json.dumps({'command': command,
                                         'args': args}) + '\r\n')

    def handle_command(self, command, args):
        raise NotImplementedError("Subclass must implement abstract method")

    def handle_response(self, response, args):
        raise NotImplementedError("Subclass must implement abstract method")

    def lineReceived(self, data):
#       logger.debug("lineReceived: %s", data)
        if (isinstance(data, unicode)):
            data = data.strip('\0')
        else:
            data = data.strip(b'\0')
        try:
            data = json.loads(data)
            args = data.get('args', {})
            if not isinstance(args, dict):
                args = {}
            command = data.get('command', None)
            response = data.get('response', None)
            logger.debug('[serial] valid json: %s' % (data, ))
        except (ValueError, KeyError) as e:
            logger.error('[serial] invalid json: %s (%s)' % (data, e))
            self.clearLineBuffer()
            return

        if command is not None and isinstance(command, unicode):
            logger.debug('received command: %s (%s)' % (command, args))
            try:
                self.handle_command(command, args)
            except Exception as e:
                logger.exception("Unhandled exception during line recived: ")
        elif response is not None and isinstance(response, unicode):
            logger.debug('received reply: %s (%s)' % (response, args))
            self.clearLineBuffer()
            self.handle_response(response, args)
