# -*- coding: utf-8 -*-
# shared_db.py
# Copyright (C) 2013 LEAP
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.


"""
A shared database for storing/retrieving encrypted key material.
"""

try:
    import simplejson as json
except ImportError:
    import json  # noqa


from u1db.remote import http_database


from leap.soledad.auth import TokenBasedAuth


#-----------------------------------------------------------------------------
# Soledad shared database
#-----------------------------------------------------------------------------

class NoTokenForAuth(Exception):
    """
    No token was found for token-based authentication.
    """


class Unauthorized(Exception):
    """
    User does not have authorization to perform task.
    """


class SoledadSharedDatabase(http_database.HTTPDatabase, TokenBasedAuth):
    """
    This is a shared recovery database that enables users to store their
    encryption secrets in the server and retrieve them afterwards.
    """
    # TODO: prevent client from messing with the shared DB.
    # TODO: define and document API.

    #
    # Token auth methods.
    #

    def set_token_credentials(self, uuid, token):
        """
        Store given credentials so we can sign the request later.

        @param uuid: The user's uuid.
        @type uuid: str
        @param token: The authentication token.
        @type token: str
        """
        TokenBasedAuth.set_token_credentials(self, uuid, token)

    def _sign_request(self, method, url_query, params):
        """
        Return an authorization header to be included in the HTTP request.

        @param method: The HTTP method.
        @type method: str
        @param url_query: The URL query string.
        @type url_query: str
        @param params: A list with encoded query parameters.
        @type param: list

        @return: The Authorization header.
        @rtype: list of tuple
        """
        return TokenBasedAuth._sign_request(self, method, url_query, params)

    #
    # Modified HTTPDatabase methods.
    #

    @staticmethod
    def open_database(url, create, creds=None):
        # TODO: users should not be able to create the shared database, so we
        # have to remove this from here in the future.
        """
        Open a Soledad shared database.

        @param url: URL of the remote database.
        @type url: str
        @param create: Should the database be created if it does not already
            exist?
        @type create: bool
        @param token: An authentication token for accessing the shared db.
        @type token: str

        @return: The shared database in the given url.
        @rtype: SoledadSharedDatabase
        """
        db = SoledadSharedDatabase(url, creds=creds)
        db.open(create)
        return db

    @staticmethod
    def delete_database(url):
        """
        Dummy method that prevents from deleting shared database.

        @raise: This will always raise an Unauthorized exception.

        @param url: The database URL.
        @type url: str
        """
        raise Unauthorized("Can't delete shared database.")

    def __init__(self, url, document_factory=None, creds=None):
        """
        Initialize database with auth token and encryption powers.

        @param url: URL of the remote database.
        @type url: str
        @param document_factory: A factory for U1BD documents.
        @type document_factory: u1db.Document
        @param creds: A tuple containing the authentication method and
            credentials.
        @type creds: tuple
        """
        http_database.HTTPDatabase.__init__(self, url, document_factory,
                                            creds)