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

"""
Bindings for the HMC Sign Text.
"""
from typing import List, Mapping

from google.protobuf.message import Message
from here.content.base import ContentPartition
from here.content.content import hmc_schema_version
from here.content.hmc2.base_attributes import Attribute, BaseAttributesBinding, _SegmentAnchor
from here.content.utils.proto import decode_message


class SignText(BaseAttributesBinding):
    """
    Bindings for the HMC Sign Text.
    """

    @classmethod
    def schema_hrn(cls) -> List[str]:
        """
        :return: the HRN of schema this binding can parse and index
        """
        return [f"hrn:here:schema:::com.here.schema.rib:sign-attributes_v2:{hmc_schema_version}"]

    @classmethod
    def object_types(cls) -> Mapping[str, type]:
        """
        :return: the types of attributes supported by this binding
        """
        return {"sign_attribute": Attribute}

    @classmethod
    def parse_and_index(cls, partition_id: str, msg: Message) -> ContentPartition:
        """
        Parse and index decoded message.

        :param partition_id: identifier of the partition
        :param msg: decoded content from the layer, in the form of a Protobuf message
        :return: the content of a partition parsed and indexed in its own data structure
        """
        assert hasattr(msg, "segment_anchor")

        def parse_generic_attributes(segment_anchors: List[_SegmentAnchor], msg):
            for attribute_msg in msg:
                a_value = decode_message(
                    attribute_msg, ignore=["originating_segment_anchor_index"]
                )
                sa = segment_anchors[attribute_msg.originating_segment_anchor_index]

                for destination in a_value["destination"]:
                    destination_segment_anchor_index = destination[
                        "destination_segment_anchor_index"
                    ]
                    destination_segments = segment_anchors[
                        destination_segment_anchor_index
                    ].segments
                    destination["segments"] = destination_segments
                # in case the anchor is malformed and doesn't contain any reference
                if not sa.segments:
                    continue
                yield Attribute(
                    segments=sa.segments,
                    forward=sa.orientation in (1, 2),
                    backward=sa.orientation in (1, 3),
                    attribute=a_value,
                )

        # parse segment anchors
        segment_anchors = [
            cls._parse_segment_anchor(sa) for sa in msg.segment_anchor  # type: ignore
        ]

        segment_attributes = {
            attribute_type: list(
                parse_generic_attributes(segment_anchors, getattr(msg, attribute_type))
            )
            for attribute_type in cls.object_types()
            # the following is to avoid parsing attributes that are empty
            if hasattr(msg, attribute_type) and getattr(msg, attribute_type)
        }

        return ContentPartition(cls, **segment_attributes)
