
from pecan import request, response
from base64 import b64decode
from functools import wraps

import traceback

from . import context


# Handle authorization
def auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not context.instance.enable_auth:
            return f(*args, **kwargs)
            
        if not request.authorization:
            response.status = 401
            response.headers['WWW-Authenticate'] = 'Basic realm="Login Required"'
            return {'message': 'auth: No HTTP username/password'}

        username, password = b64decode(request.authorization[1]).decode('utf-8').split(':')

        # Check that the username exists
        if username not in context.instance.keys:
            response.status = 401
            response.headers['WWW-Authenticate'] = 'Basic realm="Login Required"'
            return {'message': 'auth: No such user'}

        # Check the password
        if context.instance.keys[username] != password:
            response.status = 401
            response.headers['WWW-Authenticate'] = 'Basic realm="Login Required"'
            return {'message': 'auth: Incorrect password'}

        return f(*args, **kwargs)
    return decorated


# Helper function to lock the function
def lock(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        with context.instance.requests_lock:
            return f(*args, **kwargs)
    return decorated


# Support ?page=N argument
def paginate(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        _out = f(*args, **kwargs)

        # Do not modify anything without a specific request
        if not 'page' in kwargs:
            return _out

        # A pass-through for errors, etc
        if not isinstance(_out, list):
            return _out

        # Parse the page argument
        _page = kwargs['page']
        try:
            _page = int(_page)
        except ValueError:
            response.status = 500
            return {'message': 'The requested page is not an integer'}

        # Raise _page so that 0 is the first page and -1 is the last
        _page += 1

        if _page > 0:
            _page *= 100
        else:
            _page = len(_out) - (_page*100)

        return _out[_page - 100: _page]
    return decorated
