# Copyright (C) 2019-2021 HERE Global B.V. and its affiliate(s).
# All rights reserved.
#
# This software and other materials contain proprietary information
# controlled by HERE and are protected by applicable copyright legislation.
# Any use and utilization of this software and other materials and
# disclosure to any third parties is conditional upon having a separate
# agreement with HERE for the access, use, utilization or disclosure of this
# software. In the absence of such agreement, the use of the software is not
# allowed.

"""HERE Platform Python SDK, Content access module
"""

from typing import Optional

from here.platform import Platform
from here.platform.adapter import Adapter, ContentAdapter


class Content:
    """
    Represent the source used by content bindings to access the data.
    """

    def __init__(
        self,
        platform: Platform,
        catalog_hrn: str,
        version: Optional[int] = None,
    ):
        """
        Initialize the content source.

        Platform is provided for the bindings to access the platform.
        Catalog HRN and version, when applicable, to select the content source.

        :param platform: access to the HERE platform
        :param catalog_hrn: which instance of the content to read
        :param version: which version of the content to read, latest if not specified
        :raises Exception: If catalog is empty.
        """

        # The catalog HRN, as passed
        self.catalog_hrn = catalog_hrn

        # This is the catalog used to access the data, adapter is never applied to it
        # This catalog is for internal use only of the content and content binding
        self._catalog = platform.get_catalog(catalog_hrn, adapter=platform.default_adapter)

        # Platform instance, for internal use of content and content binding
        self._platform = platform

        # The version must be set or detected once and in one place, otherwise
        # we risk to operate on two different versions if the catalog is modified
        # between multiple `latest_version` calls.
        self.version: int = version or self._catalog.latest_version()
        if not self.version:
            raise Exception(f"Catalog {catalog_hrn} is empty.")
        # TODO: check that a version exists if specified from outside
        # TODO: generalize also for catalogs without versioned layers


class ContentBinding:
    """
    Base class for all the bindings.
    """

    def __init__(self, content: Content, adapter: Optional[Adapter] = None):
        """
        Initialize the content binding.

        :param content: the content to bind to
        :param adapter: adapter to expose the content in a specific format. If not specified,
            the adapter defined in the ``Platform`` instance used for ``Content``
            is used by default in all the functions of the content binding.
        """
        self.content: Content = content

        # The following two are for implementations of this interface
        self._catalog = content._catalog
        self._version: int = content.version
        self._adapter = adapter
        self._default_adapter = content._platform.default_adapter

    def _content_adapter(self, adapter: Optional[Adapter]) -> Optional[ContentAdapter]:
        """Select and :return: the content adapter to use for each case."""
        return (adapter or self._adapter or self.content._platform.adapter).content_adapter
