## protocol.py
# IRC implementation-agnostic constants/helpers.
import re
from abc import abstractmethod

DEFAULT_ENCODING = "utf-8"
FALLBACK_ENCODING = "iso-8859-1"


## Errors.


class ProtocolViolation(Exception):
    """An error that occurred while parsing or constructing an IRC message that violates the IRC protocol."""

    def __init__(self, msg, message):
        super().__init__(msg)
        self.irc_message = message


## Bases.


class Message:
    """Abstract message class. Messages must inherit from this class."""

    @classmethod
    @abstractmethod
    def parse(cls, line, encoding=DEFAULT_ENCODING):
        """Parse data into IRC message. Return a Message instance or raise an error."""
        raise NotImplementedError()

    @abstractmethod
    def construct(self, force=False):
        """Convert message into raw IRC command. If `force` is True, don't attempt to check message validity."""
        raise NotImplementedError()

    def __str__(self):
        return self.construct()


## Misc.


def identifierify(name):
    """Clean up name so it works for a Python identifier."""
    name = name.lower()
    name = re.sub("[^a-z0-9]", "_", name)
    return name
