# -*- coding: utf-8 -*-
"""
    jinja.tests
    ~~~~~~~~~~~

    Jinja test functions. Used with the "is" operator.

    :copyright: 2007 by Armin Ronacher.
    :license: BSD, see LICENSE for more details.
"""
import re


number_re = re.compile(r'^-?\d+(\.\d+)?$')
regex_type = type(number_re)


def test_odd():
    """
    Return true if the variable is odd.
    """
    return lambda e, c, v: v % 2 == 1


def test_even():
    """
    Return true of the variable is even.
    """
    return lambda e, c, v: v % 2 == 0


def test_defined():
    """
    Return true if the variable is defined:

    .. sourcecode:: jinja

        {% if variable is defined %}
            value of variable: {{ variable }}
        {% else %}
            variable is not defined
        {% endif %}

    See also the ``default`` filter.
    """
    return lambda e, c, v: v is not e.undefined_singleton


def test_lower():
    """
    Return true if the variable is lowercase.
    """
    return lambda e, c, v: isinstance(v, basestring) and v.islower()


def test_upper():
    """
    Return true if the variable is uppercase.
    """
    return lambda e, c, v: isinstance(v, basestring) and v.isupper()


def test_numeric():
    """
    Return true if the variable is numeric.
    """
    return lambda e, c, v: isinstance(v, (int, long, float)) or (
                           isinstance(v, basestring) and
                               number_re.match(v) is not None)


def test_sequence():
    """
    Return true if the variable is a sequence. Sequences are variables
    that are iterable.
    """
    def wrapped(environment, context, value):
        try:
            len(value)
            value.__getitem__
        except:
            return False
        return True
    return wrapped


def test_matching(regex):
    r"""
    Test if the variable matches the regular expression given. Note that
    you have to escape special chars using *two* backslashes, these are
    *not* raw strings.

    .. sourcecode:: jinja

        {% if var is matching @/^\d+$/ %}
            var looks like a number
        {% else %}
            var doesn't really look like a number
        {% endif %}
    """
    def wrapped(environment, context, value):
        if type(regex) is regex_type:
            regex_ = regex
        else:
            if environment.disable_regexps:
                raise RuntimeError('regular expressions disabled.')
            if isinstance(regex, unicode):
                regex_ = re.compile(regex, re.U)
            elif isinstance(regex, str):
                regex_ = re.compile(regex)
            else:
                return False
        return regex_.search(value) is not None
    return wrapped


def test_sameas(other):
    """
    Check if an object points to the same memory address than another
    object:

    .. sourcecode:: jinja

        {% if foo.attribute is sameas(false) %}
            the foo attribute really is the `False` singleton
        {% endif %}

    *New in Jinja 1.2*
    """
    return lambda e, c, v: v is other


TESTS = {
    'odd':              test_odd,
    'even':             test_even,
    'defined':          test_defined,
    'lower':            test_lower,
    'upper':            test_upper,
    'numeric':          test_numeric,
    'sequence':         test_sequence,
    'matching':         test_matching,
    'sameas':           test_sameas
}
