"""
Base classes related to items, which represent UML classes deriving
from NamedElement.
"""

from gaphor import UML
from gaphor.UML.interfaces import IAttributeChangeEvent
from gaphor.diagram.elementitem import ElementItem
from gaphor.diagram.style import get_min_size, ALIGN_CENTER, ALIGN_TOP


class NamedItem(ElementItem):

    __style__ = {
        "min-size": (100, 50),
        "from-font": "sans 8",
        "name-font": "sans 10",
        "name-align": (ALIGN_CENTER, ALIGN_TOP),
        "name-padding": (5, 10, 5, 10),
        "name-outside": False,
        "name-align-str": None,
        "name-rotated": False,
    }

    def __init__(self, id=None):
        """
        Create named item.
        """
        ElementItem.__init__(self, id)

        # create (from ...) text to distinguish diagram items from
        # different namespace
        self._from = self.add_text(
            "from",
            pattern="(from %s)",
            style={"text-align-group": "stereotype", "font": self.style.from_font},
            visible=self.is_namespace_info_visible,
        )

        self._name = self.add_text(
            "name",
            style={
                "font": self.style.name_font,
                "text-align": self.style.name_align,
                "text-padding": self.style.name_padding,
                "text-outside": self.style.name_outside,
                "text-rotated": self.style.name_rotated,
                "text-align-str": self.style.name_align_str,
                "text-align-group": "stereotype",
            },
            editable=True,
        )

        # size of stereotype, namespace and name text
        self._header_size = 0, 0
        self.watch("subject<NamedElement>.name", self.on_named_element_name).watch(
            "subject<Namespace>.namespace", self.on_named_element_namespace
        )

    def postload(self):
        self.on_named_element_name(None)
        self.on_named_element_namespace(None)
        super(NamedItem, self).postload()

    def is_namespace_info_visible(self):
        """
        Display name space info when it is different, then diagram's or
        parent's namespace.
        """
        subject = self.subject
        canvas = self.canvas

        if not subject or not canvas:
            return False

        if not self._name.is_visible():
            return False

        namespace = subject.namespace
        parent = canvas.get_parent(self)

        # if there is a parent (i.e. interaction)
        if parent and parent.subject and parent.subject.namespace is not namespace:
            return False

        return self._from.text and namespace is not canvas.diagram.namespace

    def on_named_element_name(self, event):
        """
        Callback to be invoked, when named element name is changed.
        """
        if self.subject:
            self._name.text = self.subject.name
            self.request_update()

    def on_named_element_namespace(self, event):
        """
        Add a line '(from ...)' to the class item if subject's namespace
        is not the same as the namespace of this diagram.
        """
        subject = self.subject
        if subject and subject.namespace:
            self._from.text = subject.namespace.name
        else:
            self._from.text = ""
        self.request_update()

    def pre_update(self, context):
        """
        Calculate minimal size and header size.
        """
        super(NamedItem, self).pre_update(context)

        style = self._name.style

        # we can determine minimal size and header size only
        # when name is aligned inside an item
        if not style.text_outside:
            # at this stage stereotype text group should be already updated
            assert "stereotype" in self._text_groups_sizes

            nw, nh = self._text_groups_sizes["stereotype"]
            self._header_size = get_min_size(nw, nh, self.style.name_padding)

            self.min_width = max(self.style.min_size[0], self._header_size[0])
            self.min_height = max(self.style.min_size[1], self._header_size[1])


# vim:sw=4:et:ai
