# (heavily) Adapted from http://flask.pocoo.org/snippets/44/

from flask import request, url_for
from math import ceil


def get_url_for_page(page, endpoint=None, view_args=None, args=None,
                     exclude_args=('apikey', 'apiuser'), full_url=True):
    """
    Gets the url to a result page. All the parameter but page are
    optional, falling back to the current request.

    :param page: (int) the target page number.
    :param endpoint: (string) the name of the target view.
    :param view_args: (dict) arguments to the view.
    :param args: (dict) extra arguments to include in the querystring.
    :param exclude_args: (sequence) keys to blacklist in the querystring.
    :param full_url: (boolean) True to include the whole url (root_base)

    """
    if endpoint is None:
        endpoint = request.endpoint

    if view_args is None:
        view_args = request.view_args

    if args is None:
        args = request.args.to_dict(flat=False)

    options = dict(args)
    if exclude_args:
        [options.pop(key, None) for key in exclude_args]

    options.update(view_args, page=page, _external=full_url)
    return url_for(endpoint, **options)


class Paginator(object):
    """
    A class to create objects providing common methods to ease the
    creation of paginated links.

    """
    url_for_page = staticmethod(get_url_for_page)

    def __init__(self, page, per_page, total_count, max_result_window=None):
        self.page = page
        self.per_page = per_page
        self.total_count = total_count
        if max_result_window is None:
            self.last_reachable_result = total_count
        else:
            self.last_reachable_result = min(total_count, max_result_window)

    @property
    def pages(self):
        return int(ceil(self.last_reachable_result / float(self.per_page)))

    @property
    def has_prev(self):
        return self.page > 1

    @property
    def has_next(self):
        return self.page < self.pages

    @property
    def page_url(self):
        """
        Returns the url corresponding to the paginator's current page.
        When the current page is 1, the generated url will not carry
        any page information. This is to keep consistency between
        naive and generated urls (by default any listing starts at its
        first page).

        :return: (string) an absolute url.

        """
        return self.url_for_page(self.page if self.page != 1 else None)

    @property
    def first_page_url(self):
        return self.url_for_page(1)

    @property
    def previous_page_url(self):
        return self.url_for_page(self.page - 1)

    @property
    def next_page_url(self):
        return self.url_for_page(self.page + 1)

    @property
    def last_page_url(self):
        return self.url_for_page(self.pages)

    @property
    def links(self):
        links = {"self": self.page_url}

        if self.total_count:
            links["first"] = self.first_page_url
            links["last"] = self.last_page_url
            if self.has_prev:
                links["prev"] = self.previous_page_url
            if self.has_next:
                links["next"] = self.next_page_url

        return links
