import re
from django import template
from django.http import QueryDict


ADJACENT = 3
CAPS = 1
RE_URL = re.compile('(.*)1(.*)')
register = template.Library()


def page_separator(current, count, adjacent=ADJACENT, caps=CAPS):
    if current < adjacent + 1:
        adjacent += adjacent - current + 1
    elif count - current < adjacent:
        adjacent += adjacent - (count - current)
    bits = []
    if current > (1 + adjacent + caps):
        if caps:
            bits.append(range(1, caps+1))
        start = current - adjacent
    else:
        start = 1
    if current + adjacent < count - caps:
        end = current + adjacent
    else:
        end = count
    bits.append(range(start, end+1))
    if end != count:
        if caps:
            bits.append(range(count-caps+1, count+1))
    return bits


def get_page_context(page, url_func, adjacent, caps):
    if not page:
        return {}
    current = page.number
    count = page.paginator.num_pages
    if count < 2:
        return {}
    pages = []
    for page_group in page_separator(current, count, adjacent, caps):
        group = []
        for number in page_group:
            url = url_func(number)
            if not url:
                return {}
            group.append({'url': url, 'number': number,
                          'current': page.number==number})
        pages.append(group)
    c = {'pages': pages}
    if current > 1:
        c['previous_url'] = url_func(current-1)
    if current < count:
        c['next_url'] = url_func(current+1)
    return c


@register.inclusion_tag('pagination-nav.html')
def pagination_nav(page, url, first_page_url=None, adjacent=ADJACENT, caps=CAPS):
    """
    Generate Digg-like pagination navigation for URLs like "/entries/page/5/".

    Required arguments:

    page
        A ``django.core.paginator`` ``Page`` object
    url
        An example URL to navigate to page 1 (the last character ``"1"`` in the
        URL gets replaced with the actual page number)

    Optional arguments:

    first_page_url
        An alternate first page exact URL
    adjacent
        The minimum number of pages to show either side of the current page
        (defaults to ``3``)
    caps
        The number of pages to show at either end (defaults to ``1``)
    """
    def make_url(number):
        if number == 1 and first_page_url:
            return first_page_url
        match = RE_URL.match(url)
        if not match:
            raise template.TemplateSyntaxError(
                'URL did not contain the character "1" (which gets replaced with '
                'the actual page number).'
            )
        start, end = match.groups()
        return '%s%s%s' % (start, number, end)
    return get_page_context(page, make_url, adjacent, caps)


@register.inclusion_tag('pagination-nav.html')
def pagination_nav_qs(page, url='', querydict=None, url_attr='page',
                      adjacent=ADJACENT, caps=CAPS):
    """
    Generate Digg-like pagination navigation for URLs like "/entries/?page=5".

    Required arguments:

    page
        A django.core.paginator Page object

    Optional arguments:

    url
        The base url (defaults to a blank string)
    querydict
        Usually ``request.GET`` (defaults to an empty ``QueryDict``)
    url_attr
        The querystring attribute to change (defaults to ``'page'``)
    adjacent
        The minimum number of pages to show either side of the current page
        (defaults to ``3``)
    caps
        The number of pages to show at either end (defaults to ``1``)
    """
    querydict = querydict or QueryDict('')
    def make_url(number):
        qs = querydict.copy()
        if number == 1:
            qs.pop(url_attr, None)
        else:
            qs[url_attr] = number
        qs = qs.urlencode()
        if qs:
            qs = '?%s' % qs
        if not url and not qs:
            return '.'
        return '%s%s' % (url or '', qs)
    return get_page_context(page, make_url, adjacent, caps)
