import Levels
import fnmatch
import re

__re_type = type(re.compile('foo')) # XXX is there a canonical place for this?

def msgFilter(x):
    """return a function suitable for use as a filter with emitters.

    You may pass:

    :None, True: the filter will always return True
    :False: the filter will always return False
    :string: compiled into a regex
    :regex: match()ed against the message text
    :callable: returned as is

    """
    if x is None:
        return lambda msg: True
    elif isinstance(x, bool):
        return lambda msg: x
    elif isinstance(x, basestring):
        return regex_wrapper(re.compile(x))
    elif isinstance(x, __re_type):
        return regex_wrapper(x)
    elif callable(x): # XXX test w/ inspect.getargs here?
        return x
    else:
        # XXX a dict could be used to filter on fields (w/ callables?)
        raise ValueError("Unknown filter: {0!r}".format(x))

def regex_wrapper(regexp):
    assert isinstance(regexp, __re_type)
    def wrapped(msg):
        return regexp.match(msg.text) is not None
    return wrapped

def names(*names):
    """returns a filter, which gives True if the messsage's name equals any of those provided

    ``names`` will be stored as an attribute on the filter.

    :arg strings names: names to match
    """
    names_set = set(names)
    def set_names_filter(msg):
        return msg.name in names_set
    set_names_filter.names = names
    return set_names_filter

def glob_names(*names):
    """returns a filter, which gives True if the messsage's name globs those provided

    ``names`` will be stored as an attribute on the filter.

    This is probably quite a bit slower than :function:`names`.

    :arg strings names: glob patterns.
    """
    # copied from fnmatch.fnmatchcase - for speed
    patterns = [re.compile(fnmatch.translate(pat)) for pat in names]
    def glob_names_filter(msg):
        return any(pat.match(msg.name) is not None for pat in patterns)
    glob_names_filter.names = names
    return glob_names_filter



class Emitter(object):
    """
    Emits!

    :ivar min_level: only emit if greater than this
    :type min_level: Levels.LogLevel


    .. function:: filter(msg) -> bool should_emit
    """

    def __init__(self, min_level, filter, outputter):
        if not isinstance(min_level, Levels.LogLevel):
            raise ValueError("Unknown min_level: {0}".format(min_level))

        self.min_level = min_level
        self.filter = filter
        self._outputter = outputter

    @property
    def filter(self):
        return self._filter

    @filter.setter
    def filter(self, f):
        self._filter = msgFilter(f)

    @filter.deleter
    def filter(self):
        del self._filter
import Levels
import fnmatch
import re

__re_type = type(re.compile('foo')) # XXX is there a canonical place for this?

def msgFilter(x):
    """return a function suitable for use as a filter with emitters.

    You may pass:

    :None, True: the filter will always return True
    :False: the filter will always return False
    :string: compiled into a regex
    :regex: match()ed against the message text
    :callable: returned as is

    """
    if x is None:
        return lambda msg: True
    elif isinstance(x, bool):
        return lambda msg: x
    elif isinstance(x, basestring):
        return regex_wrapper(re.compile(x))
    elif isinstance(x, __re_type):
        return regex_wrapper(x)
    elif callable(x): # XXX test w/ inspect.getargs here?
        return x
    else:
        # XXX a dict could be used to filter on fields (w/ callables?)
        raise ValueError("Unknown filter: {0!r}".format(x))

def regex_wrapper(regexp):
    assert isinstance(regexp, __re_type)
    def wrapped(msg):
        return regexp.match(msg.text) is not None
    return wrapped

def names(*names):
    """returns a filter, which gives True if the messsage's name equals any of those provided

    ``names`` will be stored as an attribute on the filter.

    :arg strings names: names to match
    """
    names_set = set(names)
    def set_names_filter(msg):
        return msg.name in names_set
    set_names_filter.names = names
    return set_names_filter

def glob_names(*names):
    """returns a filter, which gives True if the messsage's name globs those provided

    ``names`` will be stored as an attribute on the filter.

    This is probably quite a bit slower than :function:`names`.

    :arg strings names: glob patterns.
    """
    # copied from fnmatch.fnmatchcase - for speed
    patterns = [re.compile(fnmatch.translate(pat)) for pat in names]
    def glob_names_filter(msg):
        return any(pat.match(msg.name) is not None for pat in patterns)
    glob_names_filter.names = names
    return glob_names_filter



class Emitter(object):
    """
    Emits!

    :ivar min_level: only emit if greater than this
    :type min_level: Levels.LogLevel


    .. function:: filter(msg) -> bool should_emit
    """

    def __init__(self, min_level, filter, outputter):
        if not isinstance(min_level, Levels.LogLevel):
            raise ValueError("Unknown min_level: {0}".format(min_level))

        self.min_level = min_level
        self.filter = filter
        self._outputter = outputter

    @property
    def filter(self):
        return self._filter

    @filter.setter
    def filter(self, f):
        self._filter = msgFilter(f)
kill Emitter.filter.deleter - it was broken anyway