import re
from src import IRCLine, utils

STR_MORE = " (more...)"
STR_MORE_LEN = len(STR_MORE.encode("utf8"))
STR_CONTINUED = "(...continued) "
WORD_BOUNDARY = ' '

def _message_factory(command):
    if not command in ["PRIVMSG", "NOTICE"]:
        raise ValueError("Unknown command method '%s'" % method)

    def _(target, message, tags):
        return IRCLine.ParsedLine(command, [target, message], tags=tags)
    return _

class Out(object):
    def __init__(self, server, module_name, target, target_str, tags):
        self.server = server
        self._prefix = self._default_prefix(module_name)
        self._hide_prefix = False
        self.target = target
        self._target_str = target_str
        self._text = ""
        self.written = False
        self._tags = tags
        self._assured = False

    def assure(self):
        self._assured = True

    def write(self, text):
        self._text += text
        self.written = True
        return self
    def writeline(self, line):
        self._text += "%s\n" % line

    def send(self, method):
        if self.has_text():
            prefix = ""
            if not self._hide_prefix:
                prefix = utils.consts.RESET + "[%s] " % self._prefix

            text = self._text[:].replace("\r", "")
            while "\n\n" in text:
                text = text.replace("\n\n", "\n")

            full_text = "%s%s" % (prefix, text)
            message_factory = _message_factory(method)

            line = message_factory(self._target_str, full_text, tags=self._tags)
            if self._assured:
                line.assure()

            valid, truncated = line.truncate(self.server.hostmask(),
                margin=STR_MORE_LEN)

            if truncated:
                valid, truncated = self._adjust_to_word_boundaries(valid, truncated)

                line = IRCLine.parse_line(valid+STR_MORE)
                self._text = "%s%s" % (STR_CONTINUED, truncated)
            else:
                self._text = ""

            sent_line = self.server.send(line)

    def _adjust_to_word_boundaries(self, left, right):
        if right[0] == WORD_BOUNDARY:
            return left, right

        parts = left.rsplit(WORD_BOUNDARY, 1)

        if len(parts) != 2:
            return left, right

        return parts[0], parts[1] + right

    def _default_prefix(self, s: str):
        return s
    def set_prefix(self, prefix):
        self._prefix = self._default_prefix(prefix)
    def append_prefix(self, s: str):
        self._prefix = "%s%s" % (self._prefix, s)
    def hide_prefix(self):
        self._hide_prefix = True

    def has_text(self):
        return bool(self._text)

class StdOut(Out):
    def _default_prefix(self, s: str):
        return utils.irc.color(s, utils.consts.GREEN)
class StdErr(Out):
    def _default_prefix(self, s: str):
        return utils.irc.color(s, utils.consts.RED)