from django.utils.encoding import smart_unicode
from fields import currency_field_name


def _expand_money_params(kwargs):
    from moneyed import Money
    from django.db.models.sql.constants import LOOKUP_SEP, QUERY_TERMS
    to_append = {}
    for name, value in kwargs.items():
        if isinstance(value, Money):
            # Get rid of __lt, __gt etc for the currency lookup
            path = name.split(LOOKUP_SEP)
            if QUERY_TERMS.has_key(path[-1]):
                clean_name = LOOKUP_SEP.join(path[:-1])
            else:
                clean_name = name

            to_append[name] = value.amount
            to_append[currency_field_name(clean_name)] = smart_unicode(value.currency)
    kwargs.update(to_append)
    return kwargs


def understands_money(func):
    '''
    Used to wrap a queryset method with logic to expand
    a query from something like:

    mymodel.objects.filter(money=Money(100,"USD"))

    To something equivalent to:

    mymodel.objects.filter(money=Decimal("100.0), money_currency="USD")
    '''
    def decorator(*args, **kwargs):
        kwargs = _expand_money_params(kwargs)
        return func(*args, **kwargs)
    return decorator

RELEVANT_QUERYSET_METHODS = ['dates', 'distinct', 'extra', 'get', 'get_or_create', 'filter', 'complex_filter',
                             'exclude', 'in_bulk', 'iterator', 'latest', 'order_by', 'select_related', 'values']


def add_money_comprehension_to_queryset(qs):
    # Decorate each relevant method with understand_money in the queryset given
    map(lambda attr: setattr(qs, attr, understands_money(getattr(qs, attr))), RELEVANT_QUERYSET_METHODS)
    return qs


def money_manager(manager):
    '''
    Wraps a model managers get_query_set method so that each query set it returns
    is able to work on money fields.

    We use this instead of a real model manager, in order to allow users of django-money to
    use other managers special managers while still doing money queries.
    '''
    import types

    def get_query_set(self, *args, **kwargs):
        return add_money_comprehension_to_queryset(self._old_get_query_set(*args, **kwargs))

    if not hasattr(manager, '_old_get_query_set'):
        manager.__class__._old_get_query_set = manager.__class__.get_query_set

    manager.__class__.get_query_set = types.MethodType(get_query_set, None, manager.__class__)
    return manager
