"""
Deterministic method for colorizing words.

One particularly useful application is colorizing chat logs in a consistent
manner.
"""
import math, re, string


def wave(i):
    return math.cos(i / 3 * 2 * math.pi) / 2


def hsb(h, s=1.0, b=0.5):
    return [s * wave(float(h) - n) + b for n in range(3)]


def colorizeWord(word):
    """
    Colorize C{word} using its content to determine the color.

    @rtype: C{(int, int, int)}
    @return: C{(red, green, blue)}
    """
    maxRange = float(2 ** 30)
    h = (hash(word.title()) % maxRange) / maxRange * 3
    s = 0.7
    return tuple(int(c * 255) for c in hsb(h, s))


NICKNAME_CHARS = re.escape(string.lowercase + string.uppercase + string.digits + '_-[]\\`^{}')
nicknamesPattern = re.compile('([' + NICKNAME_CHARS + ']+)')

def colorizeLine(f, line, highlights):
    """
    Colorize a line according to a specific set of words to highlight.

    @type f: C{callable} taking C{unicode}, and C{(int, int, int)}
    @param f: A callable taking C{word} and C{(red, green, blue)} (as integers
        in the range [0;255]) intended to transform the input into something
        the consumer can use directly

    @type line: C{unicode}
    @param line: Line to colorize

    @type highlights: C{container}
    @param highlights: Container of words to highlight in C{line}

    @rtype: C{iterable} of C{unicode} and whatever C{f} returns
    @return: An iterable of words and words transformed by C{f}
    """
    for word in nicknamesPattern.split(line):
        if word in highlights:
            yield f(word, colorizeWord(word))
        else:
            yield word
    yield '\n'
