"""
Templatetags for generating query string modifying the current request's query
string.

version: 0.2

"""
from django import template
from django.utils.datastructures import MultiValueDict


register = template.Library()


def _unquote(str, required=True, error_msg=''):
    """
    Strips the quotes from a string, I find it useful after parsing tags with
    split_contents().

    """
    if str[0] == str[-1] and str[0] in ('"',"'"):
        return str[1:-1]
    else:
        if required:
            raise TemplateSyntaxError, error_msg
        return str


def dict_from_qstring(qstring):
    """
    Returns a MultiValueDict from a query string.

    """
    mvd = MultiValueDict()
    for item in qstring.split('&'):
        sp = item.split('=')
        if len(sp) == 1:
            value = None
        elif len(sp) == 2:
            value = sp[1]
        else:
            continue
        mvd.appendlist(sp[0], value)
    return mvd


def qstring_from_dict(mvd):
    """
    Returns a query string from a MultiValueDict.

    """
    tmp = []
    for key, values in mvd.lists():
        for value in values:
            tmp.append('='.join([key, str(value)]))
    return '&'.join(tmp)


def tag_from_operation(operation_fn):
    """
    Returns a tag function wich uses a operation function (operation_fn).

    """
    class Node(template.Node):
        def __init__(self, qstring):
            self.qstring = qstring

        def render(self, context):
            mvd = dict_from_qstring(self.qstring)
            diff_mvd = operation_fn(context['request'].GET, mvd)
            return qstring_from_dict(diff_mvd)

    def do_operation(parser, token):
        args = token.split_contents()
        tag_name = args[0]
        qstring = _unquote(args[1], required=True,
                           error_msg='%r tag\'s argument should '
                                     'be in quotes.' % tag_name)
        return Node(qstring)
    return do_operation


def delete(lmvd, rmvd):
    mvd = lmvd.copy()
    for key, value in rmvd.lists():
        if key in mvd:
            if None in value:
                new_list = []
            else:
                new_list = [i for i in mvd.getlist(key) if i not in value]
            mvd.setlist(key, new_list)
    return mvd

register.tag('qs_delete', tag_from_operation(delete))


def update(lmvd, rmvd):
    mvd = lmvd.copy()
    for key, values in rmvd.lists():
        if key in mvd:
            mvd.setlist(key, values)
    return mvd

register.tag('qs_update', tag_from_operation(update))