"""Objects common to multiple IPC endpoint types"""
from collections import namedtuple
import json

class JSONMixin:
    """Mixin to provide JSON encoding and decoding methods"""
    def to_bytes(self):
        """Convert instance to bytes

        :rtype: bytes
        :returns: representation of self as bytes
        """
        return json.dumps(self._asdict()).encode('utf-8')

    @classmethod
    def from_bytes(cls, blob):
        """Construct instance from bytes

        :param bytes blob: the return value of a previous call to to_bytes()
        :rtype: cls
        :returns: a new instance of cls
        """
        return cls(**json.loads(blob.decode('utf-8')))

# The WorkerRequest and WorkerReply classes embed what is effectively
# importer_service.ImportRequest and also add some IPC-related attributes. We
# could embed into them ImportRequest attributes as a whole but this would make
# encoding and decoding more complicated. While ImportRequest is just two
# fields, let's keep it simple and just have two fields in WorkerRequest and
# WorkerReply that map to the ImportRequest and handle them manually as
# required.

class WorkerRequest(
    namedtuple('WorkerRequest', ['package', 'level']),
    JSONMixin,
):
    """Representation of a request to a worker sent over IPC

    :ivar str package: the source package for which an import is requested.
        This is an encoded representation of
        importer_service.ImportRequest.package.
    :ivar int level: whether the request is for an incremental or full
        reimport. This is an encoded representation of
        importer_service.ImportRequest.level.
    """
    __slots__ = ()

class WorkerReply(
    namedtuple('WorkerReply', [
        'identity',
        'previous_package',
        'previous_level',
        'previous_result',
    ]),
    JSONMixin,
):
    """Representation of a reply from a worker sent over IPC

    :ivar str identity: the identity of the worker sending the reply.
    :ivar (str or None) package: the source package for which an import was
        previously requested. This is an encoded representation of
        importer_service.ImportRequest.package. None if the reply is a request
        for work when no previous work was assigned.
    :ivar (int or None) level: whether the previous request was for an
        incremental or full reimport. This is an encoded representation of
        importer_service.ImportRequest.level. None if the reply is a request
        for work when no previous work was assigned.
    :ivar (bool or None) previous_result: the success (True) or failure (False)
        result of the previous request. None if the reply is a request for work
        when no previous work was assigned.
    """
    __slots__ = ()
