# Copyright (C) 2020-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.

"""
A class to hold street names
"""
from typing import Optional

from here.content.hmc.baseattributes import BaseLayer
from here.platform.adapter import Adapter


class StreetNames(BaseLayer):
    """
    A class to hold street names
    """

    def get_attribute(self, pid, attribute_name, adapter: Optional[Adapter] = None):
        """
        Get the attribute for given partitionId and attribute name
        Intended attributes: street_section, administrative_context

        :param pid: a partition ID
        :param attribute_name: attribute collection name in the partition
        :param adapter: the ``Adapter`` to transform data between different representations,
            ``None`` to use the adapter defined in the constructor or, if unset, in ``content``.
        :return: attribute dict or an adapter-specific type
        """

        # first fill the attribute
        self.fill_attribute(pid, attribute_name)

        content_adapter = self._content_adapter(adapter)

        if attribute_name not in self.attributes or pid not in self.attributes[attribute_name]:
            return None

        if content_adapter is None:
            return self.attributes[attribute_name][pid]
        else:
            columns, data = self.get_tabular_data(pid, attribute_name)
            return content_adapter.from_tabular(columns, data)

    def fill_attribute(self, pid, attribute_name="street"):
        """
        Fill the attribute for given attribute name
        Intended attributes: street_section, administrative_context

        :param pid: a partition ID
        :param attribute_name: attribute name
        """

        # initialize self.attributes[attribute_value_name] container
        self.attributes.setdefault(attribute_name, {})

        # do nothing if pid is already filled
        if pid in self.attributes[attribute_name]:
            return

        # get partition object
        partition = self.get_partition(pid)

        if "street" in attribute_name:
            # associate street_section with street_name
            attributes = self.resolve_street(partition)
        else:  # administrative_context
            attributes = self.resolve_administrative_context(partition)

        # update attributes container
        self.attributes[attribute_name].update(attributes)

    @staticmethod
    def resolve_street(partition):
        """
        Associate street_section with street
        :param partition: a partition object
        :return: a dict of street_section -> street
        """

        attributes = {}

        # street section partition ID
        scpid = partition.partition_name

        for attr in partition.street_section:

            # street section ID
            scid = attr.identifier

            # get street index to look up
            idx = attr.street_index.value

            # get a street for this attribute
            street = partition.street[idx]

            # initialize dict with this pid, sid
            attributes.setdefault(scpid, {})
            attributes[scpid].setdefault(scid, {})
            attributes[scpid][scid] = street

        return attributes

    @staticmethod
    def resolve_administrative_context(partition):
        """
        Associate street_section with street
        :param partition: a partition object
        :return: a dict of street_section -> administrative_context
        """

        attributes = {}

        # street section partition ID
        scpid = partition.partition_name

        for attr in partition.street_section:

            # street section ID
            scid = attr.identifier

            # get street index to look up
            idx = attr.administrative_context_index

            # get a administrative_context for this attribute
            ac = partition.administrative_context[idx]

            # initialize dict with this pid, sid
            attributes.setdefault(scpid, {})
            attributes[scpid].setdefault(scid, {})
            attributes[scpid][scid] = ac

        return attributes

    def get_tabular_data(self, pid, attribute_name):
        """
        Convert the given attribute to tabular data
        :param pid: partition ID
        :param attribute_name: attribute name to look for
        :return: columns, data
        """
        columns = ("partitionId", "street_section_id", "attribute")
        data = []
        if attribute_name in self.attributes and pid in self.attributes[attribute_name]:
            for scid, value in self.attributes[attribute_name][pid].items():
                data.append((pid, scid, value))
        return columns, data
