# -*- coding: utf-8 -*-
# Copyright 2016 Open Permissions Platform Coalition
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed under the License is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.

"""
Scopes
------

The following scopes are available:

    - read
    - write
    - delegate

The "read" scope permits the client to read a protected resource.
This is the default scope.

The "write" scope permits a client to write to a protected resource.
Unilke "read", "write" must also include the identity of the
resource, within "[]" brackets, e.g. "write[1234]" allows writing to a
resource identified by 1234. Services may also be identied with it's registered
URL, e.g. "write[http://test.com]". The auth service verifies whether the
client is permitted to write to the resource before issuing an access
token.

The "delegate" scope is used to delegate writing to a resource, e.g.
the onboarding service accesses the repository on the client's behalf
To access the resource, the delegate will exchange the token for a new
"write" token.

The delegate scope has the form

    delegate[<service id or url>]:write[<resource id or url>]

Where service id or url is the delegate service's ID or URL (e.g. the
onbooarding service URL), and the resource id or URL is the protected
resource's ID or URL (e.g. the repository ID).

The advantage of using "delegate" instead of "write" is that the token can
only be used by the specified delegate (assuming the delegate keeps their
credentials secure), and the delegate will only be able to write to the
specified resource.
"""
import re
from collections import defaultdict, namedtuple
from functools import partial

import couch
from perch import views, Repository, Service
from tornado.gen import coroutine, Return

from .exceptions import InvalidScope, Unauthorized

READ = 'read'
READ_REGEX = re.compile(r'^read\[(?P<resource_id>.+)\]$')
WRITE = 'write'
WRITE_REGEX = re.compile(r'^write\[(?P<resource_id>.+)\]$')
DELEGATE = 'delegate'
DELEGATE_REGEX = re.compile(r'^delegate\[(?P<delegate_id>.+)\]:(?P<delegated_action>read|write)\[(?P<resource_id>.+)\]$')
ACCESS_MAPPING = {
    READ: 'r',