# All Rights Reserved.
#
#    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.

"""
Version 1 of the Magnum API

NOTE: IN PROGRESS AND NOT FULLY IMPLEMENTED.
"""

from oslo_log import log as logging
import pecan
from wsme import types as wtypes

from magnum.api.controllers import base as controllers_base
from magnum.api.controllers import link
from magnum.api.controllers.v1 import bay
from magnum.api.controllers.v1 import baymodel
from magnum.api.controllers.v1 import certificate
from magnum.api.controllers.v1 import cluster
from magnum.api.controllers.v1 import cluster_template
from magnum.api.controllers.v1 import federation
from magnum.api.controllers.v1 import magnum_services
from magnum.api.controllers.v1 import quota
from magnum.api.controllers.v1 import stats
from magnum.api.controllers import versions as ver
from magnum.api import expose
from magnum.api import http_error
from magnum.i18n import _


LOG = logging.getLogger(__name__)

BASE_VERSION = 1

MIN_VER_STR = '%s %s' % (ver.Version.service_string, ver.BASE_VER)

MAX_VER_STR = '%s %s' % (ver.Version.service_string, ver.CURRENT_MAX_VER)

MIN_VER = ver.Version({ver.Version.string: MIN_VER_STR},
                      MIN_VER_STR, MAX_VER_STR)
MAX_VER = ver.Version({ver.Version.string: MAX_VER_STR},
                      MIN_VER_STR, MAX_VER_STR)


class MediaType(controllers_base.APIBase):
    """A media type representation."""

    base = wtypes.text
    type = wtypes.text

    def __init__(self, base, type):
        self.base = base
        self.type = type


class V1(controllers_base.APIBase):
    """The representation of the version 1 of the API."""

    id = wtypes.text
    """The ID of the version, also acts as the release number"""

    media_types = [MediaType]
    """An array of supcontainersed media types for this version"""

    links = [link.Link]
    """Links that point to a specific URL for this version and documentation"""

    baymodels = [link.Link]
    """Links to the baymodels resource"""

    bays = [link.Link]
    """Links to the bays resource"""

    clustertemplates = [link.Link]
    """Links to the clustertemplates resource"""

    clusters = [link.Link]
    """Links to the clusters resource"""

    quotas = [link.Link]
    """Links to the quotas resource"""

    certificates = [link.Link]
    """Links to the certificates resource"""

    mservices = [link.Link]
    """Links to the magnum-services resource"""

    stats = [link.Link]
    """Links to the stats resource"""

    # Links to the federations resources
    federations = [link.Link]

    @staticmethod
    def convert():
        v1 = V1()
        v1.id = "v1"
        v1.links = [link.Link.make_link('self', pecan.request.host_url,
                                        'v1', '', bookmark=True),
                    link.Link.make_link('describedby',
                                        'http://docs.openstack.org',
                                        'developer/magnum/dev',
                                        'api-spec-v1.html',
                                        bookmark=True, type='text/html')]
        v1.media_types = [MediaType('application/json',
                          'application/vnd.openstack.magnum.v1+json')]
        v1.baymodels = [link.Link.make_link('self', pecan.request.host_url,
                                            'baymodels', ''),
                        link.Link.make_link('bookmark',
                                            pecan.request.host_url,
                                            'baymodels', '',
                                            bookmark=True)]
        v1.bays = [link.Link.make_link('self', pecan.request.host_url,
                                       'bays', ''),
                   link.Link.make_link('bookmark',
                                       pecan.request.host_url,
                                       'bays', '',
                                       bookmark=True)]
        v1.clustertemplates = [link.Link.make_link('self',
                                                   pecan.request.host_url,
                                                   'clustertemplates', ''),
                               link.Link.make_link('bookmark',
                                                   pecan.request.host_url,
                                                   'clustertemplates', '',
                                                   bookmark=True)]
        v1.clusters = [link.Link.make_link('self', pecan.request.host_url,
                                           'clusters', ''),
                       link.Link.make_link('bookmark',
                                           pecan.request.host_url,
                                           'clusters', '',
                                           bookmark=True)]
        v1.quotas = [link.Link.make_link('self', pecan.request.host_url,
                                         'quotas', ''),
                     link.Link.make_link('bookmark',
                                         pecan.request.host_url,
                                         'quotas', '',
                                         bookmark=True)]
        v1.certificates = [link.Link.make_link('self', pecan.request.host_url,
                                               'certificates', ''),
                           link.Link.make_link('bookmark',
                                               pecan.request.host_url,
                                               'certificates', '',
                                               bookmark=True)]
        v1.mservices = [link.Link.make_link('self', pecan.request.host_url,
                                            'mservices', ''),
                        link.Link.make_link('bookmark',
                                            pecan.request.host_url,
                                            'mservices', '',
                                            bookmark=True)]
        v1.stats = [link.Link.make_link('self', pecan.request.host_url,
                                        'stats', ''),
                    link.Link.make_link('bookmark',
                                        pecan.request.host_url,
                                        'stats', '',
                                        bookmark=True)]
        v1.federations = [link.Link.make_link('self', pecan.request.host_url,
                                              'federations', ''),
                          link.Link.make_link('bookmark',
                                              pecan.request.host_url,
                                              'federations', '',
                                              bookmark=True)]

        return v1


class Controller(controllers_base.Controller):
    """Version 1 API controller root."""

    bays = bay.BaysController()
    baymodels = baymodel.BayModelsController()
    clusters = cluster.ClustersController()
    clustertemplates = cluster_template.ClusterTemplatesController()
    quotas = quota.QuotaController()
    certificates = certificate.CertificateController()
    mservices = magnum_services.MagnumServiceController()
    stats = stats.StatsController()
    federations = federation.FederationsController()

    @expose.expose(V1)
    def get(self):
        # NOTE: The reason why convert() it's being called for every
        #       request is because we need to get the host url from
        #       the request object to make the links.
        return V1.convert()

    def _check_version(self, version, headers=None):
        if headers is None:
            headers = {}
        # ensure that major version in the URL matches the header
        if version.major != BASE_VERSION:
            raise http_error.HTTPNotAcceptableAPIVersion(_(
                "Mutually exclusive versions requested. Version %(ver)s "
                "requested but not supported by this service."
                "The supported version range is: "
                "[%(min)s, %(max)s].") % {'ver': version,
                                          'min': MIN_VER_STR,
                                          'max': MAX_VER_STR},
                headers=headers,
                max_version=str(MAX_VER),
                min_version=str(MIN_VER))
        # ensure the minor version is within the supported range
        if version < MIN_VER or version > MAX_VER:
            raise http_error.HTTPNotAcceptableAPIVersion(_(
                "Version %(ver)s was requested but the minor version is not "
                "supported by this service. The supported version range is: "
                "[%(min)s, %(max)s].") % {'ver': version, 'min': MIN_VER_STR,
                                          'max': MAX_VER_STR},
                headers=headers,
                max_version=str(MAX_VER),
                min_version=str(MIN_VER))

    @pecan.expose()
    def _route(self, args):
        version = ver.Version(
            pecan.request.headers, MIN_VER_STR, MAX_VER_STR)

        # Always set the basic version headers
        pecan.response.headers[ver.Version.min_string] = MIN_VER_STR
        pecan.response.headers[ver.Version.max_string] = MAX_VER_STR
        pecan.response.headers[ver.Version.string] = " ".join(
            [ver.Version.service_string, str(version)])
        pecan.response.headers["vary"] = ver.Version.string

        # assert that requested version is supported
        self._check_version(version, pecan.response.headers)
        pecan.request.version = version
        if pecan.request.body:
            msg = ("Processing request: url: %(url)s, %(method)s, "
                   "body: %(body)s" %
                   {'url': pecan.request.url,
                    'method': pecan.request.method,
                    'body': pecan.request.body})
            LOG.debug(msg)

        return super(Controller, self)._route(args)


__all__ = (Controller)
