from django.core.urlresolvers import reverse
from django.template import FilterExpression
from django.template import Library, Node, TemplateSyntaxError, resolve_variable
from re import split
from urllib import quote,unquote
import re

register = Library()

class LinkNode(Node):
	def __init__(self, viewname, args, kwargs, add_to_current_link=False):
		self.viewname = viewname
		self.kwargs = kwargs
		self.args = args
		self.add_to_current_link = add_to_current_link
		
	def render(self,context):
		req = resolve_variable('request',context)

		args = [isinstance(k,FilterExpression) and k.resolve(context) or k for k in self.args]
		kwargs = req.GET.copy()

		for k,v in self.kwargs.items():
			if isinstance(v, FilterExpression) and v.token:
				kwargs[k] = v.resolve(context)
			elif v:
				kwargs[k] = v 
		
		try:
			url = not self.add_to_current_link and reverse(viewname=self.viewname, args=args, kwargs=None) or req.path
		except:
			url = req.path
	
		# check to see if named arguments have been passed
		query_started = url.find('?') > -1
		query_string  = ""

		raw_url = unquote(url)

		for k,values in kwargs.items():
			if not isinstance(values,list):
				values = [values]
			
			params_added = "&".join(
				[quote(k) + "=" + quote(isinstance(v,str) and v or str(v)) for v in values 
					if v and (not query_started or not re.search(r"\b" + re.escape(k + "=" + v) + r"\b", raw_url))])

			if params_added: query_string += "&" + params_added
		

		if not query_started and len(query_string) > 0:
			query_string = "?" + query_string[1:]

		return url + query_string
			

def link_persist(parser, token):
	"""Url Tag that persists GET variables

	It has the same behaviour as the standard url tag
	found in django.template.defaulttags.

	But GET variables are passed by default to the 'reverse' url 
	method that builds the final url. Specified parameters override
	GET parameters.

	Usage: {% link_persist viewname arg1, arg2, ... karg1=val1, karg2=val2 ... %}

	This has been tested with Django version 0.96"""

	bits = token.contents.split(' ', 2)
	if len(bits) < 2:
		raise TemplateSyntaxError, "'%s' takes at least one argument (path to a view)" % bits[0]

	args = []
	kwargs = {}

	if len(bits) > 2:
		for arg in bits[2].split(','):
			if '=' in arg:
				k, v = arg.split('=', 1)
				kwargs[k] = parser.compile_filter(v)
			else:
				args.append(parser.compile_filter(arg))

	return LinkNode(bits[1], args, kwargs)


def link_add(parser, token):
	"""Tag that adds parameters to the current url.

	Usage: {% link_add karg1=val1, karg2=val2 ... %}

	This has been tested with Django version 0.96"""

	bits = token.contents.split(' ', 2)

	args = []
	kwargs = {}
	if len(bits) > 1:
		for arg in bits[1].split(','):
			if '=' in arg:
				k, v = arg.split('=', 1)
				kwargs[k] = parser.compile_filter(v)

	return LinkNode(None, args, kwargs, True)


register.tag('link_persist', link_persist)
register.tag('link_add', link_add)