# Modified version of the {% url %} tag that allows you to specify a hostname
# {% hosturl http://hostpath/path path.to.some_view arg1,arg2,name1=value1 %}

from django import template
from django.conf import settings

register = template.Library()

class HostURLNode(template.Node):
    def __init__(self, hostpath, view_name, args, kwargs, asvar):
        self.hostpath = hostpath
        self.view_name = view_name
        self.args = args
        self.kwargs = kwargs
        self.asvar = asvar
        print self.view_name

    def render(self, context):
        from django.core.urlresolvers import reverse, NoReverseMatch
        args = [arg.resolve(context) for arg in self.args]
        kwargs = dict([(smart_str(k,'ascii'), v.resolve(context))
                       for k, v in self.kwargs.items()])
        
        
        # Try to look up the URL twice: once given the view name, and again
        # relative to what we guess is the "main" app. If they both fail, 
        # re-raise the NoReverseMatch unless we're using the 
        # {% hosturl ... as var %} construct in which cause return nothing.
        url = ''
        try:
            url = reverse(self.view_name, args=args, kwargs=kwargs)
        except NoReverseMatch:
            project_name = settings.SETTINGS_MODULE.split('.')[0]
            try:
                url = reverse(project_name + '.' + self.view_name,
                              args=args, kwargs=kwargs)
            except NoReverseMatch:
                if self.asvar is None:
                    raise
                    
        if self.asvar:
            context[self.asvar] = self.hostpath + url
            return ''
        else:
            return self.hostpath + url

def hosturl(parser, token):
    """
    Returns an absolute URL matching given view with its parameters.

    This is a way to define links that aren't tied to a particular URL
    configuration::

        {% hosturl hostpath path.to.some_view arg1,arg2,name1=value1 %}

    The first argument is a path to a view. It can be an absolute python path
    or just ``app_name.view_name`` without the project name if the view is
    located inside the project.  Other arguments are comma-separated values
    that will be filled in place of positional and keyword arguments in the
    URL. All arguments for the URL should be present.

    For example if you have a view ``app_name.client`` taking client's id and
    the corresponding line in a URLconf looks like this::

        ('^client/(\d+)/$', 'app_name.client')

    and this app's URLconf is included into the project's URLconf under some
    path::

        ('^clients/', include('project_name.app_name.urls'))

    then in a template you can create a link for a certain client like this::

        {% hosturl http://other_server/path/to app_name.client client.id %}

    The URL will look like ``http://other_server/path/to/clients/client/123/``.
    """
    bits = token.contents.split(' ')
    if len(bits) < 3:
        raise TemplateSyntaxError("'%s' takes at least two arguments"
                                  " (hostpath and path to a view)" % bits[0])
    hostpath = bits[1]
    viewname = bits[2]
    args = []
    kwargs = {}
    asvar = None
        
    if len(bits) > 3:
        bits = iter(bits[3:])
        for bit in bits:
            if bit == 'as':
                asvar = bits.next()
                break
            else:
                for arg in bit.split(","):
                    if '=' in arg:
                        k, v = arg.split('=', 1)
                        k = k.strip()
                        kwargs[k] = parser.compile_filter(v)
                    elif arg:
                        args.append(parser.compile_filter(arg))
    return HostURLNode(hostpath, viewname, args, kwargs, asvar)
hosturl = register.tag(hosturl)
